java集合Stream流的详细介绍及使用
1、什么是Stream流
Java8提供的stream API可以让程序员像操作数据库一样操作集合。Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。同时它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势,使用 fork/join 并行方式来拆分任务和加速处理过程。通常编写并行代码很难而且容易出错, 但使用 Stream API 无需编写一行多线程的代码,就可以很方便地写出高性能的并发程序。
2、Stream流的特性
a、stream不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果。
b、stream不会改变数据源,通常情况下会产生一个新的集合或一个值。
c、stream具有延迟执行特性,只有调用终端操作时,中间操作才会执行。
3、创建流
void test(){//创建流
List<String> list = new ArrayList<>();
//获取一个顺序流 可以理解成异步 把一个内容分成多个数据块,使用同一个线程按顺序处理每个数据块的流。
Stream<String> stream = list.stream(); //获取一个顺序流
//获取一个并行流 可以理解成同步 把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。
Stream<String> parallelStream = list.parallelStream();
}
public
4、基础用法
4.1、遍历(循环)foreach
void test2(){//遍历循环
List<Integer> list = Arrays.asList(1,2,3,4,5);
System.out.println("所有元素:");
list.stream().forEach( o -> { //o表示循环的对象(根据集合类型 集合类型是对象则o是对象 集合类型是某个字符串 o则是字符串)
System.out.println(o);
});
}
public
执行结果:
4.2、过滤(筛选)filter、findFirst
void test3(){//过滤(筛选)filter、findFirst、findAny
//filter 过滤
List<Integer> list = Arrays.asList(1,2,3,4,5);
System.out.println("大于2的元素:");
//遍历集合里大于2的每一个元素
list.stream().filter(x-> x > 2).forEach(System.out::println);
//findFirst 用于获取第一个满足条件的元素
System.out.println("获取第一个小于4的元素:");
Optional<Integer> first = list.stream().filter(x -> x < 4).findFirst();
System.out.println(first.get());
}
public
执行结果:
4.3、映射(map/flatMap)
映射,可以将一个流的元素按照一定的映射规则映射到另一个流中。分为map和flatMap:
a、map:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
b、flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
创建User实体:
package com;
import lombok.Data;
public class User {
private String name;
private Integer age;
public User(String name,Integer age){
this.name = name;
this.age = age;
}
}
实例:
void test4(){//映射(map/flatMap)
List<User> userList = new ArrayList<>();
userList.add(new User("张三",18));
userList.add(new User("李四",28));
userList.add(new User("王五",38));
//筛选出年龄大于18的员工名称 将User user 映射成o
List<String> collect = userList.stream()
//o 表示声明的对象名称 这里 o 相当于 User o = new User() 这里o可以随意命名遵守变量命名规范即可。
.filter(o -> o.getAge() > 18)
.map(User::getName)
.collect(Collectors.toList());
collect.forEach(System.out::println);
List<String> list = Arrays.asList("a-s-d-f", "1-3-5-7");
List<String> listNew = list.stream().flatMap(x -> {
// 将每个元素转换成一个stream
String[] split = x.split("-");
Stream<String> y = Arrays.stream(split);
return y;
}).collect(Collectors.toList());
System.out.println("处理之前的集合:" + list);
System.out.println("处理之后的集合:" + listNew);
}
public
执行结果:
4.4、聚合(max/min/count)
1、count:返回流中元素的总个数
2、max:返回流中元素最大值
3、min:返回流中元素最小值
实例:
void test5(){//聚合(max/min/count)
List<User> userList = new ArrayList<>();
userList.add(new User("张三",18));
userList.add(new User("李四",28));
userList.add(new User("王五",38));
Optional<String> max = userList.stream().max(Comparator.comparing(User::getAge)).map(User::getName);
Optional<String> min = userList.stream().min(Comparator.comparing(User::getAge)).map(User::getName);
long count = userList.stream().filter(user -> user.getAge() > 18).count();
System.out.println("年龄最大的用户:"+max.get());
System.out.println("年龄最小的用户:"+min.get());
System.out.println("年龄大于18的用户数量:"+count);
}
public
执行结果:
4.5、归约(reduce)
归约:把一个流缩减成一个值,能实现对集合求和、求乘积和求最值操作。
实例:
void test6(){//归约(reduce)
List<User> userList = new ArrayList<>();
userList.add(new User("张三",18));
userList.add(new User("李四",28));
userList.add(new User("王五",38));
//求所有人年龄总和
Optional<Integer> min = userList.stream().map(User::getAge).reduce(Integer::min);
Optional<Integer> max = userList.stream().map(User::getAge).reduce(Integer::max);
Optional<Integer> sum = userList.stream().map(User::getAge).reduce(Integer::sum);
System.out.println("年龄最小:"+min.get());
System.out.println("年龄最大:"+max.get());
System.out.println("年龄总和:"+sum.get());
}
public
执行结果:
4.6、收集(collect)
收集:可以说是内容最繁多、功能最丰富的部分了。从字面上去理解,就是把一个流收集起来,最终可以是收集成一个值也可以收集成一个新的集合。
实例:
void test7(){//收集(collect)
List<User> userList = new ArrayList<>();
userList.add(new User("张三",18));
userList.add(new User("李四",28));
userList.add(new User("王五",38));
//获取年龄大于18的List集合
List<User> toList = userList.stream().filter(user -> user.getAge() > 18).collect(Collectors.toList());
//获取年龄大于18的set集合
Set<User> toSet = userList.stream().filter(user -> user.getAge() > 18).collect(Collectors.toSet());
//获取年龄大于18的map集合
Map<Integer, User> toMap = userList.stream().filter(user -> user.getAge() > 18).collect(Collectors.toMap(User::getAge, user -> user));
//获取年龄集合
List<Integer> ageList = userList.stream().map(o -> o.getAge()).collect(Collectors.toList());
//获取姓名集合
List<String> nameList = userList.stream().map(o -> o.getName()).collect(Collectors.toList());
System.out.println("年龄大于18的List集合:"+toList);
System.out.println("获取年龄大于18的set集合:"+toSet);
System.out.println("获取年龄大于18的map集合:"+toMap);
System.out.println("年龄集合:"+ageList);
System.out.println("姓名集合:"+nameList);
}
public
执行结果:
4.7、统计(count/averaging)
Collectors提供了一系列用于数据统计的静态方法:
计数:count
平均值:averagingInt、averagingLong、averagingDouble
最值:maxBy、minBy
求和:summingInt、summingLong、summingDouble
统计以上所有:summarizingInt、summarizingLong、summarizingDouble
实例:
void test8(){//统计(count/averaging)
List<User> userList = new ArrayList<>();
userList.add(new User("张三",18));
userList.add(new User("李四",28));
userList.add(new User("王五",38));
//员工总数
Long count = userList.stream().collect(Collectors.counting());
// 平均年龄
Double average = userList.stream().collect(Collectors.averagingDouble(User::getAge));
// 最高年龄
Optional<Integer> max = userList.stream().map(User::getAge).collect(Collectors.maxBy(Integer::compare));
// 年龄之和
Integer sum = userList.stream().collect(Collectors.summingInt(User::getAge));
// 一次性统计所有信息,包含前面五种
DoubleSummaryStatistics collect = userList.stream().collect(Collectors.summarizingDouble(User::getAge));
System.out.println("员工总数:" + count);
System.out.println("员工平均年龄:" + average);
System.out.println("员工年龄总和:" + sum);
System.out.println("员工年龄所有统计:" + collect);
}
public
执行结果:
4.8、分组(partitioningBy/groupingBy)
实例:
void test9(){//分组
List<User> userList = new ArrayList<>();
userList.add(new User("张三",18));
userList.add(new User("李四",28));
userList.add(new User("王五",38));
//是否大于18分组
Map<Boolean, List<User>> partitioningBy = userList.stream().collect(Collectors.partitioningBy(user -> user.getAge() > 18));
//按照年龄分组
Map<Integer, List<User>> groupingBy = userList.stream().collect(Collectors.groupingBy(User::getAge));
//多条件分组
Map<Integer, Map<String, List<User>>> collect = userList.stream().collect(Collectors.groupingBy(User::getAge, Collectors.groupingBy(User::getName)));
System.out.println("partitioningBy:"+partitioningBy);
System.out.println("groupingBy:"+groupingBy);
System.out.println("collect:"+collect);
}
public
执行结果:
4.9、接合(joining)
joining:可以将stream中的元素用特定的连接符(没有的话,则直接连接)连接成一个字符串。
实例:
void test10(){
List<User> userList = new ArrayList<>();
userList.add(new User("张三",18));
userList.add(new User("李四",28));
userList.add(new User("王五",38));
//将所有人名称用,隔开
String collect = userList.stream().map(User::getName).collect(Collectors.joining(","));
System.out.println(collect);
}
public
执行结果:
4.10、排序(sorted)
实例:
void test11(){
List<User> userList = new ArrayList<>();
userList.add(new User("张三",18));
userList.add(new User("王五",38));
userList.add(new User("李四",28));
//按照年龄排序隔开
String sorted = userList.stream().sorted(Comparator.comparing(User::getAge)).map(User::getName).collect(Collectors.joining(","));
String sorted2 = userList.stream().sorted(Comparator.comparing(User::getAge).reversed()).map(User::getName).collect(Collectors.joining(","));
System.out.println("正序:"+sorted);
System.out.println("倒序:"+sorted2);
}
public
执行结果:
5、代码案例(全)
5.1 实体
package com;
import lombok.Data;
public class User {
private String name;
private Integer age;
public User(String name,Integer age){
this.name = name;
this.age = age;
}
}
5.2 测试类
import com.User;
import org.junit.Test;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Stream流的常见用法
*/
public class StreamDemo {
public void test(){//创建流
List<String> list = new ArrayList<>();
//获取一个顺序流 可以理解成异步 把一个内容分成多个数据块,使用同一个线程按顺序处理每个数据块的流。
Stream<String> stream = list.stream(); //获取一个顺序流
//获取一个并行流 可以理解成同步 把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。
Stream<String> parallelStream = list.parallelStream();
}
public void test2(){//遍历循环
List<Integer> list = Arrays.asList(1,2,3,4,5);
System.out.println("所有元素:");
list.stream().forEach( o -> { //o表示循环的对象(根据集合类型 集合类型是对象则o是对象 集合类型是某个字符串 o则是字符串)
System.out.println(o);
});
}
public void test3(){//过滤(筛选)filter、findFirst
//filter 过滤
List<Integer> list = Arrays.asList(1,2,3,4,5);
System.out.println("大于2的元素:");
//遍历集合里大于2的每一个元素
list.stream().filter(x-> x > 2).forEach(System.out::println);
//findFirst 用于获取第一个满足条件的元素
System.out.println("获取第一个小于4的元素:");
Optional<Integer> first = list.stream().filter(x -> x < 4).findFirst();
System.out.println(first.get());
}
public void test4(){//映射(map/flatMap)
List<User> userList = new ArrayList<>();
userList.add(new User("张三",18));
userList.add(new User("李四",28));
userList.add(new User("王五",38));
//筛选出年龄大于18的员工名称 将User user 映射成o
List<String> collect = userList.stream()
//o 表示声明的对象名称 这里 o 相当于 User o = new User() 这里o可以随意命名遵守变量命名规范即可。
.filter(o -> o.getAge() > 18)
.map(User::getName)
.collect(Collectors.toList());
collect.forEach(System.out::println);
List<String> list = Arrays.asList("a-s-d-f", "1-3-5-7");
List<String> listNew = list.stream().flatMap(x -> {
// 将每个元素转换成一个stream
String[] split = x.split("-");
Stream<String> y = Arrays.stream(split);
return y;
}).collect(Collectors.toList());
System.out.println("处理之前的集合:" + list);
System.out.println("处理之后的集合:" + listNew);
}
public void test5(){//聚合(max/min/count)
List<User> userList = new ArrayList<>();
userList.add(new User("张三",18));
userList.add(new User("李四",28));
userList.add(new User("王五",38));
Optional<String> max = userList.stream().max(Comparator.comparing(User::getAge)).map(User::getName);
Optional<String> min = userList.stream().min(Comparator.comparing(User::getAge)).map(User::getName);
long count = userList.stream().filter(user -> user.getAge() > 18).count();
System.out.println("年龄最大的用户:"+max.get());
System.out.println("年龄最小的用户:"+min.get());
System.out.println("年龄大于18的用户数量:"+count);
}
public void test6(){//归约(reduce)
List<User> userList = new ArrayList<>();
userList.add(new User("张三",18));
userList.add(new User("李四",28));
userList.add(new User("王五",38));
//求所有人年龄总和
Optional<Integer> min = userList.stream().map(User::getAge).reduce(Integer::min);
Optional<Integer> max = userList.stream().map(User::getAge).reduce(Integer::max);
Optional<Integer> sum = userList.stream().map(User::getAge).reduce(Integer::sum);
System.out.println("年龄最小:"+min.get());
System.out.println("年龄最大:"+max.get());
System.out.println("年龄总和:"+sum.get());
}
public void test7(){//收集(collect)
List<User> userList = new ArrayList<>();
userList.add(new User("张三",18));
userList.add(new User("李四",28));
userList.add(new User("王五",38));
//获取年龄大于18的List集合
List<User> toList = userList.stream().filter(user -> user.getAge() > 18).collect(Collectors.toList());
//获取年龄大于18的set集合
Set<User> toSet = userList.stream().filter(user -> user.getAge() > 18).collect(Collectors.toSet());
//获取年龄大于18的map集合
Map<Integer, User> toMap = userList.stream().filter(user -> user.getAge() > 18).collect(Collectors.toMap(User::getAge, user -> user));
//获取年龄集合
List<Integer> ageList = userList.stream().map(o -> o.getAge()).collect(Collectors.toList());
//获取姓名集合
List<String> nameList = userList.stream().map(o -> o.getName()).collect(Collectors.toList());
System.out.println("年龄大于18的List集合:"+toList);
System.out.println("获取年龄大于18的set集合:"+toSet);
System.out.println("获取年龄大于18的map集合:"+toMap);
System.out.println("年龄集合:"+ageList);
System.out.println("姓名集合:"+nameList);
}
public void test8(){//统计(count/averaging)
List<User> userList = new ArrayList<>();
userList.add(new User("张三",18));
userList.add(new User("李四",28));
userList.add(new User("王五",38));
//员工总数
Long count = userList.stream().collect(Collectors.counting());
// 平均年龄
Double average = userList.stream().collect(Collectors.averagingDouble(User::getAge));
// 最高年龄
Optional<Integer> max = userList.stream().map(User::getAge).collect(Collectors.maxBy(Integer::compare));
// 年龄之和
Integer sum = userList.stream().collect(Collectors.summingInt(User::getAge));
// 一次性统计所有信息,包含前面五种
DoubleSummaryStatistics collect = userList.stream().collect(Collectors.summarizingDouble(User::getAge));
System.out.println("员工总数:" + count);
System.out.println("员工平均年龄:" + average);
System.out.println("员工年龄总和:" + sum);
System.out.println("员工年龄所有统计:" + collect);
}
public void test9(){//分组
List<User> userList = new ArrayList<>();
userList.add(new User("张三",18));
userList.add(new User("李四",28));
userList.add(new User("王五",38));
//是否大于18分组
Map<Boolean, List<User>> partitioningBy = userList.stream().collect(Collectors.partitioningBy(user -> user.getAge() > 18));
//按照年龄分组
Map<Integer, List<User>> groupingBy = userList.stream().collect(Collectors.groupingBy(User::getAge));
//多条件分组
Map<Integer, Map<String, List<User>>> collect = userList.stream().collect(Collectors.groupingBy(User::getAge, Collectors.groupingBy(User::getName)));
System.out.println("partitioningBy:"+partitioningBy);
System.out.println("groupingBy:"+groupingBy);
System.out.println("collect:"+collect);
}
public void test10(){
List<User> userList = new ArrayList<>();
userList.add(new User("张三",18));
userList.add(new User("李四",28));
userList.add(new User("王五",38));
//将所有人名称用,隔开
String collect = userList.stream().map(User::getName).collect(Collectors.joining(","));
System.out.println(collect);
}
public void test11(){
List<User> userList = new ArrayList<>();
userList.add(new User("张三",18));
userList.add(new User("王五",38));
userList.add(new User("李四",28));
//按照年龄排序隔开
String sorted = userList.stream().sorted(Comparator.comparing(User::getAge)).map(User::getName).collect(Collectors.joining(","));
String sorted2 = userList.stream().sorted(Comparator.comparing(User::getAge).reversed()).map(User::getName).collect(Collectors.joining(","));
System.out.println("正序:"+sorted);
System.out.println("倒序:"+sorted2);
}
}