在集合转换和遍历的时候,你还在使用 for 循环吗? for 循环缺点: 1.复杂转换 转换时赋值极易出现错误和 bug 2.遍历时,要写很多冗余代码。
综上所述: 1.是时候使用 java8 Lambda 表达式,Stream,Collect, Collectors 了 2.流式编程,函数编程是 java 未来的趋势,最新的 Spring5 WebFlux 异步(响应式)流编程
java8 Lambda Stream collect Collectors 常用详细实例https://blog.csdn.net/fzy629442466/article/details/84629422 java 集合遍历https://blog.csdn.net/fzy629442466/article/details/84622757
Stream 的使用分为两种类型: Intermediate,一个 Stream 可以调用 0 到多个 Intermediate 类型操作,每次调用会对 Stream 做一定的处理,返回一个新的 Stream,这类操作都是惰性化的(lazy),就是说,并没有真正开始流的遍历。 常用操作:map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel
Terminal,一个 Stream 只能执行一次 terminal 操作,而且只能是最后一个操作,执行 terminal 操作之后,Stream 就被消费掉了,并且产生一个结果。 常用操作:forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny
实例: 任何集合都可以转换为 Stream: 数组 转 Stream
1 2 3 String[] strArr = new String[]{"aa" ,"bb" ,"cc" }; Stream<String> streamArr = Stream.of(strArr); Stream<String> streamArr2 = Arrays.stream(strArr);
List 集合 转 Stream
1 2 List<String> list = new ArrayList<>(); Stream<String> streamList = list.stream();
Map 集合 转 Stream
1 Stream stream = map.entrySet().stream();
List 集合 转并行 Stream
1 Stream<String> streamList2 = list.parallelStream();
/****** Intermediate ****** / filter 过滤操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 streamArr.filter(str -> str.startsWith("a" )); list.stream().filter(student -> student.getSex().equals("G" )).forEach(student -> System.out.println(student.toString())); List nums = Arrays.asList(1 , 3 , null , 8 , 7 , 8 , 13 , 10 ); nums.stream().filter(num -> num != null ).distinct().forEach(System.out::println); Stream.of(1 , 2 , 3 , 4 , 5 ).filter(item -> item > 3 ).forEach(System.out::println); list.stream().filter(TestObject::isLeader).collect(Collectors.toList()); String result = "" ; for (Map.Entry<Integer, String> entry : maps.entrySet()) { if ("something" .equals(entry.getValue())){ result = entry.getValue(); } } String result = maps.entrySet().stream() .filter(map -> "something" .equals(map.getValue())) .map(map->map.getValue()) .collect(Collectors.joining()); Map<Integer, String> collect = maps.entrySet().stream() .filter(map -> map.getKey() == 2 ) .collect(Collectors.toMap(p -> p.getKey(), p -> p.getValue()));
map 遍历和转换操作 还有提供:mapToDouble,mapToInt,mapToLong
1 2 3 4 5 6 7 8 9 10 11 streamArr.map(String::toLowerCase); list.stream().map(TestObject::getName).collect(Collectors.toList()).forEach(System.out::println); list.stream().map(TestObject::getName).map(String::length).collect(Collectors.toList()).forEach(System.out::println); Stream.of("a" , "b" , "hello" ).map(item-> item.toUpperCase()).forEach(System.out::println); List<Integer> nums = Arrays.asList(1 , 2 , 3 , 4 ); List<Integer> squareNums = nums.stream().map(n -> n * n).collect(Collectors.toList());
flatMap 将流展开
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 List<String> list1 = new ArrayList<>(); list1.add("aa" ); list1.add("bb" ); List<String> list2 = new ArrayList<>(); list2.add("cc" ); list2.add("dd" ); Stream.of(list1,list2).flatMap(str -> str.stream()).collect(Collectors.toList()); Stream<List<Integer>> inputStream = Stream.of( Arrays.asList(1 ), Arrays.asList(2 , 3 ), Arrays.asList(4 , 5 , 6 ) ); Stream<Integer> outputStream = inputStream.flatMap((childList) -> childList.stream()); class Outer { Nested nested; } class Nested { Inner inner; } class Inner { String foo; } Optional.of(new Outer()) .flatMap(o -> Optional.ofNullable(o.nested)) .flatMap(n -> Optional.ofNullable(n.inner)) .flatMap(i -> Optional.ofNullable(i.foo)) .ifPresent(System.out::println);
limit 提取子流 最大长度限制
1 2 3 4 streamArr.limit(1 ); Stream.of(1 , 2 , 3 ,4 ,5 ).limit(2 ).forEach(System.out::println);
skip 跳过
1 2 3 4 streamArr.skip(1 ); Stream.of(1 , 2 , 3 ,4 ,5 ).skip(2 ).forEach(System.out::println);
peek 产生相同的流,支持每个元素调用一个函数
1 2 3 4 5 6 7 8 9 10 11 12 13 streamArr.peek(str -> System.out.println("item:" +str)); Stream.of(1 , 2 , 3 , 4 , 5 ).peek(integer -> System.out.println("accept:" + integer)).forEach(System.out::println);
distinct 去重
1 2 3 4 5 6 Stream.of("aa" ,"bb" ,"aa" ).distinct(); Stream.of(1 ,2 ,3 ,1 ,2 ,3 ).distinct().forEach(System.out::println); List<Person> unique = appleList.stream().collect(collectingAndThen(toCollection(() -> new TreeSet<>(comparingLong(Apple::getId))), ArrayList::new ));
sorted(),sorted(Comparator) 排序:
1 2 3 4 List<Human> humans = Lists.newArrayList(new Human("Sarah" , 10 ), new Human("Jack" , 12 )); Collections.sort(humans, Comparator.comparing(Human::getName)); Assert.assertThat(humans.get(0 ), equalTo(new Human("Jack" , 12 ))); humans.sort((h1, h2) -> h1.getName().compareTo(h2.getName()));
反转排序
1 2 Comparator<Human> comparator = (h1, h2) -> h1.getName().compareTo(h2.getName()); humans.sort(comparator.reversed());
多条件排序
1 2 3 4 5 6 7 8 humans.sort((lhs, rhs) -> { if (lhs.getName().equals(rhs.getName())) { return lhs.getAge() - rhs.getAge(); } else { return lhs.getName().compareTo(rhs.getName()); } }); Assert.assertThat(humans.get(0 ), equalTo(new Human("Sarah" , 10 )));
多条件组合排序
1 2 3 4 5 6 7 8 9 10 humans.sort(Comparator.comparing(Human::getName).thenComparing(Human::getAge)); Assert.assertThat(humans.get(0 ), equalTo(new Human("Sarah" , 10 ))); students.sort((Student s1, Student s2) -> {return Integer.compare(s1.getHeight(), s2.getHeight());}); students.sort((s1, s2) -> Integer.compare(s1.getHeight(), s2.getHeight())); students.sort(Comparator.comparingDouble(Student::getScore)); Stream.of("aaa" ,"bb" ,"c" ).sorted(Comparator.comparing(String::length).reversed()); Stream.of(1 , 2 , 3 , 4 , 5 ).sorted().forEach(System.out::println);
parallel 转为并行流,谨慎使用
/****** Terminal ****** / forEach
1 2 3 4 streamArr.forEach(System.out::println); int ids[] = new int []{1 , 2 , 3 , 4 };Arrays.stream(ids).forEach(System.out::println);
forEachOrdered 如果希望顺序执行并行流,请使用该方法
1 2 3 4 5 6 7 8 streamArr.parallel().forEachOrdered(System.out::println); Stream.of(5 ,2 ,1 ,4 ,3 ).forEachOrdered(integer -> { System.out.println("integer:" +integer);});
toArray 收集到数组中
1 streamArr.filter(str -> str.startsWith("a" )).toArray(String[]::new );
min 取最小值
1 2 3 4 5 6 IntStream.of(1 ,2 ,3 ,4 ).min(); Stream.of(arr).min(String::compareTo); Optional<Integer> min = Stream.of(1 , 2 , 3 , 4 , 5 ).min((o1, o2) -> o1 - o2); System.out.println("min:" + min.get());
reduce 聚合操作
1 2 3 4 5 6 streamArr.reduce((str1,str2) -> str1+str2); int sum2 = numbers.stream().reduce(0 , (a,b) -> a + b);Optional<Integer> max = numbers.stream().reduce(Integer::max); Optional<Integer> min = numbers.stream().reduce(Integer::min);
max 取最大值
1 2 3 4 5 6 IntStream.of(1 ,2 ,3 ,4 ).max(); Stream.of(arr).max(String::compareTo); Optional<Integer> max = Stream.of(1 , 2 , 3 , 4 , 5 ).max((o1, o2) -> o2 - o1); System.out.println("max:" + max.get());
count 计算总量
1 2 3 4 5 streamArr.count(); long count = Stream.of(1 , 2 , 3 , 4 , 5 ).count();System.out.println("count:" + count);
anyMatch 匹配 判断流中是否含有匹配元素
1 2 3 4 5 6 7 8 boolean hasMatch = streamArr.anyMatch(str -> str.startsWith("a" ));boolean anyMatch = Stream.of(1 , 2 , 3 , 4 ).anyMatch(integer -> integer > 3 );System.out.println("anyMatch: " + anyMatch); if (list.stream().anyMatch(u -> u.getName().equals("Ron" ))){ System.out.println("Ron已经到了" ); }
allMatch 匹配 判断流中是否全部匹配
1 2 3 4 5 boolean hasMatch = streamArr.allMatch(str -> str.startsWith("a" ));boolean allMatch = Stream.of(1 , 2 , 3 , 4 ).allMatch(integer -> integer > 0 );System.out.println("allMatch: " + allMatch);
noneMatch 判断流中是否全部不匹配
1 2 3 4 5 6 7 8 9 boolean hasMatch = streamArr.noneMatch(str -> str.startsWith("a" ));boolean noneMatch = Stream.of(1 , 2 , 3 , 4 , 5 ).noneMatch(integer -> integer > 10 );System.out.println("noneMatch:" + noneMatch); boolean noneMatch_ = Stream.of(1 , 2 , 3 , 4 , 5 ).noneMatch(integer -> integer < 3 );System.out.println("noneMatch_:" + noneMatch_);
findFirst 找到第一个就返回
1 2 3 4 streamArr.filter(str -> str.startsWith("a" )).findFirst(); list.stream().filter(u->u.isLeader()).findFirst().ifPresent(u->System.out.println(u.getName()));
findAny 找到任意一个就返回
1 2 3 streamArr.filter(str -> str.startsWith("a" )).findAny(); list.stream().filter(u -> u.getName().equals("Ron" )).findAny().ifPresent(u -> System.out.println(u.getName()));
Concat 联接两个 Stream:
1 2 Stream.concat(Stream.of(1 , 2 , 3 ), Stream.of(4 , 5 )).forEach(integer -> System.out.print(integer + "" ));
Stream 流复用
1 2 3 4 Supplier<Stream<String>> streamSupplier = () -> Stream.of("d2" , "a2" , "b1" , "b3" , "c" ).filter(s -> s.startsWith("a" )); streamSupplier.get().anyMatch(s -> true ); streamSupplier.get().noneMatch(s -> true );
文件 Stream 把单词挑出来
1 2 3 4 List<String> output =reader.lines(). flatMap(line ->Stream.of(line.split(REGEXP))). filter(word -> word.length() > 0 ). collect(Collectors.toList());
异步编排 CompletableFuture 和 Stream 结合用法: 单条流水线
1 2 3 4 5 6 7 8 9 10 11 12 public List<String> findPricesFutureOnePipeline (String product) { List<String> result = shops.stream() .map(shop -> CompletableFuture.supplyAsync(() -> shop.getName() + " price is " + shop.getPrice(product), executor)) .map(CompletableFuture::join) .collect(Collectors.toList()); return result; } [BestPrice price is 227.53480147033423 , LetsSaveBig price is 200.89398407500244 , MyFavoriteShop price is 161.14747297059597 , BuyItAll price is 155.9041805933185 ] one pipeline composed CompletableFuture done in 4004 msecs
组合两条流水线
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public List<String> findPricesFuture (String product) { List<CompletableFuture<String>> priceFutures = shops.stream() .map(shop -> CompletableFuture.supplyAsync(() -> shop.getName() + " price is " + shop.getPrice(product), executor)) .collect(Collectors.toList()); List<String> prices = priceFutures.stream() .map(CompletableFuture::join) .collect(Collectors.toList()); return prices; } [BestPrice price is 171.10524235618578 , LetsSaveBig price is 168.59369176671822 , MyFavoriteShop price is 174.79155890558252 , BuyItAll price is 154.82955565763797 ] composed CompletableFuture done in 1006 msecs
多条流水线组合异步+同步+Stream 组合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public List<String> findPricesFuture (String product) { List<CompletableFuture<String>> priceFutures = findPricesStream(product) .collect(Collectors.<CompletableFuture<String>>toList()); return priceFutures.stream() .map(CompletableFuture::join) .collect(Collectors.toList()); } public Stream<CompletableFuture<String>> findPricesStream(String product) { return shops.stream() .map(shop -> CompletableFuture.supplyAsync(() -> shop.getPrice(product), executor)) .map(future -> future.thenApply(Quote::parse)) .map(future -> future.thenCompose(quote -> CompletableFuture.supplyAsync(() -> Discount.applyDiscount(quote), executor))); } [BestPrice price is 204.78 , LetsSaveBig price is 190.85 , MyFavoriteShop price is 128.92 , BuyItAll price is 140.31 , ShopEasy price is 166.1 ] composed CompletableFuture done in 2009 msecs
Predicate 合并 甚至可以用 and()、or()和 xor()逻辑函数来合并 Predicate, 例如要找到所有以 J 开始,长度为四个字母的名字,你可以合并两个 Predicate 并传入
1 2 3 4 Predicate<String> startsWithJ = (n) -> n.startsWith("J" ); Predicate<String> fourLetterLong = (n) -> n.length() == 4 ; names.stream() .filter(startsWithJ.and(fourLetterLong))
自定义 filter
1 2 3 4 5 public static void filter (List names, Predicate condition) { names.stream().filter((name) -> (condition.test(name))).forEach((name) -> { System.out.println(name + " " ); }); }
文档: java8-tutorialhttp://blog.didispace.com/books/java8-tutorial/ch1.html 30 seconds of java8https://github.com/biezhi/30-seconds-of-java8#chunk