当前位置: 首页 > news >正文

网站功能有哪些网站目录不能访问

网站功能有哪些,网站目录不能访问,大数据网站视频,有没有做网站的多少钱《Java实战》学习整理 文章目录 一、Lambda1.1 基础概念1.1.1 [Lambda表达式](https://baike.baidu.com/item/Lambda表达式/4585794?fromModulelemma_inlink)定义 1.2 引入Lambda1.3 Lambda1.3.1 函数式接口1.3.2 Lambda表达式#xff1a;(参数) - 表达式1.3.3 在哪里使…《Java实战》学习整理 文章目录 一、Lambda1.1 基础概念1.1.1 [Lambda表达式](https://baike.baidu.com/item/Lambda表达式/4585794?fromModulelemma_inlink)定义 1.2 引入Lambda1.3 Lambda1.3.1 函数式接口1.3.2 Lambda表达式(参数) - 表达式1.3.3 在哪里使用Lambda表达式1.3.4 函数描述符1.3.5 类型推断1.3. 6 使用局部变量1.3.7 方法引用1.3.8 复合Lambda表达式 二、Stream流2.1 基础概念2.2 中间操作 和 终端操作2.2.1 中间操作2.2.2 终端操作2.2.3 设计模型类似构建器模式2.2.4 peek中间操作 2.3 使用流-筛选2.3.1 filter 补充 Predicate2.3.2 distinct2.3.3 max 过滤留下属性值大的类 2.4 使用流-切片2.4.1 takeWhile dropWhile 2.5 使用流-映射2.5.1 map2.5.2 flatMap 2.6 使用流-查找和匹配2.6.1 allMatch全部匹配2.6.2 anyMatch任意匹配2.6.3 findAny查找任意2.6.4 findFirst 查找第一个 2.7 使用流-归约reduce2.7.1 求和2.7.2 max、min、count 2.7.3 concat合并多个流2.8 使用流-归约 Collect2.8.1 简介2.8.2 归约和汇总-**LongSummaryStatistics**2.8.3 连接字符串-join2.8.4 归约 - reducing2.8.5 分组- groupingBy2.8.6 分区2.8.7 list转为map: toMap(类似常用的toList) 三、Java8新增特性3.1 Map相关3.1.0 compute、computeIfAbsent、putIfAbsent、put3.1.1 排序3.1.2 计数3.1.3 两个map合并-merge3.1.4 其它 3.2 Optional3.2.1 Optional简介3.2.2 Optional常用方法3.2.3 优雅的取值3.2.4 注意事项 3.3 时间类3.3.1 Temporal实现类3.3.2 ChronoUnit3.3.3 Period 和 Duration 3.4 默认方法3.4.1 简介3.4.1 菱形问题 四、CompletableFuture4.1 简介4.1.1 产生背景4.1.2 概念 4.2 正确使用姿势4.3 get方法和join方法区别4.3.1 相同点4.3.2 区别 4.4 实战4.4.1 单个并发查询4.4.2 两个参数都是集合一起作为异步查询的入参并发查询4.4.3 ListParamDTO paramlist MapIntegerListService map一起并发查询map中key 1value ListService serviceList1serviceList1为sever1、sever2、key 2value ListService serviceList2serviceList为sever34.4.3 A和B任务二者之间并行查询 同时 A和B本身也要200批次、200批次的并行查询4.4.4 将ListCompletableFutureX转为CompletableFutureListT cf14.4.5 将ListCompletableFutureMapLong, Long 变为 CompletableFuture**Map**Long, Long** cf14.4.6 并发处理map的k-v而非map.forEach((k,v) 串行处理4.4.7 limit、offset并发查询 4.4.8 协同、转运、pc打标并发mark结果一起join4.4.9 其他 4.5 Java9 CompletableFuture新特性4.5.1 新增了orTimeOut方法4.5.2 执行超时的时候赋默认结果completeOnTimeOut 五、工具类非Java85.1 集合运算5.2 集合深copy5.3 线程安全的list5.4 list Array 一、Lambda 1.1 基础概念 函数式编程 和 Lambda都是为Stream服务的 1.1.1 Lambda表达式定义 是一个匿名函数即没有函数名的函数,函数/方法可以作为参数传递至另一个方法中 (int x) - x1 上述Lambda表达式定义了这样一个匿名函数调用时给定参数x就返回x1值的函数没有共享的可变数据以及将方法\函数\行为传递给其他方法的能力这两点是函数式编程的基石。也构成了Stream的基础 1.2 引入Lambda 背景 苹果集合苹果有颜色、重量、是否售卖等三个属性。 现有集合筛选出颜色是青苹果 Data Accessors(chain true) public class Apple {private ColorEnum color;private Integer weight;private Boolean sell;}1、第一次尝试直接遍历集合 Testpublic void t(){Apple apple1 new Apple().setColor(ColorEnum.GREEN).setWeight(100).setSell(Boolean.TRUE);Apple apple2 new Apple().setColor(ColorEnum.GREEN).setWeight(150).setSell(Boolean.TRUE);Apple apple3 new Apple().setColor(ColorEnum.RED).setWeight(150).setSell(Boolean.TRUE);Apple apple4 new Apple().setColor(ColorEnum.RED).setWeight(150).setSell(Boolean.FALSE);ListApple appleList Lists.newArrayList(apple1, apple2, apple3, apple4);//下文都是使用这个苹果集合appleListListApple filteredAppleList filterGreen(appleList);}private ListApple filterfilterGreen(ListApple appleList) {ListApple result Lists.newArrayList();for (Apple apple : appleList) {if (Objects.equals(apple.getColor(), ColorEnum.GREEN)) {result.add(apple);}}return result;}缺点 如果再要求筛选出红苹果则还需要再写一个过滤方法 private ListApple filterfilterRed(ListApple appleList) {ListApple result Lists.newArrayList();for (Apple apple : appleList) {if (Objects.equals(apple.getColor(), ColorEnum.RED)) {result.add(apple);}}return result;}2、第二次尝试把颜色作为方法入参想要过滤啥颜色的就传递啥颜色 Testpublic void t(){// 想要过滤啥颜色的就传递啥颜色即可ListApple tempList filterByColor(appleList, ColorEnum.GREEN);ListApple finalResult filterByColor(tempList, ColorEnum.RED);}private ListApple filterByColor(ListApple appleList, ColorEnum colorEnum) {ListApple result Lists.newArrayList();for (Apple apple : appleList) {if (Objects.equals(apple.getColor(), colorEnum)) {result.add(apple);}}return result;}缺点 如果我想按照重量进行过滤顾虑出大于指定重量的苹果或过滤出是否售卖的苹果则还需要继续添加方法 3、第三次尝试把苹果的所有属性都作为方法入参想要过滤啥传递啥即可 Testpublic void t(){ListApple tempList filterByColor(appleList, ColorEnum.GREEN, 120, Boolean.TRUE);ListApple finalResult filterByColor(tempList, ColorEnum.RED, 100 ,Boolean.FALSE);}private ListApple filterByColor(ListApple appleList, ColorEnum colorEnum, Integer weight, Boolean isSell) {ListApple result Lists.newArrayList();for (Apple apple : appleList) {if (Objects.equals(apple.getColor(), colorEnum) apple.getWeight() weight Objects.equals(apple.getSell(), isSell)) {result.add(apple);}}return result;}缺点 类属性很多时方法入参变得复杂同时有的不需要根据类的属性进行过滤则需要在方法中传递null值 4、第四次尝试使用策略模式 定义接口和实现类其中接口方法定义为是否满足某种条件。实现类则分别为是否为青色苹果、是否为红色苹果、是否售卖等 // 1.定义接口和判断方法 public interface ApplePredicate {/*** 判断是否满足某个行为* param apple 苹果* return 是否满足某个条件*/boolean judge(Apple apple);}// 2.1定义青苹果类 public class GreenApplePredicate implements ApplePredicate{Overridepublic boolean judge(Apple apple) {return Objects.equals(apple.getColor(), ColorEnum.GREEN);} }// 2.2定义红苹果类 public class RedApplePredicate implements ApplePredicate{Overridepublic boolean judge(Apple apple) {return Objects.equals(apple.getColor(), ColorEnum.RED);} }// 2.3定义重量类 public class WeightApplePredicate implements ApplePredicate{Overridepublic boolean judge(Apple apple) {return apple.getWeight() 150;} }Testpublic void t(){ListApple tempGreenList filter(appleList, new GreenApplePredicate());ListApple tempRedList filter(tempGreenList, new RedApplePredicate());ListApple result filter(tempRedList, new WeightApplePredicate());}// 想要过滤什么属性就传递对应的实现类对象即可private ListApple filter(ListApple appleList, ApplePredicate applePredicate) {ListApple result Lists.newArrayList();for (Apple apple : appleList) {if (applePredicate.judge(apple)) {result.add(apple);}}return result;}优点策略模式满足开闭原则 filter方法的具体内容已经取决于传递的实现类对象了。只不过最重要的方法judge是被对象包裹了。可以通过lambda讲judge方法拿到外层充当方法参数 缺点需要写太多实现类麻烦 5、第五次尝试使用匿名内部类 Testpublic void t(){ListApple tempGreenList filter(appleList, new ApplePredicate() {Overridepublic boolean judge(Apple apple) {return Objects.equals(apple.getColor(), ColorEnum.GREEN);}});ListApple tempRedList filter(tempGreenList, new ApplePredicate() {Overridepublic boolean judge(Apple apple) {return Objects.equals(apple.getColor(), ColorEnum.RED);}});ListApple result filter(tempRedList, new ApplePredicate() {Overridepublic boolean judge(Apple apple) {return apple.getWeight() 150;}});}private ListApple filter(ListApple appleList, ApplePredicate applePredicate) {ListApple result Lists.newArrayList();for (Apple apple : appleList) {if (applePredicate.judge(apple)) {result.add(apple);}}return result;}优点解决了类爆炸问题缺点还是需要写很多代码笨重 6、第六次尝试和匿名内部类一样匿名函数Lambda表达式也可以作为参数传递至方法 将filter方法传递参数由对象引用变成函数引用。即将judge方法拿到外层 Testpublic void t(){ListApple greenAppleList filter(appleList, apple - Objects.equals(apple.getColor(), ColorEnum.GREEN));ListApple redAppleList filter(greenAppleList, apple - Objects.equals(apple.getColor(), ColorEnum.RED));ListApple weightList filter(redAppleList, apple - apple.getWeight() 150);ListApple result filter(weightList, apple - apple.getSell());}private ListApple filter(ListApple appleList, ApplePredicate applePredicate) {ListApple result Lists.newArrayList();for (Apple apple : appleList) {if (applePredicate.judge(apple)) {result.add(apple);}}return result;}优点函数式编程将行为/方法/函数 作为参数传递至方法。满足开闭原则代码简洁 7、第七次尝试将List抽象化同时使用语法糖 public interface PredicateT {/*** 判断是否满足某个行为* param e 苹果* return 是否满足某个条件*/boolean judge(T e);}private T ListT filter(ListT list, PredicateT predicate) {ListT result Lists.newArrayList();for (T e : list) {if (predicate.judge(e)) {result.add(e);}}return result;}ListApple sellAppleList filter(appleList, Apple::getSell);// 语法糖取代 apple - xxx形式ListInteger numbers Lists.newArrayList(1, 2, 3);ListInteger result filter(numbers, e - e 2);优点其他元素类类型的集合也可以进行过滤。类型Stream流中的filter方法了 1.3 Lambda 1.3.1 函数式接口 仅定义了一个抽象方法可以有许多默认方法常见的函数式接口Runnable、Callable、CompatorLambda表达式就是函数式接口中抽象方法的具体实现的实例 1.3.2 Lambda表达式(参数) - 表达式 参数可以为空返回值也可以为空表达式的结果就是返回值只是省略了return。表达式多行必须{} return一起使用void则直接return; // 参数和返回值都为void filter(numbers, () - {System.out.println();return;});表达式为单行则可以省略return 和 {}filter(numbers, () - );filter(numbers, () - System.out.println());1.3.3 在哪里使用Lambda表达式 当方法的入参为函数式接口时可以使用Lambda表达式作为参数 使用案例Lambda表达式函数式接口函数描述符函数式接口对应的抽象方法备注布尔表达式(List list - CollectionUtils.isEmpty(list))PredicateT - booleanboolean test(T t)消费一个对象,无返回Apple a- System.out.println(a)ConsumerT - voidvoid accept(T t)消费一个对象,有返回Integer i- i 1FunctionT, RT - RR apply(T t)创建对象- new user(“mjp”)Supplier() - TT get()特例T - TUnaryOperator extends FunctionT, T两个入参BiPredicateT, UBiConsumerT, UBiFunctionT, U, R(T, U) - boolean(T, U) - void(T, U) - R特例TT - TBinaryOperator extends FunctionT, TT 1.3.4 函数描述符 函数式接口中抽象方法的签名就是函数描述符 Lambda表达式的签名要和函数式接口中抽象方法的签名一致。req、resp类型相同否则类型检查不通过 1.3.5 类型推断 Apple a - a.getWeight() a - a.getWeight()这个明显就是T - R属于FunctionT,R函数式接口。 编译器就可以根据抽象方法的函数描述符知道Lambda表达式的签名即输入为T就可以在Lambda中省略标注参数类型 1.3. 6 使用局部变量 1、java8中的effective final 当你使用jdk7的时候这样写会报错原因是a不是final的 int a 10; Runnable runnable () - System.out.println(a);当你使用jdk8的时候编译器自动帮你优化为所以上述写法不会报错 final int a 10; Runnable runnable () - System.out.println(a);为什么在匿名内部类| Lambda表达式中使用局部变量局部变量必须是final修饰 或 是有效的final(要么是后续不再对此变量进行赋值) 这里我们拿lambda表达式举例 他们俩类似区别是 1匿名内部类编译之后会产生一个单独的.class字节码文件 Lambda表达式编译之后不会产生一个单独的.class字节码文件。对应的字节码会在运行的时候动态生成。 2 匿名内部类可以是接口也可以是抽象类还可以是具体类。 Lambda表达式只能是接口 lambda表达式中使用的局部变量应该是final或者有效的final也就是说lambda 表达式只能引用标记了 final 的外层局部变量为什么lambda使用的局部变量要是final修饰的 1因为想让开发者明确外部变量的值在lambda表达式中是无法被改变的这一事实。所以开发者自然不会尝试在lambda中对局部变量进行改变 2线程安全 局部变量x存在栈中 执行的时候在线程t1中。Lambda表达式在线程t2中lambda并行流有自己的线程池。若t2直接访问t1的局部变量x则可能存在t1执行完x直接被释放了t2访问不到的情况 所以lambda线程访问的都是x的副本 如果局部变量x仅仅被赋值一次则副本和基本变量没什么区别 但是若x后续再次被赋值则可能导致t2访问的副本值 和 最新赋值的值不一样了。存在线程安全问题 实例变量成员变量则不存在这个问题因为其存在于堆中首先不会随着t1线程结束而结束生命周期和对象实例相关其次堆对于不同线程也是共享的 2、实战 SetLong buyByDimeSkuList new HashSet();if () {//灰度查询buyByDimeSkuList xxx; } else{buyByDimeSkuList xxx;}// 4.过滤掉1档期预加工品、赠品 2黑名单品 3一毛购品sellOutProcessPlanDOList sellOutProcessPlanDOList.stream().filter(sellOutPlan - !buyByDimeSkuList.contains(sellOutPlan.getSkuId()))//filter这里会报错原因buyByDimeSkuList不是final修饰的而且编译机也无法effective final帮你加final//因为一旦帮你加上final了buyByDimeSkuList就你能再指向别的对象地址了// 所以这里只能再定义一个set变量将buyByDimeSkuList赋值给他编译器会帮忙声明为final的这样在lambda中就可以使用这个新的变量了1.3.7 方法引用 Testpublic void t(){// 第一种static方法的引用ListInteger l1 Lists.newArrayList(a, b).stream().map(Integer::parseInt).collect(Collectors.toList());// 第二种实例方法的引用ListInteger l2 Lists.newArrayList(a, b).stream().map(String::length).collect(Collectors.toList());// 第三种对象的方法引用this::xX// 第四种构造函数引用ClassName::new}::方法引用即把这个方法parseInt()作为值传递给map方法。 map方法的参数是FunctionT,R对应的lambda为(String s) - Integer即s - Integer 1.3.8 复合Lambda表达式 1、排序 正常升降 //根据Dict对象的sort字段降序排序 dictList.sort(Comparator.comparing(Dict::getSort).reversed()); //根据Dict对象的sort字段升序排序 dictList.sort(Comparator.comparing(Dict::getSort));先按照字段A降序当字段A值一样时再按照字段B降序【需要保证同一份数据每次排序后数据顺序要一致】 ListSKUCategoryRuleDO result skuCategoryRuleDOS.stream().sorted(Comparator.comparing(SKUCategoryRuleDO::getSkuCategoryId).reversed().thenComparing(SKUCategoryRuleDO::getSkuTemperatureZone,Comparator.reverseOrder())).collect(Collectors.toList());//降-降ListSKUCategoryRuleDO result skuCategoryRuleDOS.stream().sorted(Comparator.comparing(SKUCategoryRuleDO::getSkuCategoryId).reversed().thenComparing(SKUCategoryRuleDO::getSkuTemperatureZone,Comparator.reverseOrder())).collect(Collectors.toList()); //当降序字段一样时需要指定最终按照某个字段排序否则每次查询出来展示的结果顺序不一样可以用skuId或者主键id等 skuCategoryRuleDOS skuCategoryRuleDOS.stream().sorted(Comparator.comparing(SKUCategoryRuleDO::getSkuCategoryId).reversed().thenComparing(SKUCategoryRuleDO::getId, Comparator.reverseOrder())).collect(Collectors.toList()); 参考https://codeantenna.com/a/HD5Rqszcri2、谓词复合 Testpublic void t(){ListString names Arrays.asList(Java, Scala, C, Haskell, Lisp,Hello,VersionJDK);PredicateString filterLengthLowThan5 str - {if (str.length() 5) {return true;}return false;};PredicateString filterStartWithJ str - {if (str.startsWith(J)) {return true;}return false;};PredicateString filterEndWithK str - {if (str.endsWith(K)) {return true;}return false;};// 过滤出长度5并且以J开头或者以D结尾的单词ListString result names.stream().filter(filterLengthLowThan5.and(filterStartWithJ).or(filterEndWithK)).collect(Collectors.toList());System.out.println(result);//[Java, VersionJDK]}//补充negate()和and以及or不同表示非即返回一个Predicate的非3、函数复合 ListInteger list Lists.newArrayList(1, 2, 3);FunctionInteger, Integer f1 x - x 1;FunctionInteger, Integer f2 x - x * 2;FunctionInteger, Integer filter f1.andThen(f2);ListInteger result list.stream().map(filter).collect(Collectors.toList());System.out.println(result);// 等价map.mapListInteger result2 list.stream().map(f1).map(f2).collect(Collectors.toList());System.out.println(result2);二、Stream流 2.1 基础概念 绝大数Java程序都仅仅使用了CPU中的一核其它核都闲着。Stream支持并行处理多个数据。Stream库来选择底层最佳执行机制(类似数据库的查询) 没有共享的可变数据以及将方法\函数\行为传递给其他方法的能力这两点是函数式编程的基石。也构成了Stream的基础 因为Stream中大多数方法(filter、map、sort)入参都是函数式接口 for-each循环一个个迭代元素属于外部迭代【Collection更多是存储和访问元素】。stream属于内部迭代【元素计算】 流只能被消费一次 ListInteger list Lists.newArrayList(1, 2, 3);StreamInteger stream list.stream();stream.forEach(System.out::println);stream.forEach(System.out::println);//java.lang.IllegalStateException: stream has already been operated upon or closed1、创建流三种方式 最常见的list.stream 数组流Arrays.stream 多个集合创建流Stream.of(list1, list2) 2、文件流 try (StreamString lines Files.lines(Paths.get(/Users/majinpeng/Downloads/codebetter/src/main/resources/data.txt), Charset.defaultCharset())){ListString list lines.map(line - line.split( )).flatMap(Arrays::stream).collect(Collectors.toList());long count list.stream().distinct().count();System.out.println(count); } catch (Exception e){} // File.lines方法返回执行文件中的各行构成的字符串流。 // 流 中的每个元素都是文件中的一行 // 通过扁平化流可以算出文件中有多少个不同的单词2.2 中间操作 和 终端操作 2.2.1 中间操作 1、中间操作filter、map、list、sort、distinct等方法返回值都是Stream可以连城一条流水线 2、执行顺序 limit会触发短路即并非全部元素都取出来后留下三个而是取到三个满足的直接终止filter().map()不是等filter全部处理完成再到map而是一个元素经过filter再经过map下一个元素通用先经过filter再经过map。filter和map合并到同一次遍历中了 2.2.2 终端操作 终端操作触发流的执行并关闭流。返回值不是流 2.2.3 设计模型类似构建器模式 中间操作就是各种的set终端操作就是build()方法 2.2.4 peek中间操作 在流的中间在不改变流中T的数据类型情况下对T进行操作赋值 给类属性赋值map的时候map中的val是Obj也需要中间赋值操作这个时候就可以用peek对Obj的属性进行赋值 list.setMap(tempList.stream().peek(dto - dto.setRdcPoiId(rdcPoiId)).collect(Collectors.toMap(DTO::getSkuId, Function.identity(), (s1, s2) - s1))); 参考文档https://segmentfault.com/a/11900000211125852.3 使用流-筛选 2.3.1 filter ListInteger list Lists.newArrayList(1, 2, 3, 4, 5);PredicateInteger filter1 i - i 1;PredicateInteger filter2 i - i 2;PredicateInteger filter3 i - i 3;ListInteger result list.stream().filter(filter1.and(filter2).or(filter3).negate()).collect(Collectors.toList());//去除key和val为null的entryMapLong, Person collect map.entrySet().stream().filter(entry -entry.getKey() !null entry.getValue()! null).collect(Collectors.toMap(entry - entry.getKey(),entry - entry.getValue()));补充 Predicate ListString names Arrays.asList(Java, Scala, C, Haskell, Lisp,Hello,opt);PredicateString filter1 str - {if (str.length() 4) {return false;}return true;};PredicateString filter2 str - {if (str.startsWith(J) || str.endsWith(p)) {return false;}return true;};ListString filteredNames names.stream().filter(filter1.and(filter2)).collect(Collectors.toList());//C、opt1、参考文档https://blog.csdn.net/qazzwx/article/details/107864622 2、实战1 - 销售进度 private PredicateSellOutProcessPlanDO getSaleProgressFilter(Integer saleProgress) {PredicateSellOutProcessPlanDO saleProgressFilter;if (Objects.nonNull(saleProgress) saleProgress 0) {saleProgressFilter sellOutProcessPlanDO - {Long maxSellQuantity sellOutProcessPlanDO.getMaxSaleNum();BigDecimal lockQty sellOutProcessPlanDO.getSalesVolume();if (Objects.isNull(maxSellQuantity) || maxSellQuantity 0L|| lockQty null || Objects.equals(lockQty, BigDecimal.ZERO)) {return false;}return lockQty.divide(BigDecimal.valueOf(maxSellQuantity), 3, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).compareTo(BigDecimal.valueOf(saleProgress)) 0;};} else {saleProgressFilter sellOutProcessPlanDO - true;}return saleProgressFilter;}4、实战2-品类、温层 2.3.2 distinct 1、原理是通过equals方法使得元素没有重复 ListInteger skuIds Lists.newArrayList(1, 2, 3, 4, 5, 1, 2);skuIds skuIds.stream().filter(i - i 5).distinct().collect(Collectors.toList());System.out.println(skuIds);// 1,2,3,4补充 distinct最好在别的中间操作完成之后再使用 一般再查询的时候最后在底层方法request中对skuId、supplierId等字段进行去重不要相信调用方其可能传递重复值 2、自定义去重 根据类的三个属性作为唯一键过滤相同唯一键的类 SetOriginReturnSkuDO skuDOSet new TreeSet(Comparator.comparing(originReturnSkuDO -(originReturnSkuDO.getSkuId() originReturnSkuDO.getPackKey() originReturnSkuDO.getTaskCode())));skuDOSet.addAll(afterFilterByTriggerGraySkus);//过滤这个listListOriginReturnSkuDO batchInsertSkuDOS new ArrayList(skuDOSet);//得到新的list根据类的某一个属性进行过滤相同属性的类 ListMyUser myUsers Lists.newArrayList(myUser, myUser1, myUser2, myUser3, myUser4); ListMyUser res myUsers.stream().filter(distinctByKey(MyUser::getSkuId)).collect(Collectors.toList());public static T PredicateT distinctByKey(Function? super T, ? keyExtractor) {MapObject,Boolean seen new ConcurrentHashMap();return t - seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) null; }待插入db的数据 和 从db中查询出的数据进行去重只insert db不存在的数据 private ListOriginReturnSkuDO queryNotDuplicateReturnSku(ListOriginReturnSkuDO batchInsertSkuDOS, OihReturnSkuMessage request) {ListOriginReturnSkuDO removedDuplicateSkuDOs new ArrayList();//01.查询db,可退sku信息OriginReturnSkuDOExample example buildOriginReturnSkuDOExample(request.getTaskNo());ListOriginReturnSkuDO dbReturnSkuDOList originReturnSkuMapper.selectByExample(example);if (CollectionUtils.isNotEmpty(dbReturnSkuDOList)){dbReturnSkuDOList dbReturnSkuDOList.stream().filter(Objects::nonNull).collect(Collectors.toList());}else {return batchInsertSkuDOS;}//02.根据db数据过滤掉oih再次下发的相同sku数据MapString,OriginReturnSkuDO oihReturnSkuMap new HashMap();MapString,OriginReturnSkuDO dbReturnSkuMap new HashMap();batchInsertSkuDOS.forEach(originReturnSkuDO - {String uniqueKey originReturnSkuDO.getPackKey()originReturnSkuDO.getSkuId()originReturnSkuDO.getTaskCode();oihReturnSkuMap.put(uniqueKey, originReturnSkuDO);});dbReturnSkuDOList.forEach(originReturnSkuDO - {String uniqueKey originReturnSkuDO.getPackKey() originReturnSkuDO.getSkuId()originReturnSkuDO.getTaskCode();dbReturnSkuMap.put(uniqueKey,originReturnSkuDO);});IteratorMap.EntryString, OriginReturnSkuDO iterator oihReturnSkuMap.entrySet().iterator();while(iterator.hasNext()){Map.EntryString, OriginReturnSkuDO entry iterator.next();String uniqueKey entry.getKey();if (Objects.nonNull(dbReturnSkuMap.get(uniqueKey))){//说明db中有这条数据了//过滤掉该条数据iterator.remove();log.warn(从oih获取到重复sku数据,uniqueKey:[{}], GsonUtils.toJsonString(uniqueKey));}}//03.存过滤后的sku至listremovedDuplicateSkuDOs.addAll(oihReturnSkuMap.values());return removedDuplicateSkuDOs;}2.3.3 max 过滤留下属性值大的类 属性值为15:30 Testpublic void t() {User u1 new User();u1.setLotCode(18);u1.setSkuId(1L);User u2 new User();u2.setLotCode(12);u2.setSkuId(1L);User u3 new User();u3.setLotCode(11);u3.setSkuId(2L);ListUser list Lists.newArrayList(u1,u2,u3);MapLong, User map list.stream().collect(Collectors.toMap(User::getSkuId, Function.identity(), BinaryOperator.maxBy(Comparator.comparingInt(value - NumberUtils.toInt(value.getLotCode(), 0)))));ListUser users Lists.newArrayList(map.values());System.out.println(users);//[User(skuId1, lotCode18, inBirthdaynull), User(skuId2, lotCode11, inBirthdaynull)]。u2和u1在比较过程中被过滤掉了BinaryOperatorString maxLengthString BinaryOperator.maxBy(Comparator.comparingInt(String::length));String s maxLengthString.apply(wxx, mjp23);System.out.println(s);//mjp23}//如果lotCode是18:30、1400这种则需要将:转为. 按照double值比较大小MapLong, SellOutWarnAndStatusDTO skuId2latestDtoMap sellOutWarnAndStatusDtoList.stream().collect(Collectors.toMap(SellOutWarnAndStatusDTO::getSkuId, Function.identity(), BinaryOperator.maxBy(Comparator.comparingDouble(resolveLotCodeToDouble()))));return Lists.newArrayList(skuId2latestDtoMap.values());}private ToDoubleFunctionSellOutWarnAndStatusDTO resolveLotCodeToDouble() {return value - {// 14:00 - 14.00String lotCode value.getLotCode();String replaceLotCode StringUtils.replace(lotCode, :, .);return NumberUtils.toDouble(replaceLotCode, 0D);};}属性值为15 ListSellOutWarnSkuBO newestLotCodeBOList Lists.newArrayList();map.forEach((netPoiIdAndSkuIdAndWarnTypeStr, sellWarnOutBOSubList) -{OptionalSellOutWarnSkuBO warnSkuDOOptional sellWarnOutBOSubList.stream().max(Comparator.comparingInt(sellWarnOutBO - NumberUtils.toInt(sellWarnOutBO.getLotCode(), 0)));warnSkuDOOptional.ifPresent(newestLotCodeBOList::add);});2.4 使用流-切片 ListInteger skuIds Lists.newArrayList(1, 2, 3, 4, 5, 1, 2);skuIds skuIds.stream().filter(i - {System.out.println(i);return i 5;}).distinct().collect(Collectors.toList());2.4.1 takeWhile dropWhile filter需要遍历流中的所有数据对每个元素进行操作takeWhile先排序然后在遇到第一个不满足的元素时就停止处理短路 ListInteger skuIds Lists.newArrayList(1, 2, 3, 4, 5, 1, 2);skuIds skuIds.stream().takeWhile(i - {System.out.println(i);return i 5;}).distinct().collect(Collectors.toList());dropWhile在遇到第一个表达式为true的元素时则停止处理 2.5 使用流-映射 2.5.1 map Stream map(Function? super T, ? extends R mapper) 1、这个入参Function函数会作用到每个元素上使得元素从T - R 2、map本身返回Stream 2.5.2 flatMap Stream flatMap(Function? super T, ? extends Stream? extends R mapper) 这个入参Function函数会作用到每个元素上使得元素从T - Stream所有flastMap的作用是扁平化一个流。如果向拆分流元素且流元素支持再拆分(单词由单个字符组成数组和集合由元素组成等)则可以使用flatMap StreamList stream1流中的每个元素都是一个list集合则使用stream1.flatMap***(***List::stream) StreamString[] stream2流中的每个元素都是一个数组则使用stream2.flatMap( Arrays::stream) .collect(Collectors.toList())是将Stream 转换为List去除Stream .flatMap()方法入参是Function为函数式接口T - Stream方法出参是Stream 1、对集合中元素去重 ListString words Lists.newArrayList(hello, hello, world);System.out.println(words.stream().distinct().collect(Collectors.toList()));//hello, world2、对集合每个元素中的具体单词去重即结果为: h e l o w r d 无效代码1 ListString words Lists.newArrayList(hello, hello, world);ListString[] result words.stream().map(s - s.split()).distinct().collect(Collectors.toList()); 这里的map是将StreamString 转换为 StreamString[], 后者流中每个元素都是一个String数组再distinct去重的时候 对每个数组进行equals比较地址肯定都不一样, 所以无法实现无效代码2 ListString words Lists.newArrayList(hello, world); StreamString[] stream words.stream().map(s - s.split());// Arrays.stream方法入参是T[] array 出参是StreamT // map的入参是String[]出参是StreamString StreamStreamString stream1 stream.map(strings - Arrays.stream(strings));ListStreamString result stream1.distinct().collect(Collectors.toList());有效代码flatMap ListString words Lists.newArrayList(hello, world);StreamString[] stream1 words.stream().map(s - s.split());// 这个StreamT每个元素都是一个数据将数组再扁平化化使用Arrays::stream函数// 如果T是list则将集合再扁平化使用Collection::streamStreamString stream2 stream1.flatMap(strings - Arrays.stream(strings));ListString result stream2.distinct().collect(Collectors.toList());System.out.println(result);3、给出[1,2]和[3,4]返回[ (1,3) ,(1,4) ,(2,3) ,(2,4) ] // Stream1,3、Stream1,4、Stream2,3Stream2,4 // i 1时Stream1,3、Stream1,4 即 T - Stream数组则使用flatMapListint[] result list1.stream().flatMap(i1 - {Streamint[] array list2.stream().map(i2 - new int[]{i1, i2});return array;}).collect(Collectors.toList());4、给出[1,2]和[3,4]返回[ (1,3) ,(1,4) ,(2,3) ,(2,4) ]只返回总和能被3整除的数对 Listint[] result list1.stream().flatMap(i1 - {Streamint[] array list2.stream().filter(i2 - (i1 i2) % 3 0).map(i2 - new int[]{i1, i2});return array;}).collect(Collectors.toList());5、根据勾股定理求出aa bb c*c其中a、b均在(1,100) [3,4,5]、[…] Listint[] result IntStream.rangeClosed(1, 100).boxed().flatMap(a - IntStream.rangeClosed(a, 100).boxed().filter(b - Math.sqrt(a * a b * b) % 1 0).map(b - new int[]{a, b, (int) Math.sqrt(a * a b * b)})).collect(Collectors.toList());result.forEach(ints - System.out.println(Arrays.toString(ints)));// 等价// 01.创建StreamInteger流元素从1-100StreamInteger integerStream1 IntStream.rangeClosed(1, 100).boxed();// 02.遍历流元素Streamint[] stream2 integerStream1.flatMap(a - {// 03.创建StreamInteger流元素从a-100StreamInteger integerStream2 IntStream.rangeClosed(a, 100).boxed();// 04.给出a的值根据勾股定理可以确定b的值(过滤一部分b)StreamInteger tempStream integerStream2.filter(b - Math.sqrt(a * a b * b) % 1 0);// 05.给出a的值根据勾股定理可以确定c的值并构造出一组勾股值Streamint[] stream1 tempStream.map(b - new int[]{a, b, (int) Math.sqrt(a * a b * b)});return stream1;});// 06.转换为集合并打印Listint[] collect1 stream2.collect(Collectors.toList());collect1.forEach(ints - System.out.println(Arrays.toString(ints)));// 补充 也可以先直接根据 Math.sqrt(a * a b * b)算出全部c以及全部组合然后再过滤满足条件的c即arr[2] % 1 02.6 使用流-查找和匹配 终端操作 2.6.1 allMatch全部匹配 ListInteger list1 Lists.newArrayList(1, 2);boolean b list1.stream().allMatch(i - i 1);System.out.println(b);//false2.6.2 anyMatch任意匹配 ListInteger list1 Lists.newArrayList(1, 2);boolean b list1.stream().anyMatch(i - i 1);System.out.println(b);//true2.6.3 findAny查找任意 一般和其他流操作结合使用。比如查找任意一个 1的数先filter再findAny OptionalInteger optional list1.stream().filter(i - i 1).findAny();if (optional.isPresent()) {Integer i optional.get();}2.6.4 findFirst 查找第一个 一般和其他流操作结合使用。比如查找第一个 1的数先filter再findFirst如果不关心返回的元素是哪个建议使用findAny。因为其在使用并行流的时候限制较少 // 找出第一个平方后能被3整除的数 ListInteger list1 Lists.newArrayList(1, 2, 3, 4);OptionalInteger optional list1.stream().map(i - i * i).filter(i - i % 3 0).findFirst();if (optional.isPresent()) {Integer i optional.get();//9}2.7 使用流-归约reduce 把一个流中的元素组合起来 2.7.1 求和 1、reduce(初始值BinaryOperator) 其中BinaryOperator用的Lambda将两个元素结合起来产生新值 Integer sum list.stream().reduce(0, (a, b) - a b); 等价语法糖 Integer sum list.stream().reduce(0, Integer::sum);补充其它求和 long sum list.stream().reduce(Integer::sum).orElse(0);//ListInteger return sellOutWarnCategoryCountDOS.stream().collect(Collectors.summingInt(SellOutWarnCategoryCountDO::getTodoSkuCount));2、reduce(BinaryOperator)无初始值返回Optional对象 OptionalInteger sumOptional list.stream().reduce((a, b) - a b);if (sumOptional.isPresent()) {Integer sum sumOptional.get();}等价语法糖OptionalInteger sumOptional list.stream().reduce(Integer::sum);if (sumOptional.isPresent()) {Integer sum sumOptional.get();}实战map-reduce 获取大仓对应的品类仓集合MapLong, ListLong return Lists.partition(rdcIds, 20).stream().map(subRdcIds - CompletableFuture.supplyAsync(() - queryCategoryWarehouseByRdc(subRdcIds),cQueryExecutor)).collect(toList()).stream().map(CompletableFuture::join).reduce((m1, m2) - {m1.putAll(m2);return m1;}).orElse(Maps.newHashMap());//等价// 1.并发查询ListCompletableFutureMapLong, ListLong list1 Lists.partition(rdcIds, 20).stream().map(subRdcIds - CompletableFuture.supplyAsync(() - queryCategoryWarehouseByRdc(subRdcIds), cQueryExecutor)).collect(toList());// 2.阻塞获取结果ListMapLong, ListLong list2 list1.stream().map(mapCompletableFuture - {return mapCompletableFuture.join();}).collect(toList());// 3.reduce【把一个流中的元素组合起来】MapLong, ListLong result list2.stream().reduce((map1, map2) - {map1.putAll(map2);return map1;}).orElse(new HashMap());// 4.listListInteger同理reduce中(collect1, collect2) - collect1.addAll(collect2) return collect1实战list-reduce eg1 int threshold 200;return Lists.partition(skuIds, threshold).stream().map(skus - {SdcTrusteeshipSkuDOExample example new SdcTrusteeshipSkuDOExample();example.createCriteria().andSkuIdIn(skus).andSaleDayEqualTo(saleDay).andNetPoiIdEqualTo(netPoiId).andValidEqualTo(Boolean.TRUE);return example;}).map(example - sdcTrusteeshipSkuMapper.selectByExample(example)).reduce((sdcTrusteeshipSkuDoList1, sdcTrusteeshipSkuDoList2) - {sdcTrusteeshipSkuDoList1.addAll(sdcTrusteeshipSkuDoList2);return sdcTrusteeshipSkuDoList1;}).orElse(Lists.newArrayList());eg2 // 方式1使用flatMapListPoiBasicTInfo res1 Lists.partition(poiIds, POI_LIMIT_SIZE).stream().map(partPoiIds - CompletableFuture.supplyAsync(() - queryPoiInfoByPoiId(partPoiIds), cQueryExecutor)).collect(toList()).stream().map(CompletableFuture::join).flatMap(List::stream).collect(toList()); // 方式2使用reduceListPoiBasicTInfo res Lists.partition(poiIds, POI_LIMIT_SIZE).stream().map(partPoiIds - CompletableFuture.supplyAsync(() - queryPoiInfoByPoiId(partPoiIds), cQueryExecutor)).collect(toList()).stream().map(CompletableFuture::join).reduce(Collections.emptyList(), (l1, l2) - {l1.addAll(l2);return l1;});实战CompletableFuture-reduce ListCompletableFutureT, 集合中的每个元素都是 CompletableFutureListCompletableFutureListInteger tempList Lists.partition(model.getSkuIdList(), LionUtil.batchQueryLockStatusSize()).stream().map(skus - buildQueryLockStockStatusParam(model.getNetPoiId(), skus, model.getPickDate())).map(lockStatusParam - CompletableFuture.supplyAsync(() -stmLockMaxStockGateway.getLockStatus(lockStatusParam), queryLockStatusAndOrExecutor)).collect(Collectors.toList());CompletableFutureListInteger cf1 tempList.stream().reduce(// 每个元素都是cfcfcf cf之间可以通过thenCombine的形式聚合结果(fn1, fn2) - fn1.thenCombine(fn2, (integers, integers2) - Stream.of(integers, integers2).flatMap(Collection::stream).collect(Collectors.toList()))).orElse(CompletableFuture.completedFuture(Collections.emptyList()));2.7.2 max、min、count 1、max 最大 ListInteger list Lists.newArrayList(1, 2, 3);OptionalInteger optional list.stream().reduce((a, b) - a b ? a : b);if (optional.isPresent()) {Integer max optional.get();}// 等效OptionalInteger optional list.stream().max((a, b) - a.compareTo(b));// 语法糖OptionalInteger optional1 list.stream().max(Integer::compareTo);2、count list.stream().count() list.size()2.7.3 concat合并多个流 https://www.leftso.com/blog/613.html2.8 使用流-归约 Collect 2.8.1 简介 1、collect、Collector、Collectors collect是流的终端操作类似reduce是归约操作将流元素累积成一个汇总结果。collect方法的参数是Collector接口的具体实现Collector是一个普通接口Collectors是一个final类提供了许多静态工厂方法返回值为Collector 2、收集器 作用不同的收集器对流做不同的归约操作主要三大功能归约和汇总、分组、分区创建Collector接口的具体实现类、Collectors类的静态工厂方法创建Collectors.toList()、Collectors.groupingBy()等 2.8.2 归约和汇总-LongSummaryStatistics 1、个数、最大值、最小值、平均值、总和等 Testpublic void t(){ArrayListInteger list Lists.newArrayList(1, 2, 3, 4, 5);IntSummaryStatistics collect list.stream().collect(Collectors.summarizingInt(Integer::intValue));System.out.println(collect);//IntSummaryStatistics{count5, sum15, min1, average3.000000, max5}}LongSummaryStatistics参考https://juejin.cn/post/7119674659330588686 NumberUtils参考https://www.jianshu.com/p/46472ab7246b 2.8.3 连接字符串-join joining内部使用了StringBuilder来把字符串逐个加起来 MyUser myUser new MyUser();myUser.setCwId(1L);myUser.setCwName(hello);MyUser myuser2 new MyUser();myuser2.setCwId(1L);myuser2.setCwName(world);ListMyUser myUsers Lists.newArrayList(myUser, myuser2);String collect myUsers.stream().map(MyUser::getCwName).collect(Collectors.joining(, ));//hello, world2.8.4 归约 - reducing MyUser u1 new MyUser();u1.setAge(18);MyUser u2 new MyUser();u2.setAge(28);ArrayListMyUser list Lists.newArrayList(u1, u2);Integer sum list.stream().map(MyUser::getAge).reduce(0, Integer::sum); //正常推荐map reduceInteger sum2 list.stream().collect(Collectors.reducing(0, MyUser::getAge, Integer::sum));IntStream intStream list.stream().mapToInt(MyUser::getAge); int sum3 intStream.sum(); //不拆箱推荐此种2.8.5 分组- groupingBy 1、groupingBy(Function? super T, ? extends K func)方法入参为函数式接口Function这里叫分类函数可以将流中元素分为不同的组 按照性别分组 MyUser u1 new MyUser();u1.setAge(10);u1.setName(zhangsan);u1.setSex(1);MyUser u2 new MyUser();u2.setAge(40);u2.setName(lisi);u2.setSex(1);MyUser u3 new MyUser();u3.setAge(50);u3.setName(lilei);u3.setSex(0);ListMyUser list Lists.newArrayList(u1,u2, u3);MapInteger, ListMyUser map list.stream().collect(groupingBy(MyUser::getSex));//{0[MyUser(age50, namelilei, sex0)], 1[MyUser(age10, namezhangsan, sex1), MyUser(age40, namelisi, sex1)]}按照年龄段自定义分组。枚举青年【YONG20 - 30】、中年【MIDDLE 30 - 50】、老年【OLD 50】 Getter AllArgsConstructor public enum AgeEnum {YOUNG(1, 年轻人),MIDDLE(2, 中年),OLD(3, 老年);private final Integer code;private final String desc; }ListMyUser list Lists.newArrayList(u1, u2, u3);MapString, ListMyUser map list.stream().collect(groupingBy(user - {Integer age user.getAge();if (age 30) {return AgeEnum.YOUNG.getDesc();} else if (age 50) {return AgeEnum.MIDDLE.getDesc();} else {return AgeEnum.OLD.getDesc();}}));System.out.println(map);2、CollectorT, ?, MapK, D groupingBy(Function? super T, ? extends K func, Collector? super T, A, D c) 第一个入参为函数式接口Function这里叫分类函数可以将流中元素分为不同的组 第二个参数是Collector接口的实现类也是一个收集器 作用第二个收集器通常对被参数一分到同一组中的所有元素再执行一次归约操作 场景用于多级分组、分组后过滤、分组后再映射 a过滤 按照性别分组每组人只要年龄小于35岁的Collectors.filtering //{1[MyUser(age10, namezhangsan, sex1)]} 发现0对应的分组因为没有符合的元素导致key都没了MapInteger, ListMyUser map1 list.stream().filter(myUser - myUser.getAge() 35).collect(groupingBy(MyUser::getSex));//{0[], 1[MyUser(age10, namezhangsan, sex1)]} 分组0没有元素但是key还存在其中filtering为Jdk9方法MapInteger, ListMyUser map2 list.stream().collect(groupingBy(MyUser::getSex,Collectors.filtering(user - user.getAge() 35),toList()));每种性别中年龄最小的人 MapInteger, OptionalMyUser map list.stream().collect(groupingBy(MyUser::getSex,Collectors.minBy(Comparator.comparingInt(MyUser::getAge))));//{0Optional[MyUser(age40, namelilei, sex0)], 1Optional[MyUser(age10, namezhangsan, sex1)]}//去掉OptionalMapInteger, MyUser map list.stream().collect(groupingBy(MyUser::getSex,Collectors.collectingAndThen(Collectors.minBy(Comparator.comparingInt(MyUser::getAge)),Optional::get)));b映射按照性别分组取每组人的姓名Collectors.mapping // 3.按照性别分组然后取姓名{0[lilei], 1[lisi, zhangsan]}MapInteger, SetString map3 list.stream().collect(groupingBy(MyUser::getSex,mapping(MyUser::getName, Collectors.toSet())));c多级分组不同性别、不同的年龄划分 ListMyUser list Lists.newArrayList(u1,u2, u3, u4);MapInteger, MapString, ListMyUser map list.stream().collect(groupingBy(MyUser::getSex,groupingBy(user - {Integer age user.getAge();if (age 30) {return AgeEnum.YOUNG.getDesc();} else if (age 50) {return AgeEnum.MIDDLE.getDesc();} else {return AgeEnum.OLD.getDesc();}}))); 0{老年[MyUser(age100, namehanmeimei, sex0)], 中年[MyUser(age40, namelilei, sex0)] }, 1{年轻人[MyUser(age10, namezhangsan, sex1)], 中年[MyUser(age40, namelisi, sex1)] }d子组收集器不同性别、人数 ListMyUser list Lists.newArrayList(u1,u2, u3, u4);MapInteger, Long map list.stream().collect(groupingBy(MyUser::getSex,Collectors.counting()));3、CollectorT, ?, M groupingBy(Function? super T, ? extends K func ,Supplier mapFactory, Collector? super T, A, D downstream) 第二个参数是函数式接口【void - T】第一、三个入参同上 2.8.6 分区 1、定义特殊的分组。分组可以分为年轻、中年、老年多个组但是分区只能有两个组越库True、非越库False 2、优势结构紧凑、高效 3、实战 性别分区 MapBoolean, ListMyUser map list.stream().collect(Collectors.partitioningBy(user - user.getSex().equals(1)//男性));男性|女性 中年龄最大的 对分区后的每个区中的元素再进行一收集 MapBoolean, MyUser map list.stream().collect(Collectors.partitioningBy(user - user.getSex().equals(1),Collectors.collectingAndThen(Collectors.maxBy(Comparator.comparingInt(MyUser::getAge)),Optional::get)));将数字按质量数和非质数分区 // 2-10的质数 StreamInteger stream IntStream.rangeClosed(2, 10).boxed();MapBoolean, ListInteger map stream.collect(partitioningBy(n - isPrime(n)));// {false[4, 6, 8, 9, 10], true[2, 3, 5, 7]}private boolean isPrime(Integer n) {IntStream range IntStream.range(2, n); //从[2 ~ n-1]都无法被n整除则n为质数return range.noneMatch(i - n % i 0); }2.8.7 list转为map: toMap(类似常用的toList) 1、将list中对象的某两个属性作为map的k-v MapLong, String cwIdAndNameMap cwInfoByCwIds.stream().collect(Collectors.toMap(Warehouse::getCwId, Warehouse::getName));2、将list中对象的某些属性组成key对象为val MapString, MyUser map list.stream().collect(Collectors.toMap(user - buildKey(user),Function.identity() //表示T - T所以这里也可以写user - user));将listObj中Obj作为keyObj中几个属性组成一个新的NewObj作为val list.stream().collect(Collectors.toMap(Function.identity(), sellOutWarnSkuBo - {LockStockRequest lockStockRequest new LockStockRequest();lockStockRequest.setSkuId(sellOutWarnSkuBo.getSkuId());lockStockRequest.setPoiId(sellOutWarnSkuBo.getNetPoiId());return lockStockRequest;},(l1, l2) - l1)); //如果需要第三个参数则这种形式三、Java8新增特性 3.1 Map相关 3.1.0 compute、computeIfAbsent、putIfAbsent、put put: 方法存储作用没有key对应的val则直接存有key对应的val则覆盖 返回值put返回旧值如果没有则返回null public void put() {MapString, Integer map Maps.newHashMap();map.put(a,1);Integer b map.put(b, 2);System.out.println(b);//nullInteger v map.put(b,3); // 输出 2System.out.println(v);Integer v1 map.put(c,4);System.out.println(v1); // 输出NULL}compute:方法存储作用同理put。存储返回值返回新值如果没有则返回null putIfAbsent 没有key对应的val则直接存有key对应的val则不存储 返回值同put方法的返回旧值没有返null computeIfAbsent 存在了就不添加也就不覆盖了还是原值返回的就是原值。不存在时添加返回添加的值 MapString, Integer map Maps.newHashMap();//存在时返回存在的值不存在时返回新值map.put(a,1);map.put(b,2);Integer v map.computeIfAbsent(b,k-3); // 输出 2System.out.println(v);Integer v1 map.computeIfAbsent(c,k-4); // 输出 4System.out.println(v1);System.out.println(map);//{a1, b2, c4}3.1.1 排序 MapString,Integer result new HashMap();MapString,Integer map new HashMap();map.entrySet().stream().sorted(Map.Entry.comparingByKey()) //对key排序还可以对val排序也可以降序.forEachOrdered(e - result.put(e.getKey(), e.getValue())); // 注意这里其实result已经按照key进行了排序但是map在遍历的时候是随机的所以遍历result的时候结果看起来还是随机的 // 1.如果想让遍历的result也是有序的则可以使用TreeMap、LinkedHashMap // 2.如果只是想按照key正序遍历map则可以直接在forEachOrdered里面获取k-v即可3.1.2 计数 computeIfAbsent将相同的数存储到一个对应List集合中 存储key不存在或为null则存k-v。key存在则不存返回值如果 key 不存在或为null则返回 本次存储的val key 已经在返回对应的 val //场景将相同的数存储到一个对应List集合中ListInteger list Lists.newArrayList(1,2,3,1,3,4,6,7,9,9,1,3,4,5);MapInteger, ListInteger map new HashMap();list.forEach(item - {ListInteger integerList map.computeIfAbsent(item, key - new ArrayList());integerList.add(item);});System.out.println(map);//{1[1, 1, 1], 2[2], 3[3, 3, 3], 4[4, 4], 5[5], 6[6], 7[7], 9[9, 9]}线程安全的计算key出现的次数 AtomicLongMapString map AtomicLongMap.create(); //线程安全支持并发ListString list Lists.newArrayList(a, a, b, c, d, d, d);list.forEach(map::incrementAndGet);这里使用AtomicLongMap的原因https://blog.csdn.net/HEYUTAO007/article/details/61429454 import com.google.common.util.concurrent.AtomicLongMap; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.locks.ReentrantReadWriteLock;public class GuavaTest {//来自于Google的Guava项目AtomicLongMapString map AtomicLongMap.create(); //线程安全支持并发MapString, Integer map2 new HashMapString, Integer(); //线程不安全MapString, Integer map3 new HashMapString, Integer(); //线程不安全ReentrantReadWriteLock lock new ReentrantReadWriteLock(); //为map2增加并发锁MapString, Integer map4 new ConcurrentHashMapString, Integer(); //线程安全但也要注意使用方式private int taskCount 100;CountDownLatch latch new CountDownLatch(taskCount); //新建倒计时计数器设置state为taskCount变量值public static void main(String[] args) {GuavaTest t new GuavaTest();t.test();}private void test(){//启动线程for(int i1; itaskCount; i){Thread t new Thread(new MyTask(key, 100));t.start();}try {//等待直到state值为0再继续往下执行latch.await();} catch (InterruptedException e) {e.printStackTrace();}System.out.println(##### AtomicLongMap #####);for(String key : map.asMap().keySet()){System.out.println(key : map.get(key));}System.out.println(##### HashMap未加ReentrantReadWriteLock锁 #####);for(String key : map2.keySet()){System.out.println(key : map2.get(key));}System.out.println(##### HashMap加ReentrantReadWriteLock锁 #####);for(String key : map3.keySet()){System.out.println(key : map3.get(key));}System.out.println(##### ConcurrentHashMap #####);for(String key : map4.keySet()){System.out.println(key : map4.get(key));}}class MyTask implements Runnable{private String key;private int count 0;public MyTask(String key, int count){this.key key;this.count count;}Overridepublic void run() {try {for(int i0; icount; i){map.incrementAndGet(key); //key值自增1后返回该key的值if(map2.containsKey(key)){map2.put(key, map2.get(key)1);}else{map2.put(key, 1);}//对map2添加写锁可以解决线程并发问题lock.writeLock().lock();try{if(map3.containsKey(key)){map3.put(key, map3.get(key)1);}else{map3.put(key, 1);}}catch(Exception ex){ex.printStackTrace();}finally{lock.writeLock().unlock();}//虽然ConcurrentHashMap是线程安全的但是以下语句块不是整体同步导致ConcurrentHashMap的使用存在并发问题if(map4.containsKey(key)){map4.put(key, map4.get(key)1);}else{map4.put(key, 1);}//TimeUnit.MILLISECONDS.sleep(50); //线程休眠50毫秒}} catch (Exception e) {e.printStackTrace();} finally {latch.countDown(); //state值减1}}}}3.1.3 两个map合并-merge putAll MapString, Integer map new HashMap();MapString, Integer map1 new HashMap();map.put(tmac, 18);map.put(mjp, 40);map.put(wxx, 23);map1.put(wxx, 1);map1.putAll(map); // 如果map 和 map1有相同的keyputAll的时候不会覆盖merge MapInteger, String map new HashMap();MapInteger, String map1 new HashMap();map.put(1,mjp);map.put(2,wxx);map1.put(1, tmac);map.forEach((k, v) - {map1.merge(k, v, (v1 , v2) - v1 - v2);}); // map1 {1tmac-mjp, 2wxx}3.1.4 其它 map的key为不常见的类型时 MapByte, ListUser map list.stream().collect(Collectors.groupingBy(User::getTemperatureZone)); ListUser resList map.get((byte)5); 错误ListUser resList map.get(5); npe3.2 Optional 3.2.1 Optional简介 作用Optional 类的引入很好的解决空指针异常。Optional 是个容器它可以保存类型T的值或者仅仅保存nullOptinal类本质上是一个只能存放一个元素的不可变集合Optional.empty ()返回一个空的optionalOptional.of(value)返回一个包含了指定非null值的optional 3.2.2 Optional常用方法 点击展开内容 方法名称作用eg备注empty()返回空的 Optional 实例Optional*Integer* optional Optional.empty*();//Optional.emptyboolean present o.isPresent()*;//falseOptional集合中有一个为Null的元素则ifPresent返回falseifPresent值存在则方法会返回trueOptional*Integer* optional2 Optional.ofNullable*(1)*;//Optional[1]Optional集合中有一个不为Null的元素1则ifPresent返回trueofNullable(T value)如果为非空返回 Optional 描述的指定值否则返回空的 OptionalOptional*Integer* optional2 Optional.ofNullable*(null);//Optional.empty OptionalInteger* optional3 Optional.ofNullable*(3)*;//Optional[3]of(T value)value不能为null否则会npeOptional.of*(null)*;//NPE/map如果调用方有值则对其执行调用映射函数得到返回值。 如果返回值不为 null则创建包含映射返回值的Optional作为map方法回值调用方无值否则返回空Optional。Optional*Integer* optional Optional.ofNullable*(3);//Optional[3]optional有值且map映射后的返回值也不为null则最终返回Optional[“0011”]OptionalString* optionalByte optional.map*(Integer::toBinaryString);OptionalInteger* optional Optional.ofNullable*(null);//Optional.emptyOptionalString* optionalByte optional.map*(Integer::toBinaryString)*; optional无值则返回Optional.emptyOptional*Integer* optional Optional.ofNullable*(3);OptionalString* result optional.map*(null)*; 报错npeorElse**(T other)**如果存在该值返回值 否则返回 other。Optional*Integer* optional Optional.ofNullable*(1);//Optional[3] Integer result optional.orElse(23); System.out.println(result);//1 OptionalInteger* optional1 Optional.empty*(); Integer result1 optional1.orElse(23); System.out.println(result1)*;//23 3.2.3 优雅的取值 dto.setSupplierId(Optional.ofNullable(source.getVendorDTO()).map(VendorDTO::getVendorId).orElse(null)) 3.2.4 注意事项 不要给 Optional 变量赋值 null否则违背了Optional的初衷 OptionalInteger optional Optional.empty(); OptionalString result optional.map(Integer::toBinaryString);//Optional.emptyOptionalInteger optional null; OptionalString result optional.map(Integer::toBinaryString); System.out.println(result);//npe3.3 时间类 3.3.1 Temporal实现类 2022-12-14 07:14:41 对应LocalDateTime操作2022-12-14对应LocalDate操作07:14:41对应LocalTime操作 3.3.2 ChronoUnit 天数差计算某天距某天过了多少天年差、小时差、分钟差等 long diffDays ChronoUnit.DAYS.between(LocalDate.now(), LocalDate.of(2018, 10, 8));System.out.println(diffDays);//-1529long diffDays2 ChronoUnit.DAYS.between(LocalDate.of(2018, 10, 8), LocalDate.now());System.out.println(diffDays2);//15293.3.3 Period 和 Duration LocalDate startDate LocalDate.of(2022, 12, 12);LocalDate endDate LocalDate.of(2022, 11, 11);Period period Period.between(endDate, startDate);int diffDays period.getDays();System.out.println(diffDays);// 应该为31这里为1天因为Period无法处理跨越的天数差计算使用参考https://blog.csdn.net/neweastsun/article/details/88770592 3.4 默认方法 3.4.1 简介 背景接口引入默认方法可以让接口的实现类自动的继承 egList接口的sort 注意函数式接口只是包含一个抽象方法但是可以包含一个或多个默认方法 egPredicate接口中and、or默认方法 3.4.1 菱形问题 1、问题描述一个类同时继承了具有相同函数签名的两个方法 类可以实现多个接口假如每个接口都有默认方法则类可以从多个接口中继承他们的行为默认方法 假如不同接口的默认方法函数签名一样则会出现二义性 与此同时此类本身也可能定义了此相同签名的方法 与此同时类也可能继承的父类获取了此相同签名的方法 2、解决菱形问题 类中的方法优先级最高类或者父类中声明的方法优先级高于默认方法 其次子接口的优先级高于父接口 最后如果还是无法判断则类必须显式覆盖 和调用期望的方法显式的选择使用哪一个默认方法的实现 C中覆盖方法并显式的调用 public class C implements B,A {void hello(){B.super().hello();//java8引入的新语法表示调用B接口中的hello方法} }3、特殊场景 如果D是抽象类D中的方法是抽象方法则C类就必须提供自己的hello方法 现在D调用hello()是调用A的方法如果B也提供了一个默认的hello()则使用B的 如果B、C都提供了默认的hello()则D就要显式的调用 如果B提供的不是默认hello()而是一个abstract抽象hello()D会调用子类接口C的抽象hello故D需要需要为C的abstract抽象添加具体的实现代码否则无法编译 四、CompletableFuture 4.1 简介 4.1.1 产生背景 JDK5新增了Future接口用于描述一个异步计算的结果。虽然 Future 以及相关使用方法提供了异步执行任务的能力但是对于结果的获取却是很不方便只能通过阻塞或者轮询的方式得到任务的结果。阻塞的方式显然和我们的异步编程的初衷相违背轮询的方式又会耗费无谓的 CPU 资源而且也不能及时地得到计算结果。Java8中CompletableFuture提供了非常强大的Future的扩展功能(implement Future)可以帮助我们简化异步编程的复杂性并且提供了函数式编程的能力可以通过回调的方式处理计算结果也提供了转换和组合 CompletableFuture 的方法。 4.1.2 概念 它实现了Future和CompletionStage接口 CompletionStage代表异步计算过程中的某一个阶段一个阶段完成以后可能会触发另外一个阶段 一个阶段的计算执行可以是一个FunctionConsumer或者Runnable。 比如stage.thenApply(x - square(x)).thenAccept(x - System.out.print(x)).thenRun(() - System.out.println()) 一个阶段的执行可能是被单个阶段的完成触发也可能是由多个阶段一起触发 4.2 正确使用姿势 RunWith(SpringRunner.class) SpringBootTest(classes ApplicationLoader.class) Slf4j public class BaseTest {/**** xxx(args):CompletableFeture会把任务A和任务B封装为一个任务submit给默认线程池ForkJoinPool* xxxAsync(args)任务A和任务B是两个独立的异步任务分别submit给默认线程池ForkJoinPool开启两个独立的thread执行* xxxAsync(args,executor)同上只不过是自定义线程池*//*** 1、thenCompose : 连接* 等效方法thenApply* 串行A异步执行完B才能执行。然后返回A、B执行结果给main* A厨师炒完番茄鸡蛋、B服务员再去拿米饭main 吃饭*/Testpublic void thenCompose() {System.out.println(Thread.currentThread().getName() :进入餐厅);System.out.println(Thread.currentThread().getName() :点了番茄炒蛋和米饭);CompletableFutureString cf1 CompletableFuture.supplyAsync(() - {System.out.println(Thread.currentThread().getName() :炒番茄鸡蛋);return 炒番茄鸡蛋;}).thenCompose(work1Return - CompletableFuture.supplyAsync(() - {System.out.println(Thread.currentThread().getName() :拿米饭);return work1Return 米饭;}));System.out.println(Thread.currentThread().getName() :王者荣耀);System.out.println(Thread.currentThread().getName() String.format(%s, 开吃 cf1.join()));}/*** 1、1 thenComposeAsync : 连接* 等效方法thenApplyAsync* 串行A异步执行完B才能【异步】执行。然后返回A、B执行结果给mainA和B是两个异步任务由两个独立的线程执行* A厨师炒完番茄鸡蛋、B服务员再去拿米饭main 吃饭*/Testpublic void thenComposeAsync() {System.out.println(Thread.currentThread().getName() :进入餐厅);System.out.println(Thread.currentThread().getName() :点了番茄炒蛋和米饭);CompletableFutureString cf1 CompletableFuture.supplyAsync(() - {System.out.println(Thread.currentThread().getName() :炒番茄鸡蛋);return 炒番茄鸡蛋;}).thenComposeAsync(work1Return - CompletableFuture.supplyAsync(() - {System.out.println(Thread.currentThread().getName() :拿米饭);return work1Return 米饭;}));System.out.println(Thread.currentThread().getName() :王者荣耀);System.out.println(Thread.currentThread().getName() String.format(%s, 开吃 cf1.join()));}/*** 2、thenCombine合并* A异步执行同时B异步执行A、B异步执行结束将结果返回给main* A厨师炒菜同时 B服务员蒸饭AB结束main吃饭* A计算商品件数同时B计算商品价格AB结束计算GMV A * B*/Testpublic void thenCombine() {System.out.println(Thread.currentThread().getName() :进入餐厅);System.out.println(Thread.currentThread().getName() :点了番茄炒蛋和米饭);CompletableFutureString cf1 CompletableFuture.supplyAsync(() - {System.out.println(Thread.currentThread().getName() :炒番茄鸡蛋);return 炒番茄鸡蛋;}).thenCombine(CompletableFuture.supplyAsync(() - {System.out.println(Thread.currentThread().getName() :服务员做饭);return 蒸米饭;}), (dish, rich) - {System.out.println(Thread.currentThread().getName() :菜饭都好了);return String.format(%s %s, dish, rich);});System.out.println(Thread.currentThread().getName() :王者荣耀);System.out.println(Thread.currentThread().getName() String.format(%s, 开吃 cf1.join()));}/*** 3、applyToEither获取最先完成的任务* 141先到就坐141青卢线先到就坐青卢线。* A和B都是异步执行谁先结束就把谁的结果交给赋值applyToEither函数的第二个参数Function函数* main就用Function返回结果继续执行别的操作*/Testpublic void applyToEither() {CompletableFutureString cf1 CompletableFuture.supplyAsync(() - {try {TimeUnit.SECONDS.sleep(1l);} catch (InterruptedException exception) {exception.printStackTrace();}System.out.println(Thread.currentThread().getName() :141来了);return 141;}).applyToEither(CompletableFuture.supplyAsync(() - {try {TimeUnit.SECONDS.sleep(2l);} catch (InterruptedException exception) {exception.printStackTrace();}System.out.println(Thread.currentThread().getName() 青卢线来了);return 青卢线;}),firstCar - firstCar);System.out.println(Thread.currentThread().getName() String.format(坐%s 回家 , cf1.join()));}/*** 1min内电话没人接则挂断。有人接则沟通*/Testpublic void applyToEither2() {CompletableFutureString cf1 CompletableFuture.supplyAsync(() - {try {TimeUnit.SECONDS.sleep(60l);} catch (InterruptedException exception) {exception.printStackTrace();}System.out.println(Thread.currentThread().getName() 挂断);return 60s内没人接;}).applyToEither(CompletableFuture.supplyAsync(() - {try {TimeUnit.SECONDS.sleep(4l);} catch (InterruptedException exception) {exception.printStackTrace();}System.out.println(Thread.currentThread().getName() 接通了);return 沟通;}),res - res);System.out.println(Thread.currentThread().getName() String.format(本次call%s , cf1.join()));}/*** 4、exceptionally处理任务异常可在任意任务后加不一定非在最后加* 如果某个异步任务出了你认为可能出的相应异常则可以在异步执行代码中throw然后在最后exceptionally处理对应异步任务的对应异常*/Testpublic void exceptionally(){CompletableFutureString cf1 CompletableFuture.supplyAsync(() - {try {TimeUnit.SECONDS.sleep(1l);} catch (InterruptedException exception) {exception.printStackTrace();}System.out.println(Thread.currentThread().getName() :141来了);return 141;}).applyToEither(CompletableFuture.supplyAsync(() - {try {TimeUnit.SECONDS.sleep(2l);} catch (InterruptedException exception) {exception.printStackTrace();}System.out.println(Thread.currentThread().getName() 青卢线来了);return 青卢线;}), res - {System.out.println(Thread.currentThread().getName() : res);if (res.startsWith(141)) {throw new RuntimeException(141堵死了不动了);}return res;}).exceptionally(e - {System.out.println(Thread.currentThread().getName() e.getMessage());System.out.println(Thread.currentThread().getName() 叫车);return taxi;});System.out.println(Thread.currentThread().getName() String.format(坐%s 回家 , cf1.join()));}Testpublic void tt2() throws ExecutionException, InterruptedException {CompletableFutureVoid cf1 CompletableFuture.runAsync(() - {System.out.println(Thread.currentThread().getName() :141-start);try {TimeUnit.SECONDS.sleep(1l);} catch (InterruptedException exception) {exception.printStackTrace();}System.out.println(Thread.currentThread().getName() :141-end);});CompletableFutureVoid cf2 CompletableFuture.runAsync(() - {System.out.println(Thread.currentThread().getName() :23-start);try {TimeUnit.SECONDS.sleep(5l);} catch (InterruptedException exception) {exception.printStackTrace();}System.out.println(Thread.currentThread().getName() :23-end);});cf1.runAfterEither(cf2,() - System.out.println(all end)).thenRun(() -{cf1.cancel(false);cf2.cancel(false);}).get();}/**** 5、runAsync和supplyAsync类似只不过runAsync没有返回值*//**** 6、thenCompose thenApply thenAccept(需要前一个异步任务的返回结果但是thenAccept连接方法中无返回值)*//**** 7、thenCompose thenAccept(需要前一个异步任务的返回结果但是thenAccept连接方法中无返回值)* thenRun(不需要前一个异步任务的返回结果thenRun连接方法中也无返回值)*//**** 8、thenCombine thenAcceptBoth (任务A和任务B合并执行结果但是合并结果方法thenAcceptBoth中无返回值)* runAfterBoth(不需要任务A和任务B的合并返回结果runAfterBoth合并方法中也无返回值)*//**** 9、applyToEither acceptEither (得到任务A和任务B最先执行完的任务的结果acceptEither中无返回值)* runAfterEither(不关心任务A和任务B谁先执行完runAfterEither也无返回值)*//**** 10、exceptionally handle (如果任务正常则返回正常结果、如果任务异常则返回异常结果。后面程序都会正常执行,有返回值)* whenComplete(类型handle但无返回值)*//**** 11、join:等待异步任务完成* allOf:将ListCompletableFuture 看成是一个CompletableFeture* allOf(listCompletableFuture 每个异步任务都装到这个异步任务list中).join*//**** 12、thenRun:等待异步任务完成,异步任务可能有返回值也可能没有*/ }4.3 get方法和join方法区别 4.3.1 相同点 join()和get()方法都是用来获取CompletableFuture异步之后的返回值,都是waitingGet阻塞拿结果 4.3.2 区别 join()方法抛出的是uncheck异常即未经检查的异常),不会强制开发者抛出 public static void main(String[] args) { //2、这里不用throwsCompletableFutureInteger f1 CompletableFuture.supplyAsync(() - {int i 1/0;return 1;});CompletableFuture.allOf(f1).join(); //1、这里没有强制要求try-catch或者throwsSystem.out.println(CompletableFuture Test);}public static void main(String[] args) throws ExecutionException, InterruptedException {//2.要么这里throwsCompletableFutureInteger f1 CompletableFuture.supplyAsync(() - {int i 1/0;return 1;});f1.get();System.out.println(CompletableFuture Test);//1.要么这里try-catch}4.4 实战 4.4.1 单个并发查询 【根据仓id查询仓名称。500个仓id每次只能查询200个并发查询】 ListPoiBasicTInfo result Lists.partition(poiIds, 200).stream().map(partPoiIds - CompletableFuture.supplyAsync(() - queryPoiInfoByPoiId(partPoiIds)//方法返回ListPoiBasicTInfo, cQueryExecutor)).collect(Collectors.toList()).stream().map(CompletableFuture::join).flatMap(List::stream).collect(Collectors.toList());4.4.2 两个参数都是集合一起作为异步查询的入参并发查询 skuIds400个sku200A、200B pcIds两个PC仓id1id2 skuId和pcId需要一起作为参数并发查询即四种组合并发查询A1A2B1B2 rpc查询结果返回ListProcessPlanDtoListProcessPlanDto result Lists.partition(needFilterSkuIds, 200).stream().map(subNeedFilterSkuIds - pcPoiIds.stream().map(pcId - CompletableFuture.supplyAsync(() - {try {return pcGateway.querySkuProcessPlan4Sku(pcId, subNeedFilterSkuIds, pickDate);} catch (Exception e) {log.error(STC列表,查询加工计划发生异常, e);}return new ArrayListProcessPlanDto();}, pcAllocateSupplyTypeFilterExecutor)).collect(Collectors.toList())).flatMap(Collection::stream).collect(Collectors.toList()).stream().map(CompletableFuture::join).reduce((processPlanDtos, processPlanDtos2) - {processPlanDtos.addAll(processPlanDtos2);return processPlanDtos;}).orElse(Lists.newArrayList());// 上面步骤解析StreamListCompletableFutureListProcessPlanDto stream Lists.partition(needFilterSkuIds, processPlanQueryThreshold).stream().map(needFilterSkus - finalPcPoiIds.stream().map(pcId - CompletableFuture.supplyAsync(() - {try {return pcGateway.querySkuProcessPlan4Sku(pcId, needFilterSkus, pickDate);} catch (Exception e) {log.error(查询加工计划发生异常, e);}return new ArrayListProcessPlanDto();}, pcAllocateSupplyTypeFilterExecutor)).collect(Collectors.toList()));StreamCompletableFutureListProcessPlanDto stream1 stream.flatMap(List::stream);StreamListProcessPlanDto stream2 stream1.map(CompletableFuture::join);ListProcessPlanDto res stream2.flatMap(List::stream).collect(Collectors.toList());补充这里为了弱依赖pcGateway.querySkuProcessPlan4Sku所以吃掉异步查询可能抛出来的异常4.4.3 List paramlist MapIntegerList map一起并发查询 1、数据结构 paramlist为[仓1 400sku、仓2 400sku、-----] map中key 1value List serviceList1serviceList1为sever1、sever2、key 2value List serviceList2serviceList为sever3 2、背景map中所有key对应的所有service都要作用于paramlist即key1对应的sever1 查询仓1 400sku 、sever1查询仓2 400sku、sever2查询仓1 400sku、sever2查询仓2 400sku 同时key2对应的sever3 查询仓1 400sku 、sever3查询仓2 400sku 3、目的让他们全部并发查询 4、实现代码 map.forEach((key, serviceList) - {paramlist.stream().map(param - serviceList.stream().map(service - CompletableFuture.runAsync(() - service.doFunction(param), ownExecutor)).collect(Collectors.toList())).flatMap(Collection::stream).collect(Collectors.toList()).stream().map(CompletableFuture::join).collect(Collectors.toList());});4.4.3 A和B任务二者之间并行查询 同时 A和B本身也要200批次、200批次的并行查询 任务A批量异步并行、任务B批量异步并行。A、B之间并行【A1和A2并行 并行 B1和B2并行】 ListOverStockRiskTypeModel totalList Lists.newArrayList();CompletableFutureMapLong, LockStatusModel cf1 Lists.partition(model.getSkuIdList(), 100).stream().map(skus - buildQueryLockStockStatusParam(model.getNetPoiId(), skus, model.getPickDate())).map(lockStatusParam - CompletableFuture.supplyAsync(() -stmLockMaxStockGateway.getLockStatus(lockStatusParam), queryLockStatusAndOrExecutor))//方法返回MapLong, LockStatusModel.collect(Collectors.toList()).stream().reduce((fn1, fn2) - fn1.thenCombine(fn2, (m1, m2) - {m1.putAll(m2);return m1;})).orElse(CompletableFuture.completedFuture(Maps.newHashMap()));CompletableFutureMapLong, Long cf2 Lists.partition(model.getSkuIdList(),100).stream().map(skus - buildQueryORParam(model.getPoiId(), skus, model.getPickDate())).map(inventoryPredictParam - CompletableFuture.supplyAsync(() -inventoryPredictGateway.getInventoryPredictOrQuantity(inventoryPredictParam), queryLockStatusAndOrExecutor))//方法返回MapLong, Long.collect(Collectors.toList()).stream().reduce((fn1, fn2) - fn1.thenCombine(fn2, (m1, m2) - {m1.putAll(m2);return m1;})).orElse(CompletableFuture.completedFuture(Maps.newHashMap()));allOf(cf1, cf2).thenAccept(v - fillLockStatusAndOrQuantity(totalList, cf1.join(), cf2.join(), model.getNetPoiId())).join();4.4.4 将ListCompletableFuture转为CompletableFutureList cf1 场景转换cf1相同方式再转换cf2想让cf1和cf2一起阻塞拿结果 1、封装方法 public static T CompletableFutureListT sequence2(ListCompletableFutureT com, ExecutorService exec) {if(com.isEmpty()){throw new IllegalArgumentException();}Stream? extends CompletableFutureT stream com.stream();CompletableFutureListT init CompletableFuture.completedFuture(new ArrayListT());return stream.reduce(init, (ls, fut) - ls.thenComposeAsync(x - fut.thenApplyAsync(y - {x.add(y);return x;},exec),exec), (a, b) - a.thenCombineAsync(b,(ls1,ls2)- {ls1.addAll(ls2);return ls1;},exec)); }2、其他方式 //01.首先正常的使用CompletableFuture执行查询得到tempMap ListCompletableFutureMapLong, Long tempMap Lists.partition(model.getSkuIdList(), LionUtil.batchQueryLockStatusSize()).stream().map(skus - buildQueryLockStockStatusParam(model.getNetPoiId(), skus, model.getPickDate())).map(lockStatusParam - CompletableFuture.supplyAsync(() -stmLockMaxStockGateway.getLockStatus(lockStatusParam), queryLockStatusAndOrExecutor)).collect(Collectors.toList());//02.然后实现3.1.1的转换形式形成cf1 CompletableFutureMapLong, LockStatusModel cf1 tempMap.stream().reduce((fn1, fn2) - fn1.thenCombineAsync(fn2, (m1, m2) - {m1.putAll(m2);return m1;}, queryLockStatusAndOrExecutor)).orElse(CompletableFuture.completedFuture(Maps.newHashMap())); //03.最后可以等待B的cf2一起执行join实现并发 fillLockStatusAndOrQuantity(totalList, cf1.join(), cf2.join());4.4.5 将ListCompletableFutureMapLong, Long 变为 CompletableFuture*MapLong, Long* cf1 1、封装方法 public static T CompletableFutureListT sequence2(ListCompletableFutureT com, ExecutorService exec) {if(com.isEmpty()){throw new IllegalArgumentException();}Stream? extends CompletableFutureT stream com.stream();CompletableFutureListT init CompletableFuture.completedFuture(new ArrayListT());return stream.reduce(init, (ls, fut) - ls.thenComposeAsync(x - fut.thenApplyAsync(y - {x.add(y);return x;},exec),exec), (a, b) - a.thenCombineAsync(b,(ls1,ls2)- {ls1.addAll(ls2);return ls1;},exec)); }2、其他方式 //01.首先正常的使用CompletableFuture执行查询得到tempMap ListCompletableFutureMapLong, Long tempMap Lists.partition(model.getSkuIdList(), LionUtil.batchQueryLockStatusSize()).stream().map(skus - buildQueryLockStockStatusParam(model.getNetPoiId(), skus, model.getPickDate())).map(lockStatusParam - CompletableFuture.supplyAsync(() -stmLockMaxStockGateway.getLockStatus(lockStatusParam), queryLockStatusAndOrExecutor)).collect(Collectors.toList());//02.然后实现3.1.1的转换形式形成cf1 CompletableFutureMapLong, LockStatusModel cf1 tempMap.stream().reduce((fn1, fn2) - fn1.thenCombineAsync(fn2, (m1, m2) - {m1.putAll(m2);return m1;}, queryLockStatusAndOrExecutor)).orElse(CompletableFuture.completedFuture(Maps.newHashMap())); //03.最后可以等待B的cf2一起执行join实现并发 fillLockStatusAndOrQuantity(totalList, cf1.join(), cf2.join());4.4.6 并发处理map的k-v而非map.forEach((k,v) 串行处理 MapString, ListUser map new HashMap();User u1 new User();u1.setAge(1);User u2 new User();u2.setAge(2);map.put(mjp, Lists.newArrayList(u1, u2));User u3 new User();u3.setAge(3);User u4 new User();u4.setAge(4);map.put(wxx,Lists.newArrayList(u3, u4));ListCompletableFutureListInteger list map.entrySet().stream().map(entry - CompletableFuture.supplyAsync(() -func((entry)))).collect(Collectors.toList());CompletableFutureListInteger cf list.stream().reduce((fn1, fn2) - fn1.thenCombine(fn2,(integers, integers2) - Stream.of(integers, integers2).flatMap(Collection::stream).collect(Collectors.toList()))).orElse(CompletableFuture.completedFuture(Collections.emptyList()));ListInteger res cf.join();}private ListInteger func(EntryString, ListUser entry) {System.out.println(entry);return Lists.newArrayList(1);}4.4.7 limit、offset并发查询 常规的并发查询都是sku集合400个200、200分批的查 这种场景是limit、offset并发的查 // 查询档期商品Long limit 200L;long threshold 50000L;PageRequest pageRequest request.getPageRequest();pageRequest.setLimit(limit);pageRequest.setOffset(0L);// 1.先rpc0-200查询一次看看总共的totalQuerySkuScheduleListResponse response skuScheduleQueryGateway.querySkuScheduleList(request);Long total response.getTotal();if (total limit) {return response.getSkuScheduleDTOList();}if (total threshold) {total threshold;}// 2.total很多则for循环异步并发查询ListCompletableFutureListSkuScheduleDTO scheduleCfList Lists.newArrayList();for (long offset limit; offset total; offset limit) {QuerySkuScheduleListRequest listRequest copy(request);PageRequest pageRequest1 listRequest.getPageRequest();pageRequest1.setLimit(limit);pageRequest1.setOffset(offset);// 3.虽然是for循环串行着查询但是会异步去查询不会耗时直接进入下一个循环条件CompletableFutureListSkuScheduleDTO scheduleCf CompletableFuture.supplyAsync(() - {try {return skuScheduleQueryGateway.querySkuScheduleList(listRequest).getSkuScheduleDTOList();} catch (GatewayException e) {log.error(查询档期商品接口发生异常, e);}return new ArrayList();}, queryScheduleSkuExecutor);// 4.直接将异步任务添加进来不需要再for循环中等待一个一个的串行查询scheduleCfList.add(scheduleCf);}// 5.在for循环外侧一把拿到多有的并发查询结果ListSkuScheduleDTO skuScheduleDtoList scheduleCfList.stream().map(CompletableFuture::join).flatMap(Collection::stream).collect(Collectors.toList());4.4.8 协同、转运、pc打标并发mark结果一起join 打标是并发执行最终join可以串行执行 noDependencyQueryPredictUniteServiceList.stream().map(queryInventoryUniteBizService - CompletableFuture.runAsync(() - queryInventoryUniteBizService.mark(skuStockUpTypeMarkParam), supplyTypeFilterExecutor)).collect(Collectors.toList()).stream().map(CompletableFuture::join).collect(Collectors.toList());4.4.9 其他 1、rpc结果是List,将其转换为ListCompletableFutureMapLong, Long tempMap再转换为CompletableFuture*MapLong, Long* cf1 ListCompletableFutureMapLong, Long futureList Lists.partition(supplierSkuReservationReqDtos, 200).stream().map(//构造查询参数).map(req - CompletableFuture.supplyAsync(() - {MapLong, Long map null;try {ListX tempList rpc(req);//rpc查询// 这里将rpc查询结果ListX转换为Mapk,vmap tempList.stream().collect(Collectors.toMap(X::getKey,X::getValue));} catch (Exception e) {log.error(StockService,查询直送算法发生异常, e);}if (MapUtils.isEmpty(map)) {map Maps.newHashMap();}return map;}, getReservationIntransitQtyExecutor)).collect(Collectors.toList());MapLong, Long result futureList.stream().map(CompletableFuture::join).reduce((map1, map2) - {map1.putAll(map2);return map1;}).orElse(Maps.newHashMap());2、创建CompletableFuture不做任何处理直接返回空结果或者返回new的集合、map CompletableFutureMapx, x signedWaitingInbound; CompletableFuture.completedFuture(Maps.newHashMap());3、直接结束CompletableFuture的异步查询方法complete() // 操作1List skuScheduleDtoList // 操作2 CompletableFuture PoiRelationDTO cf 异步方法();// 当操作1的结果集合为空则人为的结束异常方法 if (CollectionUtils.isEmpty(skuScheduleDtoList)) {resp.setCode(0);resp.setErrMsg(未查询到符合条件的档期商品);cf.complete(null);return resp; }1、人为的结束异步方法是cf.complete(Futures Result) 2、所有等待这个CompletableFuture 的客户端都将得到一个指定的结果并且 completableFuture.complete() 之后的调用将被忽略。4.5 Java9 CompletableFuture新特性 4.5.1 新增了orTimeOut方法 如果在指定时间内未执行完毕就会抛出一个timeoutException /*** 2、thenCombine合并* A异步执行同时B异步执行A、B异步执行结束将结果返回给main* A厨师炒菜同时 B服务员蒸饭AB结束main吃饭*/Testpublic void t() {System.out.println(Thread.currentThread().getName() :进入餐厅);System.out.println(Thread.currentThread().getName() :点了番茄炒蛋和米饭);CompletableFutureString cf1 CompletableFuture.supplyAsync(() - {System.out.println(Thread.currentThread().getName() :炒番茄鸡蛋);return 炒番茄鸡蛋;}).thenCombine(CompletableFuture.supplyAsync(() - {System.out.println(Thread.currentThread().getName() :服务员做饭);return 蒸米饭;}), (dish, rich) - {System.out.println(Thread.currentThread().getName() :菜饭都好了);return String.format(%s %s, dish, rich);}).orTimeout(3, TimeUnit.SECONDS);System.out.println(Thread.currentThread().getName() :王者荣耀);System.out.println(Thread.currentThread().getName() String.format(%s, 开吃 cf1.join()));}4.5.2 执行超时的时候赋默认结果completeOnTimeOut /*** 2、thenCombine合并* A异步执行同时B异步执行A、B异步执行结束将结果返回给main* A厨师炒菜同时 B服务员蒸饭AB结束main吃饭*/// 这里如果A任务炒菜炒番茄鸡蛋超时了还未完成则可以给A兜底咸菜Testpublic void t() {System.out.println(Thread.currentThread().getName() :进入餐厅);System.out.println(Thread.currentThread().getName() :点了番茄炒蛋和米饭);CompletableFutureString cf1 CompletableFuture.supplyAsync(() - {System.out.println(Thread.currentThread().getName() :炒番茄鸡蛋);return 炒番茄鸡蛋;}).completeOnTimeOut(咸菜, 1, TimeUnit.SECONDS) // 这里要是任务A1s还未完成则直接返回咸菜.thenCombine(CompletableFuture.supplyAsync(() - {System.out.println(Thread.currentThread().getName() :服务员做饭);return 蒸米饭;}), (dish, rich) - {System.out.println(Thread.currentThread().getName() :菜饭都好了);return String.format(%s %s, dish, rich);}).orTimeout(3, TimeUnit.SECONDS);System.out.println(Thread.currentThread().getName() :王者荣耀);System.out.println(Thread.currentThread().getName() String.format(%s, 开吃 cf1.join()));}五、工具类非Java8 5.1 集合运算 https://www.cxyzjd.com/article/liwgdx80204/91041273 https://blog.csdn.net/qq_46239275/article/details/121849257 判断两个集合是否有交集 ListLong l1 Lists.newArrayList(1L,2L,3L,4L,5L);ListLong l2 Lists.newArrayList(7L,6L,5L);System.out.println(CollectionUtils.retainAll(l1, l2).size());//size为0就是没交集5.2 集合深copy 深copy 5.3 线程安全的list Collections.synchronizedList使用方法 https://www.cnblogs.com/luojiabao/p/11308803.html 5.4 list Array int[] intArray new int[]{1,2,3};ListInteger list Arrays.stream(intArray).boxed().collect(Collectors.toList());ListString list Lists.newArrayList(a, b);String[] array list.toArray(new String[0]); //RIGHT参考 1、https://www.bilibili.com/video/BV1Dv411A7BJ/?spm_id_from333.337.search-card.all.clickvd_sourcedba2a51a761b4fec8564e12aedf67f10 2、https://www.bilibili.com/video/BV1k64y1R7sA?p7vd_sourcedba2a51a761b4fec8564e12aedf67f10
http://www.dnsts.com.cn/news/136105.html

相关文章:

  • 怎么加快登录网站速度彩票网站怎么做
  • 有网站加金币的做弊器吗6河南做网站的公司有哪些
  • 网站网站建设哪家便宜论坛网站开发demo
  • 微网站搭建流程宁波城乡建设局管方网站
  • 怎么自己做网站qq乐辰科技网站建设
  • 网站更新的意义怎样在拼多多上卖自己的产品
  • 可以做h5游戏的网站局域网内用自己电脑做网站
  • 清远做网站哪家好公司部门一般有哪些
  • 求网站制作sql做网站
  • 2015年全球网站优秀设计师做自媒体你不得不知道的视频网站
  • 佛山网站建设的大品牌网络推广培训吧
  • html怎么做游戏seo优化网络推广
  • 网站建设客户需要提供什么wordpress 火车发布
  • 搭建网站知识团购网站切换城市js特效代码
  • 茂名公司制作网站广州网站建设 中网科技
  • h5商城网站开发半透明主题 wordpress
  • 建设网站一般流程天天网站
  • 网站备案重要性新闻株洲最新
  • 驾校视频网站模板wordpress二维码动态图片大小
  • 邯郸个人网站建设做文献综述用什么网站
  • wordpress培训类网站超链接网站怎么做
  • 外贸公司网页设计石嘴山网站seo
  • 网站空间和数据库做招聘信息的网站有哪些方面
  • 网站开发文档包括做购买网站
  • 强的网站建设网站内容规范
  • 网站建设项网站建设改版升级
  • 免费网站如何做推广自己的电脑做网站服务器吗
  • seo北京网站推广广州网站建设开顶柜
  • 全国知名网站杭州有实力的网站开发
  • 长宁区小学网站建设wordpress 网站加密