ToB企服应用市场:ToB评测及商务社交产业平台

标题: java Stream流练习 [打印本页]

作者: 怀念夏天    时间: 2022-11-1 10:46
标题: java Stream流练习
1.遍历/匹配(foreach/find/match)

Stream也是支持类似集合的遍历和匹配元素的,只是Stream中的元素是以Optional类型存在的。Stream的遍历、匹配非常简单。
  1. List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 7, 8, 9, 0, 100);
  2. // find使用,查找第一个元素
  3. Optional<Integer> first = list.stream().findFirst();
  4. log.info(first.get().toString());
  5. // match使用,判断是否存在某个值
  6. boolean b1 = list.stream().anyMatch(value -> value >= 100);
  7. boolean b2 = list.stream().anyMatch(value -> value > 10);
  8. log.info(String.valueOf(b1));
  9. log.info(String.valueOf(b2));
  10. // foreach使用,遍历输出元素
  11. list.stream().filter(value -> value > 4).forEach(System.out::print);
  12. System.out.println();
  13. list.forEach(System.out::print);
复制代码
2.筛选(filter)

筛选,是按照一定的规则校验流中的元素,将符合条件的元素提取到新的流中的操作。
  1. // 数字筛选
  2. List<Integer> list = Arrays.asList(1, 3, 4, 5, 6, 7, 8, 9, 10, 20);
  3. ArrayList<Integer> arrayList1 = new ArrayList<>();
  4. list.stream().filter(value -> value > 4).forEach(value -> arrayList1.add(value));
  5. log.info(arrayList1.toString());
  6. ArrayList<Integer> arrayList2 = new ArrayList<>();
  7. list.stream().filter(value -> value <= 4).forEach(arrayList2::add);
  8. log.info(arrayList2.toString());
  9. // 对象筛选
  10. List<User> userList1 = Arrays.asList(
  11.         new User(1, "xw", "男"),
  12.         new User(2, "zgx", "男"),
  13.         new User(3, "gg", "男"),
  14.         new User(4, "whb", "男"),
  15.         new User(5, "yda", "男"),
  16.         new User(6, "bhm", "女")
  17. );
  18. List<User> userList2 = new ArrayList<>();
  19. userList1.stream().filter(user -> user.getId() > 2).forEach(userList2::add);
  20. log.info(userList2.toString());
  21. userList1.stream().filter(user ->                                                  user.getName().equals("xw")).forEach(System.out::println);
  22. HashMap<String, Optional<User>> userHashMap = new HashMap<>();
  23. Optional<User> man = userList1.stream().filter(user -> user.getSex().equals("男")).findFirst();
  24.         userHashMap.put("man", man);
  25.         log.info(userHashMap.toString());
复制代码
3.聚合(max/min/count)

max、min、count这些字眼你一定不陌生,没错,在mysql中我们常用它们进行数据统计。Java stream中也引入了这些概念和用法,极大地方便了我们对集合、数组的数据统计工作。
max、min、count
  1. // max & min & count
  2. List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 89, 9, 0, 10, 20, 30);
  3. Optional<Integer> max = list.stream()
  4.         .max(Comparator.comparing(Integer::intValue));
  5. log.info(String.format("最大值是:%d", max.get()));
  6. Optional<Integer> min = list.stream()
  7.         .min(Comparator.comparing(value -> value.intValue()));
  8. log.info(String.format("最小值是:%d", min.get()));
  9. Integer count1 = Math.toIntExact(list.stream().count());
  10. log.info(String.format("list总元素量1为:%d", count1));
  11. Integer count2 = Math.toIntExact(list.stream().filter(value -> value > 5).count());
  12. log.info(String.format("list元素值大于5的个数:%d", count2));
  13. List<User> userList = Arrays.asList(
  14.         new User(1, "xw", "男", 22),
  15.         new User(2, "zgx", "男", 22),
  16.         new User(3, "whb", "男", 23),
  17.         new User(4, "gg", "男", 30),
  18.         new User(5, "yda", "男", 22),
  19.         new User(6, "bhm", "女", 22),
  20.         new User(7, "lwn", "女", 22)
  21. );
  22. Optional<User> ageMax = userList.stream().max(Comparator.comparing(value -> value.getAge()));
  23. log.info(String.format("年龄最大的是:%s", ageMax.get()));
  24. Optional<User> ageMin = userList.stream().filter(user -> user.getSex().equals("男")).min(Comparator.comparing(User::getAge));
  25. log.info(String.format("性别为男且年龄最小的:%s", ageMin.get()));
  26. Integer count3 = Math.toIntExact(userList.stream().filter(user -> user.getAge() > 22).count());
  27. log.info(String.format("年龄大于22的用户数量为:%d", count3));
