目录
一.Stream流介绍
1.stream是对集合的增强操作
2.stream的特点
3.流的操作:Stream操作大体上分为两步,中间操作和终止操作编辑
二.创建Stream对象
三.中间操作:生成一个新Stream
1.filter:过滤,筛选出符合条件的数据被留下来
2.distinct:去掉重复值,将不重复的元素生成一个新的Stream
3.map:转换,遍历Stream中每一个元素,对元素操作后,返回结果
4.peek消费操作:如果想对数据进行某些操作,如:读取、编辑修改等。
5.flatMap :处理二维集合(集合中元素是集合),将每一个元素拆分成一个新的流
6.limit:截取集合前max个元素,返回一个不超过给定长度的新Stream对象
7.skip:跳过前n个元素,返回剩下的
8.sorted:排序
四.终端操作:返回的结果,终端操作此流的生命周期结束
1.forEach() 遍历流中每一个元素,会关闭流
2.findFirst(),findAny()
3.allMatch,anyMatch,noneMatch
4.reduce:将整个数据流的值规约为一个值,其中count、min、max底层就是使用reduce,也可用于字符串连接
5.min、max最值操作:需要自定义比较器,返回数据流中最大、最小的值
6.count : 返回Stream中元素的个数
7.toArray数组操作:将数据流的元素转换成数组
8.collect收集操作,将流规约并返回结果
通过将集合转换为一种叫做”流“的元素序列,通过声明方式,对集合中的每个元素进行一系列并行或串行的流水线操作
不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果;
不会改变数据源,通常情况下会产生一个新的集合;
具有延迟执行特性,只有调用终端操作时,中间操作才会执行。
中间操作:中间操作会产生另一个流。因此中间操作可以用来创建执行一系列动作的管道。一个特别需要注意的点是:中间操作不是立即发生的。相反,当在中间操作创建的新流上执行完终端操作后,中间操作指定的操作才会发生。所以中间操作是延迟发生的,中间操作的延迟行为主要是让流API能够更加高效地执行。
终端操作:会消费流,这种操作会产生一个结果的,如果一个流被消费过了,那它就不能被重用的。
//方式1: Arrays.stream方法创建Stream对象
Integer[] arr = { 1, 2, 3, 4, 5, 6 }; //数组对象
Stream stream1=Arrays.stream(arr);
//方式2: Stream.of方法
Stream stream2=Stream.of(1,2,3,4,5);
//方式3:集合
List list=Arrays.asList(1,2,3,4);
//普通流
Stream stream01=list.stream();
//并行流(并行能力,多线程使用)
Stream stream02=list.parallelStream();
@Data
public class Student {
private String name;
private int age;
private Date birthday;
private String address;
private String sex;
private double score;
}
//集合
List list= new ArrayList<>();
实际上是条件返回true则保存数据,返回false则去除数据
//过滤出条件返回值为true的元素,过滤出"姓李且18岁的学生"
List result = list.stream().filter(e -> e.getName().endsWith("李") && e.getAge() == 18).collect(Collectors.toList());
默认对基本数据类型和String类型去重,如果是自定义类型的元素,则如果想实现去重,必须重写 equals()方法与hashCode()方法
List list=Arrays.asList("a","b","c","a");
//只能对集合的整个元素去重
List collect = list.stream().distinct().collect(Collectors.toList());
//获取集合中元素某字段的集合,取学生岁数的集合
List collect = list.stream().map(Student::getAge).collect(Collectors.toList());
4.peek
消费操作:如果想对数据进行某些操作,如:读取、编辑修改等。peek函数是一种特殊的map函数,当函数没有返回值或者参数就是返回值的时候可以使用peek函数,不需要返回值
//修改名字为name+age
List collect = list.stream().peek(e -> e.setName(e.getName() + e.getAge())).collect(Collectors.toList());
List> lists=new ArrayList<>();
List collect2 = lists.stream().flatMap(Collection::stream).collect(Collectors.toList());
//截取集合前3个元素
List limit = list.stream().limit(3).collect(Collectors.toList());
7.skip:
跳过前n个元素,返回剩下的//跳过集合前2个元素
List limit = list.stream().skip(2).collect(Collectors.toList());
//一.list排序
//单字段排序,年纪升序(不做空字段处理,如果字段为空会报错)
List collect1 = list.stream().sorted(Comparator.comparing(Student::getAge)).collect(Collectors.toList());
//多字段升序,先以年纪升序,再成绩升序
List collect2 = list.stream().sorted(Comparator.comparing(Student::getAge).thenComparing(Student::getScore)).collect(Collectors.toList());
//降序有两种写法,1:直接降序排列,2.先以Age升序,结果再进行降序
List collect3 = list.stream().sorted(Comparator.comparing(Student::getAge,Comparator.reverseOrder())).collect(Collectors.toList());
List collect4=list.stream().sorted(Comparator.comparing(Student::getAge).reversed()).collect(Collectors.toList());
//对排序字段空值处理,有空字段的元素放在集合开始/末尾
//nullsFirst(Comparator super T> comparator)参数:此方法接受单个参数比较器,该比较器是用于比较非空值的比较器
List collect5 = list.stream().sorted(Comparator.comparing(Student::getAge, Comparator.nullsFirst(Integer::compareTo))).collect(Collectors.toList());
//排序的另一种写法,在排序中,null元素将排在第一位。非空元素的顺序将由传递给nullsFirst方法的比较器决定。
Collections.sort(list, Comparator.nullsFirst(Comparator.comparing(Student::getName)));
Collections.sort(list, Comparator.nullsFirst(Comparator.comparing(Student::getName).reversed()));
//二.map排序
//以key排序升序,若velue排序相同
Map oldmap=new HashMap<>();
//1.创建新集合排序后放数据,无返回值 2.排序后使用.collect(Collectors.toMap(...))转map后直接返回
Map newmap=new HashMap<>();
oldmap.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEachOrdered(e-> newmap.put(e.getKey(),e.getValue()));
forEach 不能修改自己包含的本地变量值,也不能用 break/return 之类的关键字提前结束循环。
查找操作,查找第一个、任何一个,返回的类型为Optional。常用于查询集中符合条件的元素,如果流是空的,则返回空
大多数情况下,数据量不大的情况下,findAny()也会返回第一个元素,此时效果与findFirst()一致
allMatch 要求Stream中所有元素都满足条件才返回true
anyMatch, 只要有1个元素满足就返回true
noneMatch 要求所有的元素都不满足条件才返回true
//每个学生年纪都为18才返回true
boolean flag = list.stream().allMatch(e -> e.getAge() == 18);
//任意一个学生是18,则返回true
boolean flag = list.stream().anyMatch(e -> e.getAge() == 18);
//学生年纪没有一个是18 ,则返回true
boolean flag = list.stream().noneMatch(e -> e.getAge() == 18);
// 字符串连接,concat = "ABCD"
String concat = Stream.of("A", "B", "C", "D").reduce("", String::concat);
// 集合累加求和,另一写法reduce(0,Integer::sum)
int sum2=Stream.of(1,2,3,4,5).reduce((t,u)->t+u).get();
//输出最大值,另一写法reduce(Integer::max)
int max=Stream.of(1,2,3,4,5).reduce((t,u)-> t>=u? t:u).get();
2> 有2个参数 T reduce(T identity, BinaryOperator accumulator)
多一个泛型T,实际上相对于在计算值的时候多一个初始化的值
int sum3=Stream.of(1,2,3,4,5).reduce(0,(t,u)->t+u);
5.min、max
最值操作:需要自定义比较器,返回数据流中最大、最小的值//查年纪最大的
Optional max = list.stream().max(Comparator.comparing(Student::getAge));
if (max.isPresent()) {
Student student = max.get();
}
7.toArray
数组操作:将数据流的元素转换成数组List list=Arrays.asList("a","b","c","a");
//返回数组
String[] newArr=list.stream().toArray(String[]::new);
Collectors作为参数提供了非常多收集器 ,java.util.stream.Collectors,是从JDK1.8开始新引入的一个类。Collectors实现了各种有用归约的操作,例如类型归类到新集合、根据不同标准汇总元素等
8.1. 将集合中元素按照类型、条件过滤等归类,存放到指定类型的新数组,集合,List、Map、Set、Collection或者ConcurrentMap
Collectors.toList()
Collectors.toMap()
Collectors.toSet()
Collectors.toCollection()
Collectors.toConcurrentMap(
//返回list
List list2=list.stream().collect(Collectors.toList());
//返回Stack
Stack stack=list.stream().collect(Collectors.toCollection(Stack::new));
//转换为map,key=age,velue=Score,key相同时就比较score,大的覆盖
//如果条件为(key1,key2) -> key1表示key相同时以前key为准
//如果不处理key则key不能相同,否则报错
Map collect6 = list.stream().collect(Collectors.toMap(Student::getAge, Student::getScore, (score1, score2) -> score1 > score2 ? score1 : score2));
8.2. groupingBy:按条件分组,分组后,返回的是一个Map集合,其中key作为分组条件,value作为对应分组结果
Collectors.groupingBy(…):普通分组。
Collectors.groupingByConcurrent(…):线程安全的分组。
// groupingBy(按什么字段分组,去Collectors找相关的方法)
//简单分组,按年纪分组
Map> collect1 = list.stream().collect(Collectors.groupingBy(Student::getAge));
//velue转换为set集合
Map> collect2 = list.stream().collect(Collectors.groupingBy(Student::getAge,Collectors.toSet()));
//按性别分组并统计人数
Map map1=list.stream().collect(Collectors.groupingBy(Student::getSex,Collectors.counting()));
//按性别分组,求年纪之和
Map collect = list.stream().collect(Collectors.groupingBy(Student::getSex, Collectors.summingInt(Student::getAge)));
//按性别分组,并统计名字作为值
Map> collect1 = list.stream().collect(Collectors.groupingBy(Student::getSex, Collectors.mapping(Student::getName, Collectors.toList())));
//按照性别分组,将分数进行聚合运算
//IntSummaryStatistics,DoubleSummaryStatistics,LongSummaryStatistics数据统计类,可在分组后对
//聚合数据count,min,max,sum和average
Map map2 =list.stream().collect(Collectors.groupingBy(Student::getSex,Collectors.summarizingDouble(Student::getScore)));
System.out.println("所有男的总学分:" + map2.get('男').getSum());
System.out.println("男生最高学分:" + map2.get('男').getMax());
System.out.println("男生最低学分:" + map2.get('男').getMin());
System.out.println("男生的平均分:" + map2.get('男').getAverage());
System.out.println("男生的个数:" + map2.get('男').getCount());
8.3.分区,是分组的特殊情况,partitioningBy(…)
该方法实质是在做二分组,将符合条件、不符合条件的元素分组到两个key
分别为true
和false
的Map
中,从而我们能够得到符合和不符合的分组新集合。
//人名按照中、英文名进行分区
Map> collect3 = list.stream().collect(Collectors.partitioningBy(e -> e.getName().matches("^[a-zA-Z]*")));
//取英文集合
List students = collect3.get(true);
//取中文集合
List students1 = collect3.get(false);
8.4. 最值
按照某个属性查找出最大或最小值元素,并且基于Comparator接口来对其进行比较,返回一个Optional对象,并结合Optional.isPresent()判断并取得最大或最小值
Collectors.maxBy(…):最大值。
Collectors.minBy(…):最小值。
//查找年纪最大的人
Optional collect4 = list.stream().collect(Collectors.maxBy(Comparator.comparingInt(Student::getAge)));
if (collect4.isPresent()) {//防止空指针
Student student = collect4.get();
}
8.5. 累加、汇总,平均值
用来完成累加计算、数据汇总(总数、总和、最小值、最大值、平均值)操作。Collectors.summingInt/Double/Long(…):按照某个属性求和。
Collectors.summarizingInt/Double/Long(…):按照某个属性的数据进行汇总,得到其总数、总和、最小值、最大值、平均值。
//单个属性求和,年纪求和
Integer collect5 = list.stream().collect(Collectors.summingInt(Student::getAge));
//单属性统计,年纪统计IntSummaryStatistics{count=10, sum=564, min=18, average=20.000000, max=22}
IntSummaryStatistics collect6 = list.stream().collect(Collectors.summarizingInt(Student::getAge));
//单属性均值,平均年龄
Double v = list.stream().collect(Collectors.averagingDouble(Student::getAge));
8.6. 连接
将元素以某种规则连接起来,得到一个连接字符串。
Collectors.joining():字符串直接连接。
Collectors.joining(CharSequence delimiter):按照字符delimiter进行字符串连接。
Collectors.joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix):按照前缀prefix,后缀suffix,并以字符delimiter进行字符串连接。
//名字按照","分割连接: "小红,小明"
String collect7 = list.stream().map(Student::getName).collect(Collectors.joining(","));
8.7.集合对象属性去重
//根据对象单/多属性去重,并转换为list
ArrayList collect7 = list.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Student::getName))), ArrayList::new));
ArrayList collect8 = list.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Student::getName).thenComparing(Student::getAge))), ArrayList::new));