JAVA8-Java8的流式编程-高级篇

本文最后更新于:September 2, 2022 pm

JAVA8 是一个有里程碑的一个版本,提供了很多的新特性。Java 8 是oracle公司于2014年3月发布,可以看成是自Java 5 以来最具革命性的版本。Java 8为Java语言、编译器、类库、开发工具与JVM带来了大量新特性。

目录

Comparator

comparing

  • 提取对象属性,按照指定规则排序。

  • comparing是比较器功能接口的静态方法。

  • Comparator.comparing接受一个函数,该函数从给定类型中提取一个可比较的排序键,并返回一个通过该排序键进行比较的比较器。

例如:

传递一个函数,它将从一个类型T中提取一个可比较的排序键,并返回一个通过该排序键进行比较的比较器。

1
Comparator<Student> nameComparator = Comparator.comparing(Student::getName);

传递一个函数(Function)和一个比较器(Comparator)。该方法将从一个类型T中提取一个排序键,并返回一个比较器,使用指定的比较器对该排序键进行比较。

1
Comparator<Student> nameComparator = Comparator.comparing(Student::getName, (s1, s2) -> s2.compareTo(s1)); 

对于intlongdouble数据类型的排序键,比较器分别有comparingIntcomparingLongcomparingDouble方法。

示例

实体类:

1
2
3
4
5
6
class Stu{
String name;
int age;
long weight;
double money;
}

测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
List<Stu> stus = new ArrayList<>();
Stu s1 = new Stu("bbbbb",12,24,23.24);
Stu s2 = new Stu("ddddd",1,124,133.124);
Stu s3 = new Stu("aaaaa",13,34,13.14);
Stu s4 = new Stu("ccccc",17,23,113.114);
Stu s5 = new Stu("eeeee",123,341,135.134);
stus.add(s1);
stus.add(s2);
stus.add(s3);
stus.add(s4);
stus.add(s5);

Collections.sort(stus,Comparator.comparing(Stu::getName)); // 默认升序
for(Stu it : stus){
System.out.println(it.getName()+" "+it.getAge()+" "+it.getMoney()+" "+it.getWeight());
}

在上面使用Collections.sort对集合进行排序。也可以使用Stream.sortedList.sortArrays.sort来使用比较器对集合进行排序。

其他用法示例

1
2
3
Collections.sort(stus,Comparator.comparingInt(Stu::getAge)); // 对int类型的age进行升序排序
Collections.sort(stus,Comparator.comparingLong(Stu::getWeight)); // 对long类型的weight
Collections.sort(stus,Comparator.comparingDouble(Stu::getMoney)); // 对double类型的money

降序(含多属性比较)

实现方式多,这里就不做演示了,或者直接看总结。

实现降序有很多种方法,如下:(推荐先见下面的总结再看以下内容)

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表示某集合:List<类> list;

//返回 对象集合以类属性一升序排序
list.stream().sorted(Comparator.comparing(类::属性一));

//返回 对象集合以类属性一降序排序 注意两种写法
// 先以属性一升序,再将升序结果按照属性一进行降序处理;
list.stream().sorted(Comparator.comparing(类::属性一).reversed());
// 以属性一降序(没有了升序的处理步骤,直接进行降序处理)
list.stream().sorted(Comparator.comparing(类::属性一,Comparator.reverseOrder()));

//返回 对象集合以类属性一升序 属性二升序
list.stream().sorted(Comparator.comparing(类::属性一).thenComparing(类::属性二));

//返回 对象集合以类属性一降序 属性二升序 注意两种写法
// 先以属性一升序,再将升序结果按照属性一进行降序处理;再进行属性二升序
list.stream().sorted(Comparator.comparing(类::属性一).reversed().thenComparing(类::属性二));
// 先以属性一降序(没有了升序的处理步骤,直接进行降序处理);再进行属性二升序
list.stream().sorted(Comparator.comparing(类::属性一,Comparator.reverseOrder()).thenComparing(类::属性二));

//返回 对象集合以类属性一降序 属性二降序 注意两种写法
// 先以属性一升序,再将升序结果按照属性一进行降序处理;再进行属性二降序
list.stream().sorted(Comparator.comparing(类::属性一).reversed().thenComparing(类::属性二,Comparator.reverseOrder()));
// 先以属性一降序(没有了升序的处理步骤,直接进行降序处理);再进行属性二降序
list.stream().sorted(Comparator.comparing(类::属性一,Comparator.reverseOrder()).thenComparing(类::属性二,Comparator.reverseOrder()));