复制代码
4.映射(map/flatMap)

映射,可以将一个流的元素按照一定的映射规则映射到另一个流中。分为map和flatMap:
map
  1. // map
  2. List<Integer> list1 = Arrays.asList(1, 3, 5, 6, 7, 8, 0, 10, 20, 22, 39);
  3. List<Integer> collect1 = list1.stream().filter(value -> value > 7).collect(Collectors.toList());
  4. log.info(String.format("list1元素值大于7的有: %s", collect1));
  5. List<String> list2 = Arrays.asList("xw", "sjdk", "sf", "jk", "hoksh", "shdfj", "jhgkj");
  6. List<String> collect2 = list2.stream().map(String::toUpperCase).collect(Collectors.toList());
  7. log.info(String.format("list2元素值全转大写,结果:%s", collect2));
  8. List<User> userList1 = Arrays.asList(
  9.         new User(1, "xw", "男", 22),
  10.         new User(2, "zgx", "男", 22),
  11.         new User(3, "whb", "男", 23),
  12.         new User(4, "gg", "男", 30),
  13.         new User(5, "yda", "男", 22),
  14.         new User(6, "bhm", "女", 22),
  15.         new User(7, "lwn", "女", 22),
  16.         new User(8, "ksj", "女", 22)
  17. );
  18. List<User> userList2 = userList1.stream()
  19.         .map(user -> {
  20.             if (user.getSex().equals("女")) {
  21.                 user.setAge(user.getAge() - 2);
  22.             }
  23.             user.setName(user.getName().toUpperCase());
  24.             return user;
  25.         })
  26.         .filter(user -> user.getAge() > 19 && user.getSex().equals("女"))
  27.         .collect(Collectors.toList());
  28. log.info(String.format("修改结果为:%s", userList2));
复制代码
flatMap
  1. // flatMap
  2. List<String> stringList = userList1.stream()
  3.         .flatMap(user -> {
  4.             Stream<String> stream = Arrays.stream(user.toString().split("="));
  5.             return stream;
  6.         })
  7.         .collect(Collectors.toList());
  8. log.info(String.format("flatMap处理前:%s", userList1));
  9. log.info(String.format("flatMap转换结果:%s", stringList));
复制代码
5.归约(reduce)

归约,也称缩减,顾名思义,是把一个流缩减成一个值,能实现对集合求和、求乘积和求最值操作。
  1. // 求和
  2. List<Integer> list1 = Arrays.asList(1, 3, 5, 2, 1, 5, 89, 23, 89, 23, 34);
  3. Integer sum = list1.stream().reduce(0, Integer::sum);
  4. log.info(String.format("list1中各元素之和:%d", sum));
  5. // 求积
  6. List<Integer> list2 = Arrays.asList(1, 2, 4);
  7. Optional<Integer> product = list2.stream().reduce((x, y) -> x * y);
  8. log.info(String.format("list中2各元素之积:%d", product.get()));
  9. // 求最大值1
  10. Optional<Integer> max1 = list1.stream().reduce(Integer::max);
  11. log.info(String.format("list1中的最大值是:%d", max1.get()));
  12. // 求最大/小值2
  13. Optional<Integer> min1 = list1.stream().reduce((x, y) -> x < y ? x : y);
  14. log.info(String.format("list1中的最小值:%d", min1.get()));
