JDK1.8对集合List的去重,排序,过滤,分组,统计等操作,其实用到的是JDK1.8新特性stream,
首先对stream的操作可以分为两类,中间操作(intermediate operations)和结束操作(terminal operations):
中间操作总是会惰式执行,调用中间操作只会生成一个标记了该操作的新stream。
结束操作会触发实际计算,计算发生时会把所有中间操作积攒的操作以pipeline的方式执行,这样可以减少迭代次数。计算完成之后stream就会失效。
虽然大部分情况下stream是容器调用Collection.stream()方法得到的,但stream和collections有以下不同:
无存储。stream不是一种数据结构,它只是某种数据源的一个视图,数据源可以是一个数组,Java容器或I/O channel等。
为函数式编程而生。对stream的任何修改都不会修改背后的数据源,比如对stream执行过滤操作并不会删除被过滤的元素,而是会产生一个不包含被过滤元素的新stream。
惰式执行。stream上的操作并不会立即执行,只有等到用户真正需要结果的时候才会执行。
可消费性。stream只能被“消费”一次,一旦遍历过就会失效,就像容器的迭代器那样,想要再次遍历必须重新生成。
具体流式思想概述详见:https://blog.csdn.net/zhangjun62/article/details/91874325
具体操作代码实例如下:
package com.zl;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import com.alibaba.fastjson.JSON;
public class Test1 {
public static void main(String[] args) {
List<Student> resList1=new ArrayList<Student>();
Student s1=new Student();
s1.setName("张三");
s1.setAge(1);
s1.setScore(95d);
resList1.add(s1);
Student s2=new Student();
s2.setName("李四1");
s2.setAge(12);
s2.setScore(90d);
resList1.add(s2);
Student s3=new Student();
s3.setName("张三");
s3.setAge(1);
s3.setScore(88d);
resList1.add(s3);
Student s4=new Student();
s4.setName("王二");
s4.setAge(4);
s4.setScore(87d);
resList1.add(s4);
Student s5=new Student();
s5.setName("李四");
s5.setAge(5);
s5.setScore(60d);
resList1.add(s5);
List<Student> resList2=new ArrayList<Student>();
Student s11=new Student();
s11.setName("张三");
s11.setAge(11);
s11.setScore(69d);
resList2.add(s11);
Student s22=new Student();
s22.setName("李四2");
s22.setAge(12);
s22.setScore(75d);
resList2.add(s22);
Student s33=new Student();
s33.setName("张三2");
s33.setAge(33);
s33.setScore(78d);
resList2.add(s33);
Student s44=new Student();
s44.setName("王二2");
s44.setAge(4);
s44.setScore(89d);
resList2.add(s44);
Student s55=new Student();
s55.setName("李四2");
s55.setAge(5);
s55.setScore(82d);
resList2.add(s55);
/*排序,按age升续排列,如果要降续则改成:(a, b) -> b.getAge() - a.getAge(); a和b都是变量名(可以按自己意愿取名字),都是list中的对象的实例*/
List<Student> sortList = resList1.stream().sorted((a, b) -> a.getAge() - b.getAge()).collect(Collectors.toList());
System.out.println("排序后"+JSON.toJSONString(sortList));
//排序后[{"age":1,"name":"张三"},{"age":1,"name":"张三"},{"age":4,"name":"王二"},{"age":5,"name":"李四"},{"age":12,"name":"李四1"}]
/*过滤,按照自己的需求来筛选list中的数据,比如我筛选出姓名是-张三的人,t为实例*/
List<Student> filterList = resList1.stream().filter(t -> t.getName().equals("张三")).collect(Collectors.toList());
System.out.println("过滤后"+JSON.toJSONString(filterList));
//过滤后[{"age":1,"name":"张三"},{"age":1,"name":"张三"}]
/*map, 提取对象中的某一元素,例子中我取的是每个人的name,注意list中类型对应,如果取的是age,就应该是integer类型*/
List<String> mapList = resList1.stream().map(t -> t.getName()).collect(Collectors.toList());
System.out.println("提取后:"+mapList);
//提取后:[张三, 李四1, 张三, 王二, 李四]
/*统计,统计所有人年龄的和,所以用mapToInt,如果是Double类型的,则需要用mapToDouble*/
int sum = resList1.stream().mapToInt(t -> t.getAge()).sum();
System.out.println(sum);//23
/*分组, 按照字段中某个属性将list分组*/
Map<String, List<Student>> map = resList1.stream().collect(Collectors.groupingBy(t -> t.getName()));
System.out.println("按姓名分组"+JSON.toJSONString(map));
//按姓名分组{"李四":[{"age":5,"name":"李四"}],"张三":[{"age":1,"name":"张三"},{"age":1,"name":"张三"}],"李四1":[{"age":12,"name":"李四1"}],"王二":[{"age":4,"name":"王二"}]}
/*多重分组,先按名称分组,再按年龄分组*/
Map<Object, Map<Object, List<Student>>> groupMap = resList1.stream().collect(Collectors.groupingBy(t -> t.getName(), Collectors.groupingBy(t -> ((Student) t).getAge())));
System.out.println("按照姓名再按年龄分组:"+JSON.toJSONString(groupMap));
/*多重分组,一般多重分组后都是为了统计,比如说统计每个姓名,每个年龄的总分数*/
Map<Object, Map<Object, Double>> sumMap = resList1.stream().collect(Collectors.groupingBy(t -> t.getName(), Collectors.groupingBy(t -> t.getAge(), Collectors.summingDouble(t -> t.getScore()))));
System.out.println(sumMap);
/*stream是链式的,这些功能是可以一起使用的,例如:计算每个姓名每个年龄的及格人数*/
Map<Object, Map<Object, Long>> integerMap = resList1.stream().filter(t -> t.getScore() >= 60).collect(Collectors.groupingBy(t -> t.getName(), Collectors.groupingBy(t -> t.getAge(), Collectors.counting())));
System.out.println("取出及格人数:"+integerMap.get("李四").get(5));
//["张三","李四1","王二","李四"]
//2.提取出list对象中的一个属性并去重
List<String> stIdList2=resList1.stream().map(Student::getName).distinct().collect(Collectors.toList());
System.out.println(JSON.toJSON(stIdList2));
//两个集合合并-交集(注:resList1和resList2在前或后顺序不一样,结果也不一样)
List<Student> list = resList1.stream()
.filter(t->resList2.stream()
.anyMatch(t2->t2.getName().equals(t.getName())))
.collect(Collectors.toList());
System.out.println(JSON.toJSON(list));
//[{"score":95.0,"name":"张三","age":1},{"score":88.0,"name":"张三","age":1}]
//集合中某个属性 重复值
List<String> commonList= list.stream().map(Student::getName).collect(Collectors.toList());
System.out.println(JSON.toJSON(commonList));
//["张三","张三"]
List<String> rList= resList1.stream().map(Student::getName).collect(Collectors.toList());
System.out.println(JSON.toJSON(rList));
//["张三","李四1","张三","王二","李四"]
//求差集
List<String> reduce1 = rList.stream().filter(item -> !commonList.contains(item)).collect(Collectors.toList());
System.out.println(JSON.toJSON(reduce1));//["李四1","王二","李四"]
//按姓名统计个数
Map<String, Long> collect = resList1.stream().collect(Collectors.groupingBy(Student::getName,Collectors.counting()));
System.out.println(collect);
//{李四=1, 张三=2, 李四1=1, 王二=1}
//在集合中找出姓名为”张三“的对象
Student student = resList1.stream().filter(o -> "张三".equals(o.getName())).findAny().orElse(null);
System.out.println(JSON.toJSON(student));
//{"score":95.0,"name":"张三","age":1}
}
}
public class Student {
private String name ;
private Integer age;
private Double score;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Double getScore() {
return score;
}
public void setScore(Double score) {
this.score = score;
}
}