//返回 对象集合以类属性一升序 属性二降序 注意两种写法
// 先以属性一升序,再将升序结果按照属性一进行降序处理;再进行属性二升序,结果进行属性一降序属性二降序
list.stream().sorted(Comparator.comparing(类::属性一).reversed().thenComparing(类::属性二).reversed());
// 先以属性一升序,再进行属性二降序
list.stream().sorted(Comparator.comparing(类::属性一).thenComparing(类::属性二,Comparator.reverseOrder()));
总结
  • Comparator.comparing(类::属性一).reversed():先将属性一按照升序进行排序,再将结果按照属性一进行降序。
  • Comparator.comparing(类::属性一,Comparator.reverseOrder()):直接将属性一进行降序排序。

Collectors

java.util.stream.Collectors 实现了 java.util.stream.Collector 接口,同时又提供了大量的方法对流 ( stream ) 的元素执行 map and reduce 操作,或者统计操作。

Collectors的方法如下:

方法名 描述
toList 将流中的元素放置到一个列表集合中。这个列表默认为ArrayList。
toSet 将流中的元素放置到一个无序集set中。默认为HashSet。
toCollection 将流中的元素全部放置到一个集合中,这里使用Collection,泛指多种集合。
toMap 根据给定的键生成器和值生成器生成的键和值保存到一个map中返回,键和值的生成都依赖于元素,可以指定出现重复键时的处理方案和保存结果的map。
toConcurrentMap 与toMap基本一致,只是它最后使用的map是并发Map:ConcurrentHashMap
joining 将流中的元素全部以字符序列的方式连接到一起,可以指定连接符,甚至是结果的前后缀。内部拼接使用的Java8的新类StringJoiner,可定义连接符和前缀后缀。
mapping 先对流中的每个元素进行映射,即类型转换,然后再将新元素以给定的Collector进行归纳。类似Stream.toMap。
collectingAndThen 在归纳动作结束之后,对归纳的结果进行再处理。
counting 元素计数
minBy 最小值的Optional
maxBy 最大值的Optional
summingInt 求和,结果类型为int
summingLong 求和,结果类型为long
summingDouble 求和,结果类型为double
averagingInt 平均值,结果类型int
averagingLong 平均值,结果类型long
averagingDouble 平均值,结果类型double
summarizingInt 汇总,结果包含元素个数、最大值、最小值、求和值、平均值,值类型都为int
summarizingLong 汇总,结果包含元素个数、最大值、最小值、求和值、平均值,值类型都为long
summarizingDouble 汇总,结果包含元素个数、最大值、最小值、求和值、平均值,值类型都为
reducing 统计,reducing方法有三个重载方法,其实是和Stream里的三个reduce方法对应的,二者是可以替换使用的,作用完全一致,也是对流中的元素做统计归纳作用。求和、平均值、最大值、最小值等其实就属于一种特殊的统计
groupingBy 分组,得到一个HashMap
groupingByConcurrent 分组,得到一个ConcurrentHashMap
partitioningBy 将流中的元素按照给定的校验规则的结果分为两个部分,放到一个map中返回,map的键是Boolean类型,值为元素的列表List

collectingAndThen

Collectors.collectingAndThen()可接受两个参数,第一个参数用于 reduce操作,而第二参数用于 map操作。

即:先把流中的所有元素传递给第一个参数,然后把生成的集合传递给第二个参数来处理。允许我们对生成的集˚合再做一次操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
List<Stu> stus = new ArrayList<>();
Stu s1 = new Stu("bbbbb", 23, 24, 23.24);
Stu s2 = new Stu("ddddd", 11, 124, 133.124);
Stu s3 = new Stu("aaaaa", 43, 34, 13.14);
Stu s4 = new Stu("eeeee", 13, 34, 13.14);
Stu s5 = new Stu("ccccc", 33, 34, 13.14);
stus.add(s1);
stus.add(s2);
stus.add(s3);
stus.add(s4);
stus.add(s5);

ArrayList<Stu> collect = stus.stream().filter(it -> it.getAge() > 20).collect(Collectors.collectingAndThen(Collectors.toList(), ArrayList::new));
collect.forEach(System.out::println);

输出:

1
2
3
Stu{name='bbbbb', age=23, weight=24, money=23.24}
Stu{name='aaaaa', age=43, weight=34, money=13.14}
Stu{name='ccccc', age=33, weight=34, money=13.14}