复制代码
  1. List<User> userList1 = Arrays.asList(
  2.         new User(1, "xw", "男", 22),
  3.         new User(2, "zgx", "男", 22),
  4.         new User(3, "whb", "男", 23),
  5.         new User(4, "gg", "男", 30),
  6.         new User(5, "yda", "男", 22),
  7.         new User(6, "bhm", "女", 23),
  8.         new User(7, "lsn", "女", 22),
  9.         new User(8, "ksj", "女", 22)
  10. );
  11. Integer maxAge1 = userList1.stream().reduce(0, (maxAge, user) -> maxAge > user.getAge() ? maxAge : user.getAge(), Integer::max);
  12. log.info(String.format("年龄最大是:%d", maxAge1));
  13. Optional<Integer> max2 = userList1.stream().map(User::getAge).reduce(Integer::max);
  14. Optional<Integer> max3 = userList1.stream().map(User::getAge).reduce((x, y) -> x > y ? x : y);
  15. log.info(String.format("年龄最大是:%d", max2.get()));
  16. log.info(String.format("年龄最大是:%d", max3.get()));
  17. Integer stringMaxLength = userList1.stream()
  18.         .filter(user -> user.getAge() > 22 && user.getAge() < 25)
  19.         .flatMap(user -> {
  20.             Stream<String> newStream = Arrays.stream(user.toString().split("="));
  21.             return newStream;
  22.         })
  23.         .collect(Collectors.toList())
  24.         .stream().map(String::toUpperCase)
  25.         .reduce(0, (maxLength, string) -> maxLength > string.length() ? maxLength : string.length(), Integer::max);
  26. log.info(String.format("最大字符串长度为:%s", stringMaxLength));
复制代码
6.收集(collect)

collect,收集,可以说是内容最繁多、功能最丰富的部分了。从字面上去理解,就是把一个流收集起来,最终可以是收集成一个值也可以收集成一个新的集合。
  1. collect主要依赖java.util.stream.Collectors类内置的静态方法。
复制代码
6.1归集(toList/toSet/toMap)

因为流不存储数据,那么在流中的数据完成处理后,需要将流中的数据重新归集到新的集合里。toList、toSet和toMap比较常用,另外还有toCollection、toConcurrentMap等复杂一些的用法。
toList
  1. List<Integer> list1 = Arrays.asList(1, 2, 8, 0, 9, 0, 1, 23, 32, 37, 49, 48);
  2. List<Integer> collect1 = list1.stream().filter(value -> value > 5).collect(Collectors.toList());
  3. log.info(String.format("list1中收集>5的结果为:%s", collect1));
