目录
3.1.8mapToDouble,mapToInt,mapToLong
3.2.6anyMatch/allMatch/noneMatch
一、概念
Stream主要就是将要处理的元素转换成流,然后通过Stream API对流里面的元素进行操作。比如,把不需要的元素过滤掉,对元素进行分组等。(官方的概念,这里就不介绍了)
Stream中的元素是以optional类型存在的,Optional
类是一个可以为null
的容器对象。如果值存在则isPresent()
方法会返回true
,调用get()
方法会返回该对象。
二、Stream的创建
Stream的创建有很多种,但我在这里不过多介绍,我把常用的介绍给大家。在日常开发中,这种流式操作可给我们带来很多好处,主要是把集合进行流式处理,例如Map,List,数组,Set等(Collection集合的)。最简单的方法就是这些集合直接调用stream()方法。
List<String> list = new ArrayList<>();
list.add("你");
list.add("我");
//流式处理
list.stream()
三、Stream流的操作
流的操作有两种:
中间操作:一个流可以有0或者多个中间操作,对流进行操作后会返回一个新的流,然后交给下一个操作使用。(中间操作都是惰性的,只有执行到最终操作后,才真正执行,如果没有最终操作,只有中间操作,那么等同于不会执行)eg:filter,map,sorted,提取等。
最终操作:每个流都只能有一个最终操作(如果没有最终操作,中间那些操作根本不会执行),这个最终操作执行完成后,就无法再使用那个流了。eg:(遍历)foreach,(匹配)find,match,(规约)reduce,(聚合)max,min,count,(收集)collect等
对于中间操作和最终操作的理解,下图可以很好理解:
3.1中间操作
中间操作的返回值几乎都是Stream<T>。
3.1.1map/flatMap
map操作就是将流中的每一个元素映射为另外的元素,需要参数Function。flatMap用到的很少,后续用到我再整理。
//流中本来是Student类型,现在通过map转为了String类型
List<String> studentNames = student.stream().map(Student::getName)
.collect(Collectors.toList());
//上面代码与下面这段功能一样
List<String> studentNames=new ArrayList<>();
for(Student student:students){
studentNames.add(student.getName());
}
3.1.2filter
这个操作是用来过滤的,把不符合判断条件的过滤掉,通过测试的会留下了并生成一个新的Stream,接受的参数是推断类型的,返回的是布尔值。
List<Student> studentNames = student.stream()
.filter(s -> s.getAge() > 18)
.collect(Collectors.toList());
3.1.3distinct
去重操作,没有参数。直接调用即可
3.1.4sorted
排序操作,默认是从小到大排列。有两个方法,一个是不带参数的,一个是带参数,需要传入一个Comparator<T>。
1.使用不带参数的,那么流中需要比较的元素必须实现Comparable<T>
2.使用带参数的,须传入Comparator<T>,但是Comparator
在Java 8
之后被打上了@FunctionalInterface
,其他方法都提供了default
实现,因此我们可以在sort
中使用Lambda
表达式
3.使用Comparator默认提供的已经实现好的方法引用。例如:comparingInt或者comparing
//带参数
students.stream().sorted((s,o)->Integer.compare(s.getAge(),o.getAge()))
.forEach(System.out::println);;
//使用Comparator提供的方法引用
students.stream().sorted(Comparator.comparingInt(Student::getAge))
.forEach(System.out::println);;
3.1.5peek
遍历,和forEach一样,只不过这个是个中间操作
List<Student> sortedStudents= students.stream().distinct().peek(System.out::println).
collect(Collectors.toList());
3.1.6limit
可以理解为裁剪,接收long类型的参数,通过limit后的元素会剩下min(n,size)个元素,size表示流中元素个数,n表示参数(保留前面元素)
//只留下前6个元素并打印
students.stream().limit(6).forEach(System.out::println);
3.1.7skip
表示跳过多个个元素,只不过这个是保留后半部分的元素。
//跳过前3个元素并打印
students.stream().skip(3).forEach(System.out::println);
3.1.8mapToDouble,mapToInt,mapToLong
将流中的元素通过一个映射转换为double类型的值,并返回一个DoubleStream。这个DoubleStream可以进行一系列针对双精度浮点数的操作,如求和,平均值,最大值,最小值等。
mapToInt和mapToLong使用和mapToDouble类似。
EG:mapToDouble(Integer::doubleValue)
将整数流中的每个整数通过Integer::doubleValue
方法引用转换为双精度浮点数
3.2最终操作
每个流都只会有一个最终操作,只有通过最终操作后,流才算真正被处理,可以理解为最终操作就是把流转换为一个容器。
3.2.1forEach
//遍历打印
students.stream().forEach(System.out::println);
3.2.2toArray
默认toArray()会返回一个object[]==》不传参数的时候
可以返回指定类型的=》传参数了
//传参数的示例
Student[] studentArray = students.stream().skip(3).toArray(Student[]::new);
3.2.3max/min
找出最大或者最小元素,必须传入Comparator
Optional<Double> op = priceList.stream()
.max(Double::compareTo);
Optional<Double> op1 = priceList.stream()
.min(Double::compareTo);
3.2.4count
返回流中元素的数量
long count = students.stream().skip(3).count();
3.2.5reduce
归纳操作,把流中的各个元素结合起来。
带一个参数--》只传入相关表达式,返回的是Opeational
带两个参数--》传入一个起始值和表达式,返回一个确定的值
List<Integer> integers = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
long count = integers.stream().reduce(0,(x,y)->x+y);
3.2.6anyMatch/allMatch/noneMatch
测试是否有任意元素、所有元素、没有元素匹配表达式,返回布尔类型
boolean test = integers.stream().anyMatch(x->x>3);
3.2.7findFirst,findAny
不接受任何参数,返回流中第一个元素和返回流中任意一个元素
int foo = integers.stream().findAny().get();
3.2.8collect(重要!!!)
它可以传入一个参数和传入三个参数,传入一个参数的情况使用率很高,所以我这就先只介绍一个参数的时候,后续可能再补充三个参数的。
一个参数的时候,我们直接传入Collectors中的方法引用即可。
例如toList()默认生成的是ArrayList(只是把元素收集起来了,并不会改变原来的类型,如果想改变原来的类型,需要通过map去改变),toSet()默认生成的是HashSet,toMap,groupingBy()等。
toList
默认生成的是ArrayList
,toSet
默认生成的是HashSet
,如果想要指定其他容器,可以如下操作:
students.stream().collect(Collectors.toCollection(TreeSet::new));
对于groupingBy()的使用:
可以有三个参数:
1.分组按照什么分类
2.分组最后用什么容器保存(可以忽略,默认提供的是HashMap)
3.按照第一个分组后,对应的结果应该如何收集
也可以多字段分组,groupingBy()嵌套groupingBy()即可
Collectors.groupingBy(ProjectStatisticsVO::getProjectClassfication, Collectors.groupingBy(....,....));
Collectors还有一个方法挺好用的:
joining方法用于将流中的字符串元素连接成一个字符串,可以将流中的字符串按照指定的分隔符拼接在一起,也可以添加前缀和后缀。
collect(Collectors.joining())//这个直接将字符串拼在一起,没有分隔符
如:hello world 拼接完后是helloworld
collect(Collectors.joining(", "))
拼接完是hello,world
collect(Collectors.joining(", ", "[", "]"))
拼接完是[hello,world]
3.2.9average
是DoubleStream的一个终端方法(由mapToDouble等操作生成),用于计算DoubleStream中所有元素的平均值。返回一个OptionalDouble类型的值,用于可能包含或者不包含双精度浮点数的情况。(不用传参)
这篇文章总结的不太齐全,等我再用到没用过的就慢慢补充进来,这个stream流很好用,很方便,但是只看这些概念却不行,得多加练习。