写在前面
Java8中有两大最为重要的改变:
- Lambda表达式
- Stream API(java.util.stream.*)
Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤、映射数据等操作。使用Stream API对集合数据进行操作,就类似于使用SQL执行数据库查询。也可以使用Stream API来并行执行操作。简而言之,Stream API提供了一种高效且易于使用的处理数据的方式。
Stream是什么
流是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
即流这个数据渠道,在数据传输过程中,对数据源做一系列流水线式的中间操作,然后产生一个新的流,这个流不会改变原来的流
集合讲的是数据,流讲的是计算
注意
- Stream 自己不会存储元素。
- Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
- Stream 操作是延迟执行的。这意味着他们会等需要结果的时候才执行。
Stream操作的三个步骤
1. 创建Stream
1.1 通过Collection集合
通过Collection系列集合提供的Stream()串行流或parallelStream()并行流。
其中,Java8中的Collection接口扩展了,提供了两个获取流的方法:
- 返回一个顺序流
/*
* @since 1.8
*/
default Stream stream() {
return StreamSupport.stream(spliterator(), false);
}
- 返回一个并行流
/*
* @since 1.8
*/
default Stream parallelStream() {
return StreamSupport.stream(spliterator(), true);
}
下面我们写个通过Collection系列集合流创建流的例子。
@Test
public void test01(){
//通过Collection系列集合提供的Stream()或parallelStream()
List list = new ArrayList<>();
Stream stream = list.stream();
Stream stringStream = list.parallelStream();
}
1.2 通过数组Arrays
//通过数组Arrays 中的静态方法stream()获取数组
Employee[] employees = new Employee[10];
Stream stream2 = Arrays.stream(employees);
通过Stream流中的of()方法来创建
//通过Stream类中的静态方法of()
Stream stream3 = Stream.of("aa", "bb", "cc", "dd");
1.3 创建无限流
创建无限流的两种方法:迭代、生成
我们先来看一下迭代Stream.iterate()方法的定义
我们再来看一下生成的方式, Stream.generate()这里需要一个供给型的参数
再来写下创建无限流的例子
//创建无限流
//迭代 Stream.iterate()传俩参数,第一个是种子即起始值,第二个参数是Lambda表达式即对起始值进行的操作,
//这里是生成偶数
Stream stream4 = Stream.iterate(0, (x) -> x + 2);
//无限流就是没有限制,需要一个终止操作限制
stream4.limit(4).forEach(System.out::println);
//生成的方式
Stream generate5 = Stream.generate(() -> Math.random());
generate5.limit(5).forEach(System.out::println);
运行结果
0
2
4
6
0.3204608858702849
0.495403965457605
0.9188968488509007
0.18726624455121932
0.3791774193868236
2. 中间操作
一个中间操作链,对数据源的数据进行处理。
多个中间操作可以连接起来形成一个流水线,除非流水线上触发了终止操作,否则中间操作不会执行任何的处理,而在终止操作时一次性处理,称为“惰性求值”或者“延迟加载”。
2.1 筛选与切片
方法 | 描述 |
---|---|
filter(Predicate p) | 接收Lambda,从流中排除某些元素 |
distinct() | 筛选,通过流所生成元素的hashCode()和equal()去除重复元素 |
limit(long maxSize) | 截断流,使其元素不超过给定数量 |
skip(long n) | 跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit(n)互补 |
下面我们一个个来分析:
2.1.1 filter(Predicate p)
接收Lambda,从流中排除某些元素
@Test
public void test02(){
List employees = Arrays.asList(
new Employee("张三",68,9000),
new Employee("李四",38,8000),
new Employee("王五",50,4000),
new Employee("赵六",18,3000),
new Employee("田七",8,1000));
//中间操作,不会执行任何操作
//filter(Predicate p) 接收Lambda,从流中排除某些元素
Stream employeeStream = employees.stream().filter((e) -> {
System.out.println("StreamAPI的中间操作");
return e.getAge() > 35;
});
//终止操作 当只有中间操作时执行是没有结果的,因为只有执行终止操作以后所有的中间操作才一次性全部处理,即惰性求值
employeeStream.forEach(System.out::println);
}
运行结果
StreamAPI的中间操作
Employee{name='张三', age=68, salary=9000.0}
StreamAPI的中间操作
Employee{name='李四', age=38, salary=8000.0}
StreamAPI的中间操作
Employee{name='王五', age=50, salary=4000.0}
StreamAPI的中间操作
StreamAPI的中间操作
从运行结果可以看出,迭代操作不是我们做的,是由Stream API 帮我们完成的,再也不需要我们自己完成这个迭代操作了,这也叫内部迭代。与内部迭代相对应的是外部迭代,也就是我们自己写的迭代。
//外部迭代,我们自己写的迭代
@Test
public void test03(){
Iterator iterator = employees.iterator();
if(iterator.hasNext()){
System.out.println(iterator.next());
}
}
2.1.2 limit(long maxSize)
limit(),下面我们过滤公司中薪资大于5000的雇员之后,获取其中前2个
//limit()过滤公司中薪资大于5000的雇员之后,获取其中前2个雇员的信息
@Test
public void test04(){
employees.stream()
.filter((e) -> {
System.out.println("===短路===");
return e.getSalary()>5000;
})
.limit(2)
.forEach(System.out::println);
}
运行结果
从运行结果我们看出,迭代操作只执行了两次,也就是说只要找到满足条件的结果之后,就不再进行迭代了,这个过程就叫“短路”。所以说它也可以提高效率,跟我们之前学的短路&&和||有点类似。
2.1.3 skip(long n)
扔掉也即跳过前几个元素
List employees = Arrays.asList(
new Employee("张三",68,9000),
new Employee("李四",38,8000),
new Employee("王五",50,4000),
new Employee("赵六",18,3000),
new Employee("田七",8,1000));
//skip()过滤公司中薪资大于5000的雇员之后,跳过前2个雇员的信息
@Test
public void test05(){
employees.stream()
.filter((e) -> e.getSalary()>2000)
.skip(2)
.forEach(System.out::println);
}
运行结果,跳过了8000和9000的工资
Employee{name='王五', age=50, salary=4000.0}
Employee{name='赵六', age=18, salary=3000.0}
2.1.4 distinct()
我们首先给employees集合中添加几个重复的元素赵六
@Test
public void test06(){
List employees1 = Arrays.asList(
new Employee("张三",68,9000),
new Employee("李四",38,8000),
new Employee("王五",50,4000),
new Employee("赵六",18,3000),
new Employee("赵六",18,3000),
new Employee("赵六",18,3000),
new Employee("赵六",18,3000),
new Employee("田七",8,1000));
employees1.stream()
.filter((e) -> e.getSalary()>2000)
.distinct()
.forEach(System.out::println);
}
运行结果
我们发现结果并没有去重,因为,他是通过流所生成元素的hashCode()和equals()来去除重复元素的。所以,要想去除重复元素,必须得重写Employee实体类中的hashCode()和equals()这两个方法。
重写后的Employee如下
package com.cqq.java8.lambda;
import java.util.Objects;
/**
* @author caoqianqian
* @Description:
* @date 2021/3/6 9:24
*/
public class Employee {
private String name;
private int age;
private double salary;
public Employee(String name, int age, double salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
public Employee() {
}
public Employee(int age) {
this.age = age;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
", salary=" + salary +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
return age == employee.age &&
Double.compare(employee.salary, salary) == 0 &&
Objects.equals(name, employee.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age, salary);
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
我们再运行一下结果,已经是去重了的。
2.2 映射
方法 | 描述 |
---|---|
map(Function f) | 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素 |
mapToDouble(ToDoubleFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的DoubleStream |
mapToInt(ToIntFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的IntStream |
mapToLong(ToLongFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的LongStream |
flatMap(Function f) | 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把左右流连成一个流 |
2.2.1 map(Function f)
接收Lambda,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
@Test
public void test07(){
//将字母转大写
List list = Arrays.asList("aa","bb","cc");
list.stream()
.map(str -> str.toUpperCase())
.forEach(System.out::println);
//提取员工名字
employees.stream()
.map((e) -> e.getName())
.forEach(System.out::println);
}
运行结果
AA
BB
CC
张三
李四
王五
赵六
田七
2.2.2 flatMap(Function f)
接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连成另一个流。
我们先来写一个方法来解析字符串,并把字符串中的一个一个的字符给单独提取出来,放到集合中。
public static Stream filterCharacter(String str){
List list = new ArrayList<>();
for (Character c:str.toCharArray()) {
list.add(c);
}
return list.stream();
}
再来看这个测试例子
//faltMap
@Test
public void test08(){
//提取list里的一个个字符串的每一个字符
List list = Arrays.asList("aa","bb","cc");
//通过map提取到的是一个stream流里还是stream流
Stream> streamStream = list.stream()
.map(TestStreamAPI::filterCharacter);
//这里得嵌套遍历才可以循环出每个字符串的结果
streamStream.forEach(
s -> s.forEach(System.out::println)
);
//通过flatMap提取到的是一个stream流
Stream streamStream2 = list.stream()
.flatMap(TestStreamAPI::filterCharacter);
//这样就不用了嵌套遍历了
streamStream2.forEach(System.out::println);
}
其实map方法就相当于Collaction的add方法,如果add的是个集合的话就会变成二维数组,而flatMap 的话就相当于Collaction的addAll方法,参数如果是集合的话,只是将2个集合合并,而不是变成二维数组。
2.3 排序
方法 | 描述 |
---|---|
sorted() | 产生一个新流,其中按自然顺序排序 |
sorted(Comparator comp) | 产生一个新流,其中按比较器顺序排序 |
下面我们编写测试例子,首先我们先创建一个员工的集合:
List employees = Arrays.asList(
new Employee("张三",68,9000),
new Employee("李四",38,8000),
new Employee("王五",50,4000),
new Employee("赵六",18,3000),
new Employee("田七",8,1000));
用sort() 自然排序实现一串字符list的自然排序。用sorted(Comparator comp) 比较器排序,实现员工按年龄排序,如果年龄相等按姓名排。
//排序
//sort() 自然排序
//sorted(Comparator comp) 比较器排序
@Test
public void test09(){
//sort() 将字母按自然醒顺序排序
List list = Arrays.asList("bb","aa","cc");
list.stream()
.sorted()
.forEach(System.out::println);
//sorted(Comparator comp) 比较器排序 按年龄排序,如果年龄相等按姓名排
employees.stream()
.sorted((e1,e2) -> {
if(e1.getAge()== e2.getAge()){
return e1.getName().compareTo(e2.getName());
}else {
return Integer.compare(e1.getAge(),e2.getAge());
}
})
.forEach(System.out::println);
}
运行结果
aa
bb
cc
Employee{name='田七', age=8, salary=1000.0}
Employee{name='赵六', age=18, salary=3000.0}
Employee{name='李四', age=38, salary=8000.0}
Employee{name='王五', age=50, salary=4000.0}
Employee{name='张三', age=68, salary=9000.0}
3. 终止操作(终端操作)
一个终止操作,执行中间操作链,并产生结果。
即终止操作会从流的流水线生成结果,其结果可以是任何不是流的值,例如List、Integer、甚至是void。
3.1 查找与匹配
方法 | 描述 |
---|---|
allMatch(Predicate p) | 检查是否匹配所有元素 |
anyMatch(Predicate p) | 检查是否至少匹配一个元素 |
noneMatch(Predicate p) | 检查是否没有匹配所有元素 |
findFirst() | 返回第一个元素 |
findAny() | 返回当前流中的任意元素 |
count() | 返回流中元素的总个数 |
max(Comparator c) | 返回流中最大值 |
min(Comparator c) | 返回流中最小值 |
forEach(Consumer c) | 内部迭代(使用Collection接口需要用户去做迭代,成为外部迭代。相反,Stream API使用内部迭代--它帮你把迭代做好了) |
3.1.1 allMatch(Predicate p)检查是否匹配所有元素
下面写一个例子,检查公司中所有员工是否处于空闲状态。
@Test
public void test10(){
List employees1 = Arrays.asList(
new Employee("张三",68,9000, Employee.Status.FREE),
new Employee("李四",38,8000,Employee.Status.BUSY),
new Employee("王五",50,4000,Employee.Status.VOCATION),
new Employee("赵六",18,3000,Employee.Status.BUSY),
new Employee("田七",8,1000,Employee.Status.FREE));
boolean b = employees1.stream()
.allMatch(e -> e.getStatus().equals(Employee.Status.FREE));
System.out.println("===allMatch===="+b);
}
Employee 的实体类中加个状态和对应添加这个参数的构造方法
package com.cqq.java8.lambda;
import java.util.Objects;
public class Employee {
private String name;
private int age;
private double salary;
private Status status;
public Employee(String name, int age, double salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
public Employee(String name, int age, double salary,Status status) {
this.name = name;
this.age = age;
this.salary = salary;
this.status = status;
}
public Employee() {
}
public Employee(int age) {
this.age = age;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
", salary=" + salary +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
return age == employee.age &&
Double.compare(employee.salary, salary) == 0 &&
Objects.equals(name, employee.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age, salary);
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public enum Status{
FREE,
BUSY,
VOCATION;
}
}
3.1.2 anyMatch(Predicate p)检查是否至少匹配一个元素
//anyMatch
@Test
public void test11(){
boolean c = employees1.stream()
.anyMatch(e -> e.getStatus().equals(Employee.Status.FREE));
System.out.println("===anyMatch===="+c);
}
3.1.3 noneMatch(Predicate p)检查是否没有匹配所有元素
//noneMatch
@Test
public void test12(){
boolean d = employees1.stream()
.noneMatch(e -> e.getStatus().equals(Employee.Status.FREE));
System.out.println("===anyMatch===="+d);
}
3.1.4 findFirst()返回第一个元素
//findFirst
@Test
public void test13(){
Optional first = employees1.stream()
.sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))
.findFirst();
System.out.println(first.get());
}
注意:上面findFirst返回的是一个Optional对象,它将我们的Employee封装了一层,这是为了避免了空指针。而且这个对象为我们提供了orElse方法,也就是当我们拿到的这个对象为空的时候,我们可以传入一个新的对象去代替它。
3.1.5 findAny()返回当前流中任意元素
//findAny
@Test
public void test14(){
Optional first = employees1.stream()
.sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))
.findAny();
System.out.println(first.get());
}
3.1.6 count()返回流中的总个数
//count
@Test
public void test15(){
long count = employees1.stream()
.count();
System.out.println(count);
}
3.1.7 max()返回流中最大的元素
//max
@Test
public void test16(){
//两种方法
Optional max1 = employees1.stream()
.max((e1,e2) -> Integer.compare(e1.getAge(),e2.getAge()));
Optional max2 = employees1.stream()
.max(Comparator.comparingInt(Employee::getAge));
System.out.println(max1);
}
3.1.8 min()返回流中最小的元素
//min
@Test
public void test17(){
//两种方法
Optional max1 = employees1.stream()
.min((e1,e2) -> Integer.compare(e1.getAge(),e2.getAge()));
Optional max2 = employees1.stream()
.min(Comparator.comparingInt(Employee::getAge));
System.out.println(max1);
}
3.1.9 forEach(Consumer c)
这个我们很熟悉了,每个测试例子都循环打印输出
3.2 归约
方法 | 描述 |
---|---|
reduce(T identity,Binaryoperator b) | 可以将流中元素反复结合在一起,得到一个值。返回T |
reduce(Binaryoperator b) | 可以将流中元素反复结合在一起,得到一个值。返回Optional |
3.2.1 reduce(T identity,Binaryoperator b)
//reduce()
@Test
public void test18(){
List list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
//首先,需要传一个起始值,然后,传入的是一个二元运算。
Integer count = list.stream().reduce(0, (x, y) -> x + y);
System.out.println(count);
}
reduce 归约,把流中的元素按照(x, y) -> x + y的形式进行累加操作。首先0是一个起始值,然后从流中取出第一个元素1作为y进行累加即结果为1,再将这个结果1作为x,再从流中取出一个元素2作为y进行累加,结果为3,一次类推,反复结合,最终得到一个新值。
3.2.2 reduce(Binaryoperator b)
//reduce()
@Test
public void test19(){
List list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
//没有起始值,则有可能结果为空,所以返回的值会被封装到Optional中。
Optional reduce = list.stream().reduce((x, y) -> x + y);
//另一种写法
Optional reduce1 = list.stream().reduce(Integer::sum);
System.out.println(reduce);
System.out.println(reduce1);
}
没有起始值,则有可能结果为空,所以返回的值会被封装到Optional中。
备注:map和reduce的连接通常称为map-reduce模式,因Google用它来进行网络搜索而出名。
3.3 收集
方法 | 描述 |
---|---|
collect(Collect c) | 将流转化为其他形式,接收一个Collector接口的实现,用于给Stream中元素做汇总的方法 |
Collector接口中方法的实现,决定了如何对流执行收集操作(如收集到List、Set及Map中),而且Collectors实用类中提供了许多静态方法,可以方便的创建常见的收集器实例。Collectors实用类中常用的静态方法如下表所示:
方法 | 返回类型 | 作用 |
---|---|---|
toList() | List |
把流中的元素收集到List集合中 |
toSet() | Set |
把流中的元素收集到Set集合中 |
toCollection(...) | Collection |
把流中的元素收集到创建好的集合中 |
counting() | Long | 计算流中元素个数 |
averagingDouble(...) | Double | 计算流中元素Double类型的平均值 |
summingDouble(...) | Double | 计算流中元素Double类型的总和 |
maxBy(...) | Optional |
根据比较器选择最大值 |
minBy(...) | Optional |
根据比较器选择最小值 |
groupingBy(...) | Map |
根据某属性的值对流分组,属性为K,结果为V |
partitioningBy(...) | Map |
根据True或false进行分区 |
summarizingBy(...) | DoubleSummaryStatistics | 收集流(流中元素为Double类型)的统计值。如:平均值 |
joining(...) | String | 连接流中每个字符串 |
3.3.1 toList() 将流转换成List
//toList()
@Test
public void test20(){
List list = employees.stream().map(Employee::getAge).collect(Collectors.toList());
list.forEach(System.out::println);
}
3.3.2 toSet() 将流转换成Set
//toSet()
@Test
public void test21(){
Set collect = employees.stream().map(Employee::getAge).collect(Collectors.toSet());
collect.forEach(System.out::println);
}
3.3.3 toCollection() 将流转换成其他类型的集合
将流转换成HashSet
//toCollection()
@Test
public void test22(){
//换成HashSet
HashSet collect = employees.stream().map(Employee::getAge).collect(Collectors.toCollection(HashSet::new));
collect.forEach(System.out::println);
}
3.3.4 counting()计算流中元素个数
//counting()
@Test
public void test23(){
//总数
Long collect = employees.stream().collect(Collectors.counting());
System.out.println(collect);
}
3.3.5 averagingDouble(...)计算流中元素Double类型的平均值
//averagingDouble()
@Test
public void test24(){
//平均值
Double collect1 = employees.stream().collect(Collectors.averagingDouble(Employee::getAge));
System.out.println(collect1);
}
3.3.6 summingDouble(...)计算流中元素Double类型的总和
IntSummaryStatistics里包含{count=, sum=, min=, average=, max=}这几项需要哪个值,通过get获取就行
summarizingInt
//summingDouble()
@Test
public void test25(){
//平均值
DoubleSummaryStatistics collect1 = employees.stream().collect(Collectors.summarizingDouble(Employee::getSalary));
IntSummaryStatistics collect = employees.stream().collect(Collectors.summarizingInt(Employee::getAge));
System.out.println(collect);
System.out.println(collect.getSum());
}
再来看下summarizingInt()
//summarizingInt()
@Test
public void test26(){
//平均值 IntSummaryStatistics里包含{count=5, sum=182, min=8, average=36.400000, max=68}这几项需要哪个获取就行
IntSummaryStatistics collect = employees.stream().collect(Collectors.summarizingInt(Employee::getAge));
System.out.println(collect);
//从IntSummaryStatistics里取sum
System.out.println(collect.getSum());
}
执行结果
IntSummaryStatistics{count=5, sum=182, min=8, average=36.400000, max=68}
182
Collectors.summingLong()同上一样,传输传入Long型即可。
3.3.7 minBy(...)根据比较器选择最小值
//minBy()
@Test
public void test28(){
Optional min = employees.stream().collect(Collectors.minBy((x, y) -> Integer.compare(x.getAge(), y.getAge())));
System.out.println(min.get());
}
3.3.8 maxBy(...)根据比较器选择最小值
//maxBy()
@Test
public void test27(){
Optional max = employees.stream().collect(Collectors.maxBy((x, y) -> Integer.compare(x.getAge(), y.getAge())));
System.out.println(max.get());
//等价于这种形式
Optional max1 = employees.stream().max((x, y) -> Integer.compare(x.getAge(), y.getAge()));
System.out.println(max1.get());
}
3.3.9 groupingBy(...)根据某属性的值对流分组,属性为K,结果为V
分组分为一级分组和多级分组,下面例子分别进行了演示:
一级分组的例子
//groupingBy()一级分组
@Test
public void test29(){
Map> collect = employees.stream()
.collect(Collectors.groupingBy(Employee::getStatus));
System.out.println(collect);
}
运行结果
{
BUSY=[Employee{name='张三', age=68, salary=9000.0}, Employee{name='李四', age=38, salary=8000.0}, Employee{name='赵六', age=18, salary=3000.0}],
VOCATION=[Employee{name='王五', age=50, salary=4000.0}],
FREE=[Employee{name='田七', age=8, salary=1000.0}]
}
多级分组的例子
//多级分组
@Test
public void test30(){
Map>> map = employees.stream()
.collect(Collectors.groupingBy(Employee::getStatus,Collectors.groupingBy(e -> {
if(e.getAge()<35){
return "青年";
}else if(e.getAge()<50){
return "中年";
}else {
return "老年";
}
})));
System.out.println(map);
}
运行结果
{
FREE={青年=[Employee{name='田七', age=8, salary=1000.0}]},
BUSY={青年=[Employee{name='赵六', age=18, salary=3000.0}], 老年=[Employee{name='张三', age=68, salary=9000.0}], 中年=[Employee{name='李四', age=38, salary=8000.0}]},
VOCATION={老年=[Employee{name='王五', age=50, salary=4000.0}]}
}
3.3.10 partitioningBy(...)根据True或false进行分区
//partitioningBy()
@Test
public void test31(){
Map> map = employees.stream()
.collect(Collectors.partitioningBy(e -> e.getSalary() > 5000));
System.out.println(map);
}
运行结果
{
false=[Employee{name='王五', age=50, salary=4000.0}, Employee{name='赵六', age=18, salary=3000.0}, Employee{name='田七', age=8, salary=1000.0}],
true=[Employee{name='张三', age=68, salary=9000.0}, Employee{name='李四', age=38, salary=8000.0}]
}
3.3.12 joining(...)连接流中每个字符串
//joining()
@Test
public void test32(){
String collect = employees.stream().map(Employee::getName)
.collect(Collectors.joining(","));
System.out.println(collect);
}
运行结果
张三,李四,王五,赵六,田七
至此,我们Stream的基本操作差不多就结束了,我们只需要多加练习,熟练使用就能提高效率啦。