Stream流是什么?
/* A sequence of elements supporting sequential and parallel aggregate operations. */
看官方给出的定义:支持顺序和并行聚合的元素序列的操作。所谓的元素序列,可以认为是数组,集合等。流它本身不像集合、数组那样存储数据,它只是一个通道,用于计算的通道。
Stream流的过程?
首先创建Stream,需要一个数据源(如: 集合、数组), 获取到一个流;然后有一个或多个中间操作(例如去重、排序、过滤等);最后终止操作产生结果(循环遍历、求和等);
Stream流的使用?
1.创建 Stream
/**
* 数组:通过Stream.of()
**/
public static void createStreamByArrays(){
Integer[] intArr = {10,9,8,7,6,5,4,3,2,1};
Stream<Integer> stream = Stream.of(intArr);
stream.filter(e->e%2==0).forEach(System.out::println);
}
/**
* 集合:通过集合.stram()方法
**/
public static void createStreamByCollection(){
List<String> stringList = Arrays.asList("跳过","中", "华", "人", "民", "共", "和", "国", "万", "岁");
Stream<String> stream = stringList.stream();
String s = stream.skip(1).collect(Collectors.joining());
System.out.println(s);
}
/**
* Stream.generate(Supplier<T> s),参数为供给型的函数式接口,这里用lambda表达式替换
* 注意这种方式创建的是一个无限流,使用时要加限制
**/
public static void createStreamByGenerate(){
Stream<Integer> stream = Stream.generate(() -> (int) (Math.random() * 100) + 1);
stream.limit(10).forEach(System.out::println);
}
/**
*Stream.iterate(T seed,UnaryOperator<T> f)
*@param <T> 流元素的类型(啥类型都行)
*@param seed 初始值
*@param f 应用于前一个元素以产生新元素的函数式接口
*@return 一种新的序列
*
* 注意这种方式创建的是一个无限流,使用时要加限制
**/
public static void createStreamByIterate(){
Stream<Integer> stream = Stream.iterate(0, x -> x + 10);
stream.limit(5).forEach(System.out::println);
}
public static void main(String[] args) {
createStreamByArrays();
createStreamByCollection();
createStreamByGenerate();
System.out.println("=======================");
createStreamByIterate();
}
2.中间操作
一个流可以有零个或多个中间操作,目的只是打开流,做过滤或映射等操作,并没有真正开始循环遍历,终止操作才是真正的循环遍历。
2.1 filter过滤操作
Stream<T> filter(Predicate<? super T> predicate);说明:filter方法入参为断言型接口(返回boolean类型的值),可以用lamdba表达式作为其具体实现。
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
Student stu1 = new Student("10001","张三", 26);
Student stu2 = new Student("10002","李四", 18);
Student stu3 = new Student("10003","王五", 28);
list.add(stu1);
list.add(stu2);
list.add(stu3);
//实际开发中可以根据某些业务条件过滤集合元素,得到一个新集合
List<Student> collect = list.stream().filter(s -> s.getAge() > 20).collect(Collectors.toList());
collect.forEach(s->System.out.println(s.toString()));
}
输出结果:
张三:26
王五:28
2.2 map 归纳操作
<R> Stream<R> map(Function<? super T, ? extends R> mapper);说明:map接口的入参为一个函数型接口,该类型接口主要作用是跟据一个类型的数据得到另外一个类型的数据。
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
Student stu1 = new Student("10001","张三", 26);
Student stu2 = new Student("10002","李四", 18);
Student stu3 = new Student("10003","王五", 28);
list.add(stu1);
list.add(stu2);
list.add(stu3);
//实际开发中可能会存在只获取业务ID的集合,用于传参in(查询)、返回等操作
List<String> collect = list.stream().map(Student::getStudentId).collect(Collectors.toList());
System.out.println(collect);
}
输出结果:
[10001, 10002, 10003]
2.3 distinct 去重操作
官方解释:Returns a stream consisting of the distinct elements (according to {@link Object#equals(Object)}) of this stream 翻译:根据equals方法返回不同元素组成的流
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
Student stu1 = new Student("10001","张三", 26);
Student stu2 = new Student("10002","李四", 18);
Student stu3 = new Student("10003","王五", 28);
Student stu4 = new Student("10003","王五", 28);
list.add(stu1);
list.add(stu2);
list.add(stu3);
List<String> stringList = Arrays.asList("中","中", "华", "人", "民", "共", "和", "国", "万", "岁");
//可以对字符串集合直接去重
List<String> collect1 = stringList.stream().distinct().collect(Collectors.toList());
System.out.println(collect1);
//如果集合中为对象的话,也可以直接去重
List<Student> collect = list.stream().distinct().collect(Collectors.toList());
collect.forEach(s-> System.out.println(s.toString()));
}
输出结果:
[中, 华, 人, 民, 共, 和, 国, 万, 岁]
张三:26
李四:18
王五:28
2.4 sorted 排序操作
Stream<T> sorted();说明:无参的方法,可以直接对基本数据类型集合进行排序。
Stream<T> sorted(Comparator<? super T> comparator);通过传入一个Comaparator接口进行自定义排序。comparing()方法参数为一个函数型接口--根据一个类型返回新类型的集合。
public static void main(String[] args) {
List<Integer> intList = Arrays.asList(75, 12, 8, 45, 21, 26);
List<Integer> collect = intList.stream().sorted().collect(Collectors.toList());
System.out.println(collect);
//对实体集合进行排序
List<Student> list = new ArrayList<>();
Student stu1 = new Student("10001","张三", 26);
Student stu2 = new Student("10002","李四", 18);
Student stu3 = new Student("10003","王五", 28);
list.add(stu1);
list.add(stu2);
list.add(stu3);
List<Student> collect1 = list.stream().sorted(Comparator.comparing(Student::getAge)).collect(Collectors.toList());
System.out.println(collect1.toString());
}
输出结果:
[8, 12, 21, 26, 45, 75]
[李四:18, 张三:26, 王五:28]
2.5 skip 舍弃操作
Stream<T> skip(long n);舍弃前n个元素。
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
Student stu1 = new Student("10001","张三", 26);
Student stu2 = new Student("10002","李四", 18);
Student stu3 = new Student("10003","王五", 28);
list.add(stu1);
list.add(stu2);
list.add(stu3);
//Stream<T> skip(long n);舍弃前n个元素
List<Student> collect = list.stream().skip(1).collect(Collectors.toList());
System.out.println(collect);
}
输出结果:
[李四:18, 王五:28]
2.6 limit 截取操作
Stream<T> limit(long maxSize);返回由此流的元素组成的流,截断长度不超过{@code maxSize}
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
Student stu1 = new Student("10001","张三", 26);
Student stu2 = new Student("10002","李四", 18);
Student stu3 = new Student("10003","王五", 28);
list.add(stu1);
list.add(stu2);
list.add(stu3);
//Stream<T> limit(long maxSize);返回由此流的元素组成的流,截断长度不超过{@code maxSize}
List<Student> collect = list.stream().limit(2).collect(Collectors.toList());
System.out.println(collect);
}
输出结果:
[张三:26, 李四:18]
2.7 collect 聚合操作
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
Student stu1 = new Student("10001","张三", 26);
Student stu2 = new Student("10002","李四", 18);
Student stu3 = new Student("10003","王五", 28);
list.add(stu1);
list.add(stu2);
list.add(stu3);
//转成list
List<String> collect = list.stream().map(Student::getName).collect(Collectors.toList());
System.out.println(collect);
//转成set,带有去重操作
Set<String> collect1 = list.stream().map(Student::getName).collect(Collectors.toSet());
System.out.println(collect1);
//转成map
Map<String, Integer> collect2 = list.stream().collect(Collectors.toMap(Student::getName, Student::getAge));
System.out.println(collect2);
}
输出结果:
[张三, 李四, 王五]
[李四, 张三, 王五]
{李四=18, 张三=26, 王五=28}
3.终止操作(终端操作)
3.1匹配和计算操作
3.1.1 anyMatch:流中是否有一个元素可以匹配
boolean anyMatch(Predicate<? super T> predicate);入参为一个断言型函数式接口,可以传入自定义判断的lambda表达式。
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
Student stu1 = new Student("10001","张三", 26);
Student stu2 = new Student("10002","李四", 18);
Student stu3 = new Student("10003","王五", 28);
list.add(stu1);
list.add(stu2);
list.add(stu3);
//流中是否有一个元素可以匹配
//实际开发中如果我们只想得到一个boolean类型的结果,而不是filter过滤后的新集合,可以用此方法。
boolean b = list.stream().anyMatch(e -> e.getName().contains("张"));
System.out.println(b);
}
输出结果:
true
3.1.2 allMatch:流中是否每个元素都可以匹配
boolean allMatch(Predicate<? super T> predicate);注意与anyMatch的区别使用
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
Student stu1 = new Student("10001","张三", 26);
Student stu2 = new Student("10002","李四", 18);
Student stu3 = new Student("10003","王五", 28);
list.add(stu1);
list.add(stu2);
list.add(stu3);
//流中是否每元素都可以匹配
boolean b = list.stream().allMatch(e -> e.getName().contains("张"));
System.out.println(b);
}
输出结果:
false
3.1.3 noneMatch:流中是否没有任何元素与之匹配
boolean noneMatch(Predicate<? super T> predicate);
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
Student stu1 = new Student("10001","张三", 26);
Student stu2 = new Student("10002","李四", 18);
Student stu3 = new Student("10003","王五", 28);
list.add(stu1);
list.add(stu2);
list.add(stu3);
//流中没有元素与之匹配
boolean b = list.stream().noneMatch(e -> e.getName().contains("孙"));
System.out.println(b);
}
输出结果:
true
3.1.4 findAny:返回当前流中的任意一个元素
Optional<T> findAny(); Java 8 引入的一个很有趣的特性是 Optional 类,Optional 类主要解决的问题是空指针异常。本质上,这是一个包含有可选值的包装类,这意味着 Optional 类既可以含有对象也可以为空。list集合中每次都是返回第一个元素。。。。。。待验证
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
Student stu1 = new Student("10001","张三", 26);
Student stu2 = new Student("10002","李四", 18);
Student stu3 = new Student("10003","王五", 28);
list.add(stu1);
list.add(stu2);
list.add(stu3);
for (int i = 0; i < 10; i++) {
Optional<Student> student = list.stream().findAny();
System.out.println(student.toString());
}
}
输出结果:
Optional[张三:26]
Optional[张三:26]
Optional[张三:26]
Optional[张三:26]
Optional[张三:26]
Optional[张三:26]
Optional[张三:26]
Optional[张三:26]
Optional[张三:26]
Optional[张三:26]
3.1.5 findFirst:返回当前流中的任意一个元素
Optional<T> findFirst();使用Optional类的get()方法可以获取到T类型对象,可以与3.1.4中返回结果做对比。
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
Student stu1 = new Student("10001","张三", 26);
Student stu2 = new Student("10002","李四", 18);
Student stu3 = new Student("10003","王五", 28);
list.add(stu1);
list.add(stu2);
list.add(stu3);
Optional<Student> first1 = list.stream().findFirst();
//使用Optional类的get方法获取Student对象
System.out.println(first1.get().toString());
}
输出结果:
张三:26
3.1.5 min:获取流中最小的元素;max:获取流中最大的元素;count:获取流中元素的个数
Optional<T> min(Comparator<? super T> comparator);
Optional<T> max(Comparator<? super T> comparator);
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
Student stu1 = new Student("10001","张三", 26);
Student stu2 = new Student("10002","李四", 18);
Student stu3 = new Student("10003","王五", 28);
list.add(stu1);
list.add(stu2);
list.add(stu3);
//min 获取流中最小的元素
Optional<Student> optional = list.stream().min(Comparator.comparing(s -> s.getAge()));
Optional<Student> optional1 = list.stream().min(Comparator.comparing(Student::getAge));
System.out.println("min:"+optional.get());
System.out.println("min1:"+optional1.get());
//max获取流中最大的元素
Optional<Student> optional2 = list.stream().max(Comparator.comparing(Student::getAge));
System.out.println("max:"+optional2.get());
//count返回流中元素的个数
long count = list.stream().count();
System.out.println("count:"+count);
}
输出结果:
min:李四:18
min1:李四:18
max:王五:28
count:3
3.2归约操作
Optional<T> reduce(BinaryOperator<T> accumulator);第一次执行时,accumulator函数的第一个参数为流中的第一个元素,第二个参数为流中元素的第二个元素;第二次执行时,第一个参数为第一次函数执行的结果,第二个参数为流中的第三个元素;依次类推。
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
Student stu1 = new Student("10001","张三", 26);
Student stu2 = new Student("10002","李四", 18);
Student stu3 = new Student("10003","王五", 28);
list.add(stu1);
list.add(stu2);
list.add(stu3);
Optional<Integer> optional = list.stream().map(Student::getAge).reduce((x1, x2) -> x1 + x2);
System.out.println(optional.get());
}
输出结果:
72
3.3收集器操作
3.3.1 Collectors.summingInt:求和
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
Student stu1 = new Student("10001","张三", 26);
Student stu2 = new Student("10002","李四", 18);
Student stu3 = new Student("10003","王五", 28);
list.add(stu1);
list.add(stu2);
list.add(stu3);
//归约操作求和
Optional<Integer> optional = list.stream().map(Student::getAge).reduce((x1, x2) -> x1 + x2);
System.out.println(optional.get());
//汇聚操作求和
Integer integer = list.stream().collect(Collectors.summingInt(Student::getAge));
System.out.println(integer);
}
输出结果:
72
72
3.3.2 Collectors.joining:字符串拼接
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
Student stu1 = new Student("10001","张三", 26);
Student stu2 = new Student("10002","李四", 18);
Student stu3 = new Student("10003","王五", 28);
list.add(stu1);
list.add(stu2);
list.add(stu3);
//Collectors.joining():无参数
String collect = list.stream().map(Student::getName).collect(Collectors.joining());
System.out.println(collect);
//Collectors.joining(CharSequence delimiter):参数delimiter--每个元素之间要使用的分隔符
String collect1 = list.stream().map(Student::getName).collect(Collectors.joining(","));
System.out.println(collect1);
//Collectors.joining(CharSequence delimiter,CharSequence prefix,CharSequence suffix):
// delimiter--每个元素之间要使用的分隔符,
// prefix--要在开头使用的字符序列,
// suffix--结尾要使用的字符序列
String collect2 = list.stream().map(Student::getName).collect(Collectors.joining(",", "'", "'"));
System.out.println(collect2);
}
输出结果:
张三李四王五
张三,李四,王五
'张三,李四,王五'
3.3.3 Collectors.groupingBy:分组
返回结果是以分组元素作为key,分组处理后的集合作为value
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
Student stu1 = new Student("10001","张三", 26,"男");
Student stu2 = new Student("10002","李四", 18,"男");
Student stu3 = new Student("10003","王五", 28,"女");
list.add(stu1);
list.add(stu2);
list.add(stu3);
Map<String, List<Student>> map = list.stream().collect(Collectors.groupingBy(Student::getSex));
map.entrySet().stream().forEach(s->System.out.println(s.toString()));
}
运行结果
女=[Student{studentId='10003', name='王五', age=28, sex='女'}]
男=[Student{studentId='10001', name='张三', age=26, sex='男'}, Student{studentId='10002', name='李四', age=18, sex='男'}]
3.3.3 Collectors.minBy、maxBy、 counting
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
Student stu1 = new Student("10001","张三", 26);
Student stu2 = new Student("10002","李四", 18);
Student stu3 = new Student("10003","王五", 28);
list.add(stu1);
list.add(stu2);
list.add(stu3);
//minBy:找出流中最大值的元素
Optional<Student> collect = list.stream().collect(Collectors.minBy(Comparator.comparing(Student::getAge)));
//maxBy:找出流中最小值的元素
Optional<Student> collect1 = list.stream().collect(Collectors.maxBy(Comparator.comparing(Student::getAge)));
//counting:找出流中元素总个数
Long aLong = list.stream().collect(Collectors.counting());
System.out.println(collect.get().toString());
System.out.println(collect1.get().toString());
System.out.println(aLong);
}
输出结果:
Student{studentId='10002', name='李四', age=18, sex='null'}
Student{studentId='10003', name='王五', age=28, sex='null'}
3
待补充。。。。
参考:
https://www.cnblogs.com/zhangboyu/p/7580262.html
https://blog.csdn.net/weixin_37967166/article/details/89153568