最大原因是平时对一些集合进行操作,既有过滤,又有转换类型,又要收集等等…,曾经可能你的代码会是下面这种.
List<T> data = new ArrayList();
for(T t: data){
//过滤逻辑
}
for(T t: data){
//转换逻辑
}
for(T t: data){
//收集等等
}
从上面的代码中可以看出,如果对集合有复杂操作的话,要for循环非常多次,而流操作只会执行一次。如果说常规只是简单处理,其实流操作跟普通forEach循环差不多。
@Data
public class Student{
//学生名字
private String name;
//学生年龄
private int age;
//学生地址
private String address;
//学生所在班级
private String className;
}
需求: 得到了一个List 对象集合,这时候想提取出里面的所有名字。
普通实现
//得到数据 这里直接先用new
List<Student> studentList = new ArrayList();
//先创建一个容器
List<String> nameList = new ArrayList()
for(Student student:studentList){
nameList.add(student.getName());
}
流实现
//得到数据 这里直接先用new
List<Student> studentList = new ArrayList();
List<String> nameList =studentList.stream().map(x->x.getName()).collect(Collectors.toList());
需求: 得到一个List 对象集合,这时候我想过得到年龄大于18岁的学生。
普通实现
//得到数据 这里直接先用new
List<Student> studentList = new ArrayList();
//先创建一个容器
List<Student> ageStudentList= new ArrayList()
for(Student student:studentList){
//符合18岁
if(student.getAge()>18){
ageStudentList.add(student);
}
}
流实现
List<Student> ageStudentList =studentList.stream().filter(x->x.getAge()>18).collect(Collectors.toList());
1
和2
进行合并需求:得到一个List 对象集合,我想找到年龄大于18岁的学生,然后需要他们的名字集合
普通实现
//得到数据 这里直接先用new
List<Student> studentList = new ArrayList();
//先创建一个容器
List<Student> ageStudentList= new ArrayList()
for(Student student:studentList){
//符合18岁
if(student.getAge()>18){
ageStudentList.add(student);
}
}
List<String> nameStudentList = new ArrayList()
for(Student student: ageStudentList){
nameStudentList.add(student.getName());
}
流实现
List<String> ageStudentList =studentList.stream().filter(x->x.getAge()>18).map(x->x.getName()).collect(Collectors.toList());
从这里是不是就可以看出流比较简洁,而且重申一遍,流只会一次forEach循环,数据量如果大的时候,就知道好处了!后续我就不再使用普通实现了,直接写流操作,大家以后写久了就习惯了,就那几种常用的写写,不常用的实在不行就百度。
这也是一个非常常见的一种场景,尤其是从数据库中得到数据的时候需要进行分组一下。
需求: 根据学生班级将学生进行分组
流实现
//得到数据 这里直接先用new
/*
[
{name:'张三',age:18,address:'北京',className:'1年级'},
{name:'李四',age:15,address:'北京',className:'1年级'},
{name:'王五',age:20,address:'北京',className:'2年级'},
]
*/
List<Student> studentList = new ArrayList();
//根据班级进行分组
Map<String, List<Student>> collect = studentList.stream().collect(Collectors.groupingBy(x->x.getClassName()));
//Map> collect = studentList.stream().collect(Collectors.groupingBy(Student::getClassName));
//最后这个Map的结果会是这样,我简单描绘一下,这个key就是年级,也就是你按什么分的组
{
'1年级':[{name:'张三',age:18,address:'北京',className:'1年级'},{name:'李四',age:15,address:'北京',className:'1年级'}],
'2年级':[{name:'王五',age:20,address:'北京',className:'2年级'}]
}
这个也非常常见,什么叫做List->Map,我先说一个业务场景,如果符合你就使用下面这个方式去解决。
/*
[
{name:'张三',age:18,address:'北京',className:'1年级'},
{name:'李四',age:15,address:'北京',className:'2年级'},
{name:'王五',age:20,address:'北京',className:'3年级'},
]
*/
说有一天领导跟你说,得到了上面这样的一个数据,他想变成一种映射关系,什么样的映射关系呢。<名字,学生对象> 这样的一个Map,便于后续的代码可以直接通过Map.getKey(名字)来获取指定的学生对象。注意:这里的前提是我们思维里已经知道这一堆数据那个要映射的key是唯一的
,其实你4
的场景熟练了这个也能解决,因为4
的方案中可以得到<名字,List<学生对象>>,最后你getKey之后再get(0)就可以了。
流实现
studentList.stream().collect(Collectors.toMap(x->x.getName(),o->o));
现在具体说一下这个toMap
args1: 最终你要变成Map的key,你最后要拿到Map<名字,学生对象>,你的告诉人家你拿对象里面的什么属性做key吧
args2: 最终你要的value是什么,o->o的意思就是原来是啥就是啥我不做更换,因为我们就是要学生对象。
但是上面这种写法呢,是有一个问题的,这种写法是建立在绝对的key唯一的情况,就是你大脑是觉得这堆要处理的数据它一定是唯一的,key不能重复,如果重复,就嗝屁了
避免报错的一种写法
studentList.stream().collect(Collectors.toMap(x->x.getName(),o->o,(n1,n2)->n1));
args3:第三个参数说的就是万一遇到了key重复,你要怎么做呢,一般就是取其中一个咯,还能咋搞。
需求:得到学生数据,假设年级一样的我认为就是一个数据,重复的我不想要。
/*
[
{name:'张三',age:18,address:'北京',className:'1年级'},
{name:'李四',age:15,address:'北京',className:'1年级'},
{name:'王五',age:20,address:'北京',className:'3年级'},
]
*/
以下这个写法记住就行,平时拿出来抄一抄就行了。
data = studentList.stream().collect(Collectors.collectingAndThen(
Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(x->x.getClassName()))), ArrayList::new));