复制代码
toSet
  1. Set<Integer> collect2 = list1.stream().filter(value -> value < 5).collect(Collectors.toSet());
  2. log.info(String.format("list1中收集<5的结果为:%s", collect2));
  3. collect2.forEach(value -> {System.out.print(value + " ");
复制代码
6.3 分组(partitioningBy/groupingBy)

partitioningBy
  1. List<User> userList1 = Arrays.asList(
  2.         new User(1, "xww", "男", 22),
  3.         new User(2, "zgx", "男", 22),
  4.         new User(3, "whb", "男", 23),
  5.         new User(4, "gg", "男", 30),
  6.         new User(5, "yda", "男", 22),
  7.         new User(6, "bhm", "女", 23),
  8.         new User(7, "lsn", "女", 22),
  9.         new User(8, "ksj", "女", 22)
  10. );
  11. Map<String, User> userMap = userList1.stream()
  12.          .filter(user -> user.getSex().equals("女"))
  13.          .collect(Collectors.toMap(User::getName, user -> user));
  14. log.info(String.format("性别为女的用户转map:%s", userMap));
复制代码
groupingBy
  1. List<Integer> list = Arrays.asList(1, 2, 3, 2, 5, 3, 9, 8, 7, 6, 29, 10, 22);
  2. // count
  3. long count = list.stream().filter(value -> value > 10).count();
  4. log.info(String.format("list中元素>10的个数为:%d", count));
  5. // average
  6. Double average = list.stream().filter(value -> value > 1).collect(Collectors.averagingInt(Integer::intValue));
  7. log.info(String.format("list中元素>1的元素平均值为:%.2f", average));
  8. List<User> userList1 = Arrays.asList(
  9.         new User(1, "xww", "女", 22),
  10.         new User(2, "zgx", "男", 22),
  11.         new User(3, "whb", "男", 23),
  12.         new User(4, "gg", "男", 30),
  13.         new User(5, "yda", "男", 22),
  14.         new User(6, "bhm", "女", 23),
  15.         new User(7, "lsn", "女", 22),
  16.         new User(8, "ksj", "女", 22)
  17. );
  18. Double averageAge = userList1.stream()
  19.         .filter(user -> user.getSex().equals("男"))
  20.         .map(User::getAge)
  21.         .collect(Collectors.averagingInt(Integer::intValue));
  22. log.info(String.format("男用户的平均年龄为:%d 岁", averageAge.intValue()));
  23. // mapToInt
  24. int ageSum = userList1.stream()
  25.         .filter(user -> user.getSex().equals("女"))
  26.         .mapToInt(User::getAge)
  27.         .sum();
  28. log.info(String.format("女用户的年龄之和为:%d", ageSum));
  29. // summarizingInt 统计 计数、总和、最小值、平均值、最大值
  30. IntSummaryStatistics recording = userList1.stream()
  31.         .filter(user -> user.getSex().equals("男"))
  32.         .collect(Collectors.summarizingInt(User::getAge));
  33. log.info(String.format("记录所有男用户的年龄各项值,结果为:%s", recording));
复制代码
6.4 接合(joining)

joining可以将stream中的元素用特定的连接符(没有的话,则直接连接)连接成一个字符串。
  1. List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 20, 37, 49, 243, 30);
  2. // partitioningBy
  3. Map<Boolean, List<Integer>> collect1 = list.stream()
  4.         .collect(Collectors.partitioningBy(value -> value > 20));
  5. log.info(String.format("元素值是否大于20进行分组,结果为:%s", collect1));
  6. collect1.forEach((key, value) -> {
  7.     log.info(String.format("元素值是否大于20进行分组,结果为:%s:%s", key, value));
  8. });
复制代码
7.排序(sorted)

sorted,中间操作。有两种排序:
  1. List<User> userList = Arrays.asList(
  2.         new User(1, "xww", "女", 22),
  3.         new User(2, "zgx", "男", 21),
  4.         new User(3, "whb", "男", 23),
  5.         new User(4, "gg", "男", 30),
  6.         new User(5, "yda", "男", 22),
  7.         new User(6, "bhm", "女", 23),
  8.         new User(7, "lsn", "女", 22),
  9.         new User(8, "ksj", "女", 22)
  10. );
  11. // groupingBy
  12. Map<String, List<User>> collect2 = userList.stream()
  13.         .collect(Collectors.groupingBy(User::getSex));
  14. log.info(String.format("根据性别对用户进行分组,结果为:%s", collect2));
  15. collect2.forEach((key, user) -> {
  16.     log.info(String.format("根据性别对用户进行分组,结果为:%s:%s", key, user));
  17. });
复制代码
8.提取/组合

流也可以进行合并、去重、限制、跳过等操作。
1.去重排序
  1. List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 20, 37, 49, 243, 30);
  2. String collect = list.stream()
  3.         .map(Object::toString)
  4.         .collect(Collectors.joining("——"));
  5. log.info(String.format("joining测试结果为:%s", collect));
