1.遍历/匹配(foreach/find/match)
Stream也是支持类似集合的遍历和匹配元素的,只是Stream中的元素是以Optional类型存在的。Stream的遍历、匹配非常简单。- List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 7, 8, 9, 0, 100);
- // find使用,查找第一个元素
- Optional<Integer> first = list.stream().findFirst();
- log.info(first.get().toString());
- // match使用,判断是否存在某个值
- boolean b1 = list.stream().anyMatch(value -> value >= 100);
- boolean b2 = list.stream().anyMatch(value -> value > 10);
- log.info(String.valueOf(b1));
- log.info(String.valueOf(b2));
- // foreach使用,遍历输出元素
- list.stream().filter(value -> value > 4).forEach(System.out::print);
- System.out.println();
- list.forEach(System.out::print);
复制代码 2.筛选(filter)
筛选,是按照一定的规则校验流中的元素,将符合条件的元素提取到新的流中的操作。- // 数字筛选
- List<Integer> list = Arrays.asList(1, 3, 4, 5, 6, 7, 8, 9, 10, 20);
- ArrayList<Integer> arrayList1 = new ArrayList<>();
- list.stream().filter(value -> value > 4).forEach(value -> arrayList1.add(value));
- log.info(arrayList1.toString());
- ArrayList<Integer> arrayList2 = new ArrayList<>();
- list.stream().filter(value -> value <= 4).forEach(arrayList2::add);
- log.info(arrayList2.toString());
- // 对象筛选
- List<User> userList1 = Arrays.asList(
- new User(1, "xw", "男"),
- new User(2, "zgx", "男"),
- new User(3, "gg", "男"),
- new User(4, "whb", "男"),
- new User(5, "yda", "男"),
- new User(6, "bhm", "女")
- );
- List<User> userList2 = new ArrayList<>();
- userList1.stream().filter(user -> user.getId() > 2).forEach(userList2::add);
- log.info(userList2.toString());
- userList1.stream().filter(user -> user.getName().equals("xw")).forEach(System.out::println);
- HashMap<String, Optional<User>> userHashMap = new HashMap<>();
- Optional<User> man = userList1.stream().filter(user -> user.getSex().equals("男")).findFirst();
- userHashMap.put("man", man);
- log.info(userHashMap.toString());
复制代码 3.聚合(max/min/count)
max、min、count这些字眼你一定不陌生,没错,在mysql中我们常用它们进行数据统计。Java stream中也引入了这些概念和用法,极大地方便了我们对集合、数组的数据统计工作。
max、min、count
- // max & min & count
- List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 89, 9, 0, 10, 20, 30);
- Optional<Integer> max = list.stream()
- .max(Comparator.comparing(Integer::intValue));
- log.info(String.format("最大值是:%d", max.get()));
- Optional<Integer> min = list.stream()
- .min(Comparator.comparing(value -> value.intValue()));
- log.info(String.format("最小值是:%d", min.get()));
- Integer count1 = Math.toIntExact(list.stream().count());
- log.info(String.format("list总元素量1为:%d", count1));
- Integer count2 = Math.toIntExact(list.stream().filter(value -> value > 5).count());
- log.info(String.format("list元素值大于5的个数:%d", count2));
- List<User> userList = Arrays.asList(
- new User(1, "xw", "男", 22),
- new User(2, "zgx", "男", 22),
- new User(3, "whb", "男", 23),
- new User(4, "gg", "男", 30),
- new User(5, "yda", "男", 22),
- new User(6, "bhm", "女", 22),
- new User(7, "lwn", "女", 22)
- );
- Optional<User> ageMax = userList.stream().max(Comparator.comparing(value -> value.getAge()));
- log.info(String.format("年龄最大的是:%s", ageMax.get()));
- Optional<User> ageMin = userList.stream().filter(user -> user.getSex().equals("男")).min(Comparator.comparing(User::getAge));
- log.info(String.format("性别为男且年龄最小的:%s", ageMin.get()));
- Integer count3 = Math.toIntExact(userList.stream().filter(user -> user.getAge() > 22).count());
- log.info(String.format("年龄大于22的用户数量为:%d", count3));
复制代码 4.映射(map/flatMap)
映射,可以将一个流的元素按照一定的映射规则映射到另一个流中。分为map和flatMap:
- map:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
- flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
map
- // map
- List<Integer> list1 = Arrays.asList(1, 3, 5, 6, 7, 8, 0, 10, 20, 22, 39);
- List<Integer> collect1 = list1.stream().filter(value -> value > 7).collect(Collectors.toList());
- log.info(String.format("list1元素值大于7的有: %s", collect1));
- List<String> list2 = Arrays.asList("xw", "sjdk", "sf", "jk", "hoksh", "shdfj", "jhgkj");
- List<String> collect2 = list2.stream().map(String::toUpperCase).collect(Collectors.toList());
- log.info(String.format("list2元素值全转大写,结果:%s", collect2));
- List<User> userList1 = Arrays.asList(
- new User(1, "xw", "男", 22),
- new User(2, "zgx", "男", 22),
- new User(3, "whb", "男", 23),
- new User(4, "gg", "男", 30),
- new User(5, "yda", "男", 22),
- new User(6, "bhm", "女", 22),
- new User(7, "lwn", "女", 22),
- new User(8, "ksj", "女", 22)
- );
- List<User> userList2 = userList1.stream()
- .map(user -> {
- if (user.getSex().equals("女")) {
- user.setAge(user.getAge() - 2);
- }
- user.setName(user.getName().toUpperCase());
- return user;
- })
- .filter(user -> user.getAge() > 19 && user.getSex().equals("女"))
- .collect(Collectors.toList());
- log.info(String.format("修改结果为:%s", userList2));
复制代码 flatMap
- // flatMap
- List<String> stringList = userList1.stream()
- .flatMap(user -> {
- Stream<String> stream = Arrays.stream(user.toString().split("="));
- return stream;
- })
- .collect(Collectors.toList());
- log.info(String.format("flatMap处理前:%s", userList1));
- log.info(String.format("flatMap转换结果:%s", stringList));
复制代码 5.归约(reduce)
归约,也称缩减,顾名思义,是把一个流缩减成一个值,能实现对集合求和、求乘积和求最值操作。- // 求和
- List<Integer> list1 = Arrays.asList(1, 3, 5, 2, 1, 5, 89, 23, 89, 23, 34);
- Integer sum = list1.stream().reduce(0, Integer::sum);
- log.info(String.format("list1中各元素之和:%d", sum));
- // 求积
- List<Integer> list2 = Arrays.asList(1, 2, 4);
- Optional<Integer> product = list2.stream().reduce((x, y) -> x * y);
- log.info(String.format("list中2各元素之积:%d", product.get()));
- // 求最大值1
- Optional<Integer> max1 = list1.stream().reduce(Integer::max);
- log.info(String.format("list1中的最大值是:%d", max1.get()));
- // 求最大/小值2
- Optional<Integer> min1 = list1.stream().reduce((x, y) -> x < y ? x : y);
- log.info(String.format("list1中的最小值:%d", min1.get()));
复制代码- List<User> userList1 = Arrays.asList(
- new User(1, "xw", "男", 22),
- new User(2, "zgx", "男", 22),
- new User(3, "whb", "男", 23),
- new User(4, "gg", "男", 30),
- new User(5, "yda", "男", 22),
- new User(6, "bhm", "女", 23),
- new User(7, "lsn", "女", 22),
- new User(8, "ksj", "女", 22)
- );
- Integer maxAge1 = userList1.stream().reduce(0, (maxAge, user) -> maxAge > user.getAge() ? maxAge : user.getAge(), Integer::max);
- log.info(String.format("年龄最大是:%d", maxAge1));
- Optional<Integer> max2 = userList1.stream().map(User::getAge).reduce(Integer::max);
- Optional<Integer> max3 = userList1.stream().map(User::getAge).reduce((x, y) -> x > y ? x : y);
- log.info(String.format("年龄最大是:%d", max2.get()));
- log.info(String.format("年龄最大是:%d", max3.get()));
- Integer stringMaxLength = userList1.stream()
- .filter(user -> user.getAge() > 22 && user.getAge() < 25)
- .flatMap(user -> {
- Stream<String> newStream = Arrays.stream(user.toString().split("="));
- return newStream;
- })
- .collect(Collectors.toList())
- .stream().map(String::toUpperCase)
- .reduce(0, (maxLength, string) -> maxLength > string.length() ? maxLength : string.length(), Integer::max);
- log.info(String.format("最大字符串长度为:%s", stringMaxLength));
复制代码 6.收集(collect)
collect,收集,可以说是内容最繁多、功能最丰富的部分了。从字面上去理解,就是把一个流收集起来,最终可以是收集成一个值也可以收集成一个新的集合。- collect主要依赖java.util.stream.Collectors类内置的静态方法。
复制代码 6.1归集(toList/toSet/toMap)
因为流不存储数据,那么在流中的数据完成处理后,需要将流中的数据重新归集到新的集合里。toList、toSet和toMap比较常用,另外还有toCollection、toConcurrentMap等复杂一些的用法。
toList
- List<Integer> list1 = Arrays.asList(1, 2, 8, 0, 9, 0, 1, 23, 32, 37, 49, 48);
- List<Integer> collect1 = list1.stream().filter(value -> value > 5).collect(Collectors.toList());
- log.info(String.format("list1中收集>5的结果为:%s", collect1));
复制代码 toSet
- Set<Integer> collect2 = list1.stream().filter(value -> value < 5).collect(Collectors.toSet());
- log.info(String.format("list1中收集<5的结果为:%s", collect2));
- collect2.forEach(value -> {System.out.print(value + " ");
复制代码 6.3 分组(partitioningBy/groupingBy)
- 分区:将stream按条件分为两个Map,比如员工按薪资是否高于8000分为两部分。
- 分组:将集合分为多个Map,比如员工按性别分组。有单级分组和多级分组。
partitioningBy
- List<User> userList1 = Arrays.asList(
- new User(1, "xww", "男", 22),
- new User(2, "zgx", "男", 22),
- new User(3, "whb", "男", 23),
- new User(4, "gg", "男", 30),
- new User(5, "yda", "男", 22),
- new User(6, "bhm", "女", 23),
- new User(7, "lsn", "女", 22),
- new User(8, "ksj", "女", 22)
- );
- Map<String, User> userMap = userList1.stream()
- .filter(user -> user.getSex().equals("女"))
- .collect(Collectors.toMap(User::getName, user -> user));
- log.info(String.format("性别为女的用户转map:%s", userMap));
复制代码 groupingBy
- List<Integer> list = Arrays.asList(1, 2, 3, 2, 5, 3, 9, 8, 7, 6, 29, 10, 22);
- // count
- long count = list.stream().filter(value -> value > 10).count();
- log.info(String.format("list中元素>10的个数为:%d", count));
- // average
- Double average = list.stream().filter(value -> value > 1).collect(Collectors.averagingInt(Integer::intValue));
- log.info(String.format("list中元素>1的元素平均值为:%.2f", average));
- List<User> userList1 = Arrays.asList(
- new User(1, "xww", "女", 22),
- new User(2, "zgx", "男", 22),
- new User(3, "whb", "男", 23),
- new User(4, "gg", "男", 30),
- new User(5, "yda", "男", 22),
- new User(6, "bhm", "女", 23),
- new User(7, "lsn", "女", 22),
- new User(8, "ksj", "女", 22)
- );
- Double averageAge = userList1.stream()
- .filter(user -> user.getSex().equals("男"))
- .map(User::getAge)
- .collect(Collectors.averagingInt(Integer::intValue));
- log.info(String.format("男用户的平均年龄为:%d 岁", averageAge.intValue()));
- // mapToInt
- int ageSum = userList1.stream()
- .filter(user -> user.getSex().equals("女"))
- .mapToInt(User::getAge)
- .sum();
- log.info(String.format("女用户的年龄之和为:%d", ageSum));
- // summarizingInt 统计 计数、总和、最小值、平均值、最大值
- IntSummaryStatistics recording = userList1.stream()
- .filter(user -> user.getSex().equals("男"))
- .collect(Collectors.summarizingInt(User::getAge));
- log.info(String.format("记录所有男用户的年龄各项值,结果为:%s", recording));
复制代码 6.4 接合(joining)
joining可以将stream中的元素用特定的连接符(没有的话,则直接连接)连接成一个字符串。- List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 20, 37, 49, 243, 30);
- // partitioningBy
- Map<Boolean, List<Integer>> collect1 = list.stream()
- .collect(Collectors.partitioningBy(value -> value > 20));
- log.info(String.format("元素值是否大于20进行分组,结果为:%s", collect1));
- collect1.forEach((key, value) -> {
- log.info(String.format("元素值是否大于20进行分组,结果为:%s:%s", key, value));
- });
复制代码 7.排序(sorted)
sorted,中间操作。有两种排序:
- sorted():自然排序,流中元素需实现Comparable接口
- sorted(Comparator com):Comparator排序器自定义排序
- List<User> userList = Arrays.asList(
- new User(1, "xww", "女", 22),
- new User(2, "zgx", "男", 21),
- new User(3, "whb", "男", 23),
- new User(4, "gg", "男", 30),
- new User(5, "yda", "男", 22),
- new User(6, "bhm", "女", 23),
- new User(7, "lsn", "女", 22),
- new User(8, "ksj", "女", 22)
- );
- // groupingBy
- Map<String, List<User>> collect2 = userList.stream()
- .collect(Collectors.groupingBy(User::getSex));
- log.info(String.format("根据性别对用户进行分组,结果为:%s", collect2));
- collect2.forEach((key, user) -> {
- log.info(String.format("根据性别对用户进行分组,结果为:%s:%s", key, user));
- });
复制代码 8.提取/组合
流也可以进行合并、去重、限制、跳过等操作。
1.去重排序- List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 20, 37, 49, 243, 30);
- String collect = list.stream()
- .map(Object::toString)
- .collect(Collectors.joining("——"));
- log.info(String.format("joining测试结果为:%s", collect));
复制代码 存在重复数据的问题,这里使用stream流的衍生功能,去除一个对象中的部分元素的重复如下:- List<User> userList1 = Arrays.asList(
- new User(1, "xw", "女", 22),
- new User(2, "zgx", "男", 21),
- new User(3, "whb", "男", 23),
- new User(4, "gg", "男", 30),
- new User(5, "yda", "男", 22),
- new User(6, "bhm", "女", 23),
- new User(7, "lsn", "女", 22),
- new User(8, "ksj", "女", 22)
- );
- // sorted
- List<User> userList2 = userList1.stream()
- .sorted(Comparator.comparing(User::getAge))
- .collect(Collectors.toList());
- log.info(String.format("按照年龄排序,结果为:%s", userList2));
- // 从小到大,正序
- List<String> userName1 = userList1.stream()
- .sorted(Comparator.comparing(User::getAge))
- .map(User::getName)
- .collect(Collectors.toList());
- log.info(String.format("根据年龄从小到大排序:%s", userName1));
- // 从大到小,倒序
- List<String> userName2 = userList1.stream()
- .filter(user -> user.getSex().equals("男"))
- .sorted(Comparator.comparing(User::getAge).reversed())
- .map(User::getName)
- .collect(Collectors.toList());
- log.info(String.format("男用户根据年龄从大到小排序:%s", userName2));
复制代码 多个字段或者多个条件去重- List<Integer> list = Arrays.asList(1, 2, 4, 4, 10, 9, 6, 8, 6, 2, 3, 7, 5);
- List<Integer> collect = list
- .stream()
- .distinct()
- .sorted(Comparator.comparing(Integer::intValue))
- .collect(Collectors.toList());
- collect.forEach(x -> System.out.print(x+" ")); // 1 2 3 4 5 6 7 8 9 10
复制代码以上使用到了collectingAndThen()根据属性进行去重的操作,进行结果集的收集,收集到结果集之后再进行下一步的处理。在这个去重操作中还用到了toCollection、TreeSet两个操作。- List<User> userList = Arrays.asList(
- new User(1, "xw", "女", 21),
- new User(2, "zgx", "男", 21),
- new User(3, "whb", "男", 23),
- new User(4, "gag", "男", 30),
- new User(4, "gbg", "男", 30),
- new User(4, "gcg", "女", 30),
- new User(5, "yda", "男", 22),
- new User(6, "bhm", "女", 23),
- new User(7, "lsn", "女", 22),
- new User(8, "ksj", "女", 22)
- );
- ArrayList<User> collect1 = userList.stream().collect(Collectors.collectingAndThen(
- Collectors.toCollection(() -> new TreeSet<>(
- Comparator.comparing(
- 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)- ArrayList<User> collect2 = userList.stream().collect(Collectors.collectingAndThen(
- Collectors.toCollection(() -> new TreeSet<>(
- Comparator.comparing(user->user.getName() + ";" + user.getId()))), ArrayList::new)
复制代码 3.跳过(skip)- public static<T,A,R,RR> Collector<T,A,RR> collectingAndThen(Collector<T,A,R> downstream,Function<R,RR> finisher)
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |