在集合转换和遍历的时候,你还在使用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
String[] strArr = new String[]{"aa","bb","cc"};
Stream<String> streamArr = Stream.of(strArr);
Stream<String> streamArr2 = Arrays.stream(strArr);
List集合 转Stream
List<String> list = new ArrayList<>();
Stream<String> streamList = list.stream();
Map集合 转Stream
Stream stream = map.entrySet().stream();
List集合 转并行Stream
Stream<String> streamList2 = list.parallelStream();
/********** Intermediate **********/
filter 过滤操作
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);
// 打印结果:4,5
list.stream().filter(TestObject::isLeader).collect(Collectors.toList());
//Java 8 Map Filter 过滤示例
//Java 8之前:
String result = "";
for (Map.Entry<Integer, String> entry : maps.entrySet()) {
if("something".equals(entry.getValue())){
result = entry.getValue();
}
}
//在Java 8中,您可以转换Map.entrySet()到stream由遵循filter()和collect()它。
//Map -> Stream -> Filter -> String
String result = maps.entrySet().stream()
.filter(map -> "something".equals(map.getValue()))
.map(map->map.getValue())
.collect(Collectors.joining());
//Map -> Stream -> Filter -> MAP
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
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);
// 打印结果 A, B, HELLO
List<Integer> nums = Arrays.asList(1, 2, 3, 4);
List<Integer> squareNums = nums.stream().map(n -> n * n).collect(Collectors.toList());
flatMap 将流展开
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());
//获取 foo
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 提取子流 最大长度限制
streamArr.limit(1);
Stream.of(1, 2, 3,4,5).limit(2).forEach(System.out::println);
// 打印结果 1,2
skip 跳过
streamArr.skip(1);
Stream.of(1, 2, 3,4,5).skip(2).forEach(System.out::println);
// 打印结果 3,4,5
peek 产生相同的流,支持每个元素调用一个函数
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);
// 打印结果: accept:1
// 1
// accept:2
// 2
// accept:3
// 3
// accept:4
// 4
// accept:5
// 5
distinct 去重
Stream.of("aa","bb","aa").distinct();
Stream.of(1,2,3,1,2,3).distinct().forEach(System.out::println);
// 打印结果:1,2,3
// 根据id去重
List<Person> unique = appleList.stream().collect(collectingAndThen(toCollection(() -> new TreeSet<>(comparingLong(Apple::getId))), ArrayList::new));
sorted(),sorted(Comparator) 排序:
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()));
反转排序
Comparator<Human> comparator = (h1, h2) -> h1.getName().compareTo(h2.getName());
humans.sort(comparator.reversed());
多条件排序
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)));
多条件组合排序
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);
// 打印结果 5, 4, 3, 2, 1
parallel 转为并行流,谨慎使用
streamArr.parallel();
/********** Terminal **********/
forEach
streamArr.forEach(System.out::println);
int ids[] = new int[]{1, 2, 3, 4};
Arrays.stream(ids).forEach(System.out::println);
forEachOrdered 如果希望顺序执行并行流,请使用该方法
streamArr.parallel().forEachOrdered(System.out::println);
Stream.of(5,2,1,4,3).forEachOrdered(integer -> { System.out.println("integer:"+integer);});
// 打印结果 integer:5
// integer:2
// integer:1
// integer:4
// integer:3
toArray 收集到数组中
streamArr.filter(str -> str.startsWith("a")).toArray(String[]::new);
min 取最小值
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());
// 打印结果:min:5
reduce 聚合操作
streamArr.reduce((str1,str2) -> str1+str2);
int sum2 = numbers.stream().reduce(0, (a,b) -> a + b);
//reduce 求最大值
Optional<Integer> max = numbers.stream().reduce(Integer::max);
//reduce 求最小值
Optional<Integer> min = numbers.stream().reduce(Integer::min);
max 取最大值
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());
// 打印结果:max:1
count 计算总量
streamArr.count();
long count = Stream.of(1, 2, 3, 4, 5).count();
System.out.println("count:" + count);
// 打印结果:count:5
anyMatch 匹配 判断流中是否含有匹配元素
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);
// 打印结果:anyMatch: true
if(list.stream().anyMatch(u -> u.getName().equals("Ron"))){
System.out.println("Ron已经到了");
}
allMatch 匹配 判断流中是否全部匹配
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);
// 打印结果:allMatch: true
noneMatch 判断流中是否全部不匹配
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);
// 打印结果 noneMatch:true
boolean noneMatch_ = Stream.of(1, 2, 3, 4, 5).noneMatch(integer -> integer < 3);
System.out.println("noneMatch_:" + noneMatch_);
// 打印结果 noneMatch_:false
findFirst 找到第一个就返回
streamArr.filter(str -> str.startsWith("a")).findFirst();
//需要找到第一个isLeader为ture的对象并打印其名字,就可以按照如下的代码操作。
list.stream().filter(u->u.isLeader()).findFirst().ifPresent(u->System.out.println(u.getName()));
findAny 找到任意一个就返回
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:
Stream.concat(Stream.of(1, 2, 3), Stream.of(4, 5)).forEach(integer -> System.out.print(integer + ""));
// 打印结果: 1 2 3 4 5
Stream流复用
Supplier<Stream<String>> streamSupplier = () -> Stream.of("d2", "a2", "b1", "b3", "c").filter(s -> s.startsWith("a"));
streamSupplier.get().anyMatch(s -> true); // ok
streamSupplier.get().noneMatch(s -> true); // ok
文件 Stream
把单词挑出来
List<String> output =reader.lines().
flatMap(line ->Stream.of(line.split(REGEXP))).
filter(word -> word.length() > 0).
collect(Collectors.toList());
异步编排CompletableFuture和Stream结合用法:
单条流水线
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
组合两条流水线
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>,列表中的每个CompletableFuture对象在计算完成后都包含商店的String类型的名称。
// 要得到List,需要等待所有的future执行完毕,将其包含的值抽取出来,填充到列表中才能返回。使用join方法获取CompletableFuture包含的值.
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]
// 书上显示是2000ms左右,这里貌似跟直接并行流差不多.
composed CompletableFuture done in 1006 msecs
多条流水线组合异步+同步+Stream组合
public List<String> findPricesFuture(String product) {
List<CompletableFuture<String>> priceFutures = findPricesStream(product)
.collect(Collectors.<String>>toList());
return priceFutures.stream()
// 等待流中的所有Future执行完毕,并提取各自的返回值
.map(CompletableFuture::join)
.collect(Collectors.toList());
}
public Stream<CompletableFuture<String>> findPricesStream(String product) {
return shops.stream()
// 以异步方式取得每个shop中指定产品的原始价格, 返回值 Stream>
.map(shop -> CompletableFuture.supplyAsync(() -> shop.getPrice(product), executor))
// 不需要异步, 因为只是price+折扣字符串->Quota对象,返回 Stream>
.map(future -> future.thenApply(Quote::parse)) // 取future中的string进行解析.
// 使用另一个异步任务构造期望的Future,申请折扣
.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并传入
Predicate<String> startsWithJ = (n) -> n.startsWith("J");
Predicate<String> fourLetterLong = (n) -> n.length() == 4;
names.stream()
.filter(startsWithJ.and(fourLetterLong))
自定义filter
public static void filter(List names, Predicate condition) {
names.stream().filter((name) -> (condition.test(name))).forEach((name) -> {
System.out.println(name + " ");
});
}
private List<String> afterJava8(List<Dish> dishList) {
return dishList.stream()
.filter(d -> d.getCalories() < 400) //筛选出卡路里小于400的菜肴
.sorted(comparing(Dish::getCalories)) //根据卡路里进行排序
.map(Dish::getName) //提取菜肴名称
.collect(Collectors.toList()); //转换为List
}
//对数据库查询到的菜肴根据菜肴种类进行分类,返回一个Map<Type, List<Dish>>的结果
private static Map<Type, List<Dish>> afterJdk8(List<Dish> dishList) {
return dishList.stream().collect(groupingBy(Dish::getType));
}
文档:
java8-tutorial
http://blog.didispace.com/books/java8-tutorial/ch1.html
30 seconds of java8
https://github.com/biezhi/30-seconds-of-java8#chunk