复制代码
存在重复数据的问题,这里使用stream流的衍生功能,去除一个对象中的部分元素的重复如下:
  1. List<User> userList1 = Arrays.asList(
  2.         new User(1, "xw", "女", 22),
  3.         new User(2, "zgx", "男", 21),
  4.         new User(3, "whb", "男", 23),
  5.         new User(4, "gg", "男", 30),
  6.         new User(5, "yda", "男", 22),
  7.         new User(6, "bhm", "女", 23),
  8.         new User(7, "lsn", "女", 22),
  9.         new User(8, "ksj", "女", 22)
  10. );
  11. // sorted
  12. List<User> userList2 = userList1.stream()
  13.         .sorted(Comparator.comparing(User::getAge))
  14.         .collect(Collectors.toList());
  15. log.info(String.format("按照年龄排序,结果为:%s", userList2));
  16. // 从小到大,正序
  17. List<String> userName1 = userList1.stream()
  18.         .sorted(Comparator.comparing(User::getAge))
  19.         .map(User::getName)
  20.         .collect(Collectors.toList());
  21. log.info(String.format("根据年龄从小到大排序:%s", userName1));
  22. // 从大到小,倒序
  23. List<String> userName2 = userList1.stream()
  24.         .filter(user -> user.getSex().equals("男"))
  25.         .sorted(Comparator.comparing(User::getAge).reversed())
  26.         .map(User::getName)
  27.         .collect(Collectors.toList());
  28. log.info(String.format("男用户根据年龄从大到小排序:%s", userName2));
复制代码
多个字段或者多个条件去重
  1. List<Integer> list = Arrays.asList(1, 2, 4, 4, 10, 9, 6, 8, 6, 2, 3, 7, 5);
  2. List<Integer> collect = list
  3.         .stream()
  4.         .distinct()
  5.         .sorted(Comparator.comparing(Integer::intValue))
  6.         .collect(Collectors.toList());
  7. collect.forEach(x -> System.out.print(x+" ")); // 1 2 3 4 5 6 7 8 9 10
复制代码
以上使用到了collectingAndThen()根据属性进行去重的操作,进行结果集的收集,收集到结果集之后再进行下一步的处理。在这个去重操作中还用到了toCollection、TreeSet两个操作。
  1. List<User> userList = Arrays.asList(
  2.         new User(1, "xw", "女", 21),
  3.         new User(2, "zgx", "男", 21),
  4.         new User(3, "whb", "男", 23),
  5.         new User(4, "gag", "男", 30),
  6.         new User(4, "gbg", "男", 30),
  7.         new User(4, "gcg", "女", 30),
  8.         new User(5, "yda", "男", 22),
  9.         new User(6, "bhm", "女", 23),
  10.         new User(7, "lsn", "女", 22),
  11.         new User(8, "ksj", "女", 22)
  12. );
  13. ArrayList<User> collect1 = userList.stream().collect(Collectors.collectingAndThen(
  14.                         Collectors.toCollection(() -> new TreeSet<>(
  15.                                 Comparator.comparing(
  16.                                         User::getId))), ArrayList::new));
复制代码
看源码中需要传的参数有两个,第一个参数是Collector的子类,所以Collectors类中的大多数方法都能使用,比如:toList(),toSet(),toMap()等,当然也包括collectingAndThen()。第二个参数是一个Function函数,也是去重的关键,用到的ArrayList::new调用到了ArrayList的有参构造。Function函数是R apply(T t),在第一个参数downstream放在第二个参数Function函数的参数里面,将结果设置为t。对于toCollection是一个通用的方法,满足treeSet收集集合,再传入需要根据某个属性进行比较的比较器,就能达到去重的效果。
2.限制长度(limit)
  1. ArrayList<User> collect2 = userList.stream().collect(Collectors.collectingAndThen(
  2.                 Collectors.toCollection(() -> new TreeSet<>(
  3.                         Comparator.comparing(user->user.getName() + ";" + user.getId()))), ArrayList::new)
复制代码
3.跳过(skip)
  1. public static<T,A,R,RR> Collector<T,A,RR> collectingAndThen(Collector<T,A,R> downstream,Function<R,RR> finisher)
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4