目录
前言
其实最近自己看了不少的关于list流的操作文章,但是总觉得自己好像差点意思,只有有一天,自己好像忽然就明白了stream操作流的使用方式,不得不说,这个操作真的是行云流水以及上手,现在感觉就是开心,非常开心
正文
1.准备数据
1.1 实体类
我们先来准备一个实体类,用来模拟我们正常业务开发中的实体类,也可以当做是map,下面的内容,我会一点一点来说明目前我所理解的流操作。
实体类代码:
public class Student {
private int number;
private String name;
private String clazz;
private int score;
public Student(int number, String name, String clazz, int score) {
this.number = number;
this.name = name;
this.clazz = clazz;
this.score = score;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getClazz() {
return clazz;
}
public void setClazz(String clazz) {
this.clazz = clazz;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"number=" + number +
", name='" + name + '\'' +
", clazz='" + clazz + '\'' +
", score=" + score +
'}';
}
}
1.2 操作测试类
准备数据的代码
private static final List<Student> STUDENTS = create();
private static final String CLAZZ1 = "软件1班";
private static final String CLAZZ2 = "软件2班";
private static List<Student> create() {
Student s1 = new Student(2018008, "张扬", CLAZZ2, 66);
Student s2 = new Student(2018005, "刘飞", CLAZZ1, 92);
Student s3 = new Student(2018007, "李明", CLAZZ2, 42);
Student s4 = new Student(2018006, "赵勇", CLAZZ2, 56);
Student s5 = new Student(2018002, "王磊", CLAZZ1, 81);
Student s6 = new Student(2018010, "牛娜", CLAZZ1, 78);
List<Student> students = new ArrayList<>();
students.add(s1);students.add(s2);students.add(s3);
students.add(s4);students.add(s5);students.add(s6);
return students;
}
接下来我们要上作业了,在下面写上我们的main方法,把需求写在上面然后慢慢来。好了,来看一下这次我们的任务是哪些?
public static void main(String[] args) {
//方法1,获取成绩小于等于指定分数的全部学生
//方法2,获取指定班级,成绩小于等于指定分数,的全部学生
//方法3,获取指定班级,成绩小于等于指定分数,的全部学生的姓名。注意返回类型
//方法4,按成绩由低到高排序,返回全部学生
//方法5,获取指定班级,成绩小于等于指定分数,成绩由高到低排序,的全部学生
//方法6,获取指定班级,成绩小于等于指定分数,成绩由高到低排序,的全部学生的学号。注意返回类型
//方法7,获取指定班级,成绩小于等于指定分数,的全部学生
}
2.实现数据筛选
2.1 获取成绩小于等于指定分数的全部学生
先明确我们目的,要获取成绩小于等于指定分数,我们先假定这个分数为75,那么我们要使用流来进行操作,所以第一步,我们要先拿到这个list的流,那么先写出我们的代码,
STUDENTS.stream()
这样我们就拿到我们的流了,然后看需要,我们要拿到成绩小于等于指定分数,也就是说我们是要在这些数据中做筛选了,那么我点在上面的代码添加.之后,会出现很多的方法,如下图
有些方法我们先不讲,我们这次是要做筛选,所以我们选择filter,那么我们的代码就变成了这样
STUDENTS.stream().filter()
选择了filter之后,我们要在filter里面写上我们的筛选条件,通常我们都是使用lambda表达式,我们的list中每一个对应都是一个Student,所以我们先用一个变量来标识这个student,这个变量,和你正常遍历的使用for遍历的i是一个功能,然后加入我们的筛选条件,成绩小于等于75,然后我们的代码就变成了
STUDENTS.stream().filter(student -> student.getScore() <= 75)
这样我们的过滤就已经做完了,现在我们要拿到他返回的结果,我们在代码后面继续点,让这个结果变成一个集合,所以我们需要把这个结果收集起来,所以我们选择collect,这样代码就变成了
STUDENTS.stream().filter(student -> student.getScore() < 75).collect()
那么我们以什么样的结果返回那,通常我们也是希望它能为我们返回一个list,那么我们在collect里面告诉他,帮我返回list,我们借助集合工具类,代码就变成了
STUDENTS.stream().filter(student -> student.getScore() < 75).collect(Collectors.toList());
任务完成,加上分号,存储变量打印输出!看结果
下一个!!!
2.2 获取指定班级,成绩小于等于指定分数,的全部学生
这个需求,和上面什么区别,我xxxxx,好吧,现在我们假定获取软件2班的同学吧(为了偷懒就不让他们选择了,这个参数是可以传递的),那我们的代码需要变得是哪里,没错,就是我们的过滤条件,那我们怎么改那,我直接双&行不行,搞一下不就晓得了。来,上代码
List<Student> collect2 = STUDENTS.stream().filter(student -> CLAZZ2.equals(student.getClazz()) && student.getScore() <= 75).collect(Collectors.toList());
任务完成,加上分号,存储变量打印输出!看结果
怎么又是你们!看了一眼数据,没错啊,就是你们,小于75的都是二班的!!!!
下一个!!!!
2.3 获取指定班级,成绩小于等于指定分数,的全部学生的姓名。注意返回类型
这个看样子来新的需求了,不慌,看我搞定!
首先我们还是按照之前的数据来做过滤,那么我们的代码先写成这个样子
STUDENTS.stream().filter(student -> CLAZZ2.equals(student.getClazz()) && student.getScore() <= 75)
这个时候我们已经做了过滤等级和班级,看他后面的需要,全部学生的姓名,那我们应该怎么搜集他的姓名呢,首先明确我们的目标,我们是要做收集对象的某一个属性,filter肯定不对,foreach遍历操作有点像,但是也不对,因为foreach的操作时没有返回值的(这个你试一下就知道了),那么其他的方法名我们怎么看都不太像,那就试一下map吧,里面同样写出lambda表达式,我们获取他的名称,上代码
List<String> collect3 = STUDENTS.stream().filter(student -> CLAZZ2.equals(student.getClazz()) && student.getScore() < 75).map(student -> student.getName()).collect(Collectors.toList());
收集就一起写上去了,看一下返回结果,好像是一个List 好像有戏,执行一下试一下
下一个!!!!
2.4 按成绩由低到高排序,返回全部学生
这个简单,我直接Arrays.sort(list.toArray)
等等,
我在说什么,先看看我们的流又没有提供排序功能吧,获取流之后点一下,发现有一个sorted,嗯,像,那就试一下吧
所以我们代码就变成了这样
有两个方法,一个需要传递比较器,一个不需要传递,看样子不传递的应该就是默认的排序规则了吧,java默认的排序规则一般都是从小到大(实际上我也试了,是从小到大),student里面没有比较的方法,所以我们还是自己写一个比较器吧,然后我们的代码就变成了
List<Student> collect4 = STUDENTS.stream().sorted(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.getScore()-o2.getScore();
}
}).collect(Collectors.toList());
//打印输出内容
collect4.stream().forEach(student -> System.out.println(student));
看执行结果
下一个!!!!!!
2.5 获取指定班级,成绩小于等于指定分数,成绩由高到低排序,的全部学生
这个就是2.2和2.4组合,代码应该不难理解,先排序还是先过滤都可以,建议还是先过滤 。注意排序规则变了,所以我们要修改我们的比较器。上代码了
List<Student> collect5 = STUDENTS.stream().filter(student -> CLAZZ2.equals(student.getClazz()) && student.getScore() < 75).sorted(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o2.getScore() - o1.getScore();
}
}).collect(Collectors.toList());
执行结果
下一个!!!!
2.6 获取指定班级,成绩小于等于指定分数,成绩由高到低排序,的全部学生的学号。注意返回类型
这,这个2.4有什么区别,就是多了一个比较吗?过,下一个
List<Integer> collect6 = STUDENTS.stream().filter(student -> CLAZZ2.equals(student.getClazz()) && student.getScore() < 75).sorted(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o2.getScore() - o1.getScore();
}
}).map(student -> student.getNumber()).collect(Collectors.toList());
2.7 获取指定班级,成绩小于等于指定分数,的全部学生
这个,怎么感觉需求跟上面比还变简单了呢,上代码了
STUDENTS.stream().filter(student -> CLAZZ2.equals(student.getClazz()) && student.getScore() < 75).collect(Collectors.toList());
附上完整版本代码
public class StreamTest1 {
private static final List<Student> STUDENTS = create();
private static final String CLAZZ1 = "软件1班";
private static final String CLAZZ2 = "软件2班";
private static List<Student> create() {
Student s1 = new Student(2018008, "张扬", CLAZZ2, 66);
Student s2 = new Student(2018005, "刘飞", CLAZZ1, 92);
Student s3 = new Student(2018007, "李明", CLAZZ2, 42);
Student s4 = new Student(2018006, "赵勇", CLAZZ2, 56);
Student s5 = new Student(2018002, "王磊", CLAZZ1, 81);
Student s6 = new Student(2018010, "牛娜", CLAZZ1, 78);
List<Student> students = new ArrayList<>();
students.add(s1);students.add(s2);students.add(s3);
students.add(s4);students.add(s5);students.add(s6);
return students;
}
public static void main(String[] args) {
//方法1,获取成绩小于等于指定分数,的全部学生
System.out.println("-------------------------------");
List<Student> scoredayu = STUDENTS.stream().filter(student -> student.getScore() <= 75).collect(Collectors.toList());
scoredayu.stream().forEach(student -> System.out.println(student));
System.out.println("-------------------------------");
// //方法2,获取指定班级,成绩小于等于指定分数,的全部学生
List<Student> collect2 = STUDENTS.stream().filter(student -> CLAZZ2.equals(student.getClazz()) && student.getScore() <= 75).collect(Collectors.toList());
collect2.stream().forEach(student -> System.out.println(student));
System.out.println("-------------------------------");
// //方法3,获取指定班级,成绩小于等于指定分数,的全部学生的姓名。注意返回类型
List<String> collect3 = STUDENTS.stream().filter(student -> CLAZZ2.equals(student.getClazz()) && student.getScore() < 75).map(student -> student.getName()).collect(Collectors.toList());
collect3.stream().forEach(student -> System.out.println(student));
System.out.println("-------------------------------");
// //方法4,按成绩由低到高排序,返回全部学生
List<Student> collect4 = STUDENTS.stream().sorted(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.getScore()-o2.getScore();
}
}).collect(Collectors.toList());
collect4.stream().forEach(student -> System.out.println(student));
System.out.println("-------------------------------");
// //方法5,获取指定班级,成绩小于等于指定分数,成绩由高到低排序,的全部学生
List<Student> collect5 = STUDENTS.stream().filter(student -> CLAZZ2.equals(student.getClazz()) && student.getScore() < 75).sorted(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o2.getScore() - o1.getScore();
}
}).collect(Collectors.toList());
collect5.stream().forEach(student -> System.out.println(student));
System.out.println("-------------------------------");
// //方法6,获取指定班级,成绩小于等于指定分数,成绩由高到低排序,的全部学生的学号。注意返回类型
List<Integer> collect6 = STUDENTS.stream().filter(student -> CLAZZ2.equals(student.getClazz()) && student.getScore() < 75).sorted(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o2.getScore() - o1.getScore();
}
}).map(student -> student.getNumber()).collect(Collectors.toList());
collect6.stream().forEach(System.out::println);
System.out.println("-------------------------------");
// //方法7,获取指定班级,成绩小于等于指定分数,的全部学生
List<Student> collect7 = STUDENTS.stream().filter(student -> CLAZZ2.equals(student.getClazz()) && student.getScore() < 75).collect(Collectors.toList());
collect7.stream().forEach(student -> System.out.println(student));
System.out.println("-------------------------------");
}
}
3 代码优化
改动1
写完了功能发现我的代码在干嘛,它再飘黄,有代码洁癖的人看了肯定忍不了,来,看看怎么优化,
看这个提示,什么lambda可以被方法给替代,按照idea给的建议方案来改动
我们的打印代码就变成了
collect7.forEach(System.out::println);
改动2
估计大家也能看到了飘黄的不止是这个地方,还有这个
虽然我英语不太好,但是凭借着我的经验我还是认出来了它的意思,
它的意思是比较器可以被lambda表达式给替代,那要是替代的话怎么写呢?直接alt+inter 看看idea给出的解决方案
List<Student> collect5 = STUDENTS.stream().filter(student -> CLAZZ2.equals(student.getClazz()) && student.getScore() < 75).sorted((o1, o2) -> o2.getScore() - o1.getScore()).collect(Collectors.toList());
看到了 其实就是将
换成了
这个改动之后,我总算是明白了为什么我之前看别人的例子,别人的例子总是那么的简洁,让我有点些许的迷茫,不过现在知道这个结果怎么来的之后,发现自己能看明白了这个操作。
4 Stream流API
Stream流的中间操作api有
api | 操作解释 |
---|---|
limit | 指定几条数据 |
skip | 跳过几条数据从指定数据下标开始 |
distinct | 去重 |
map | 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。 |
sorted | 排序 |
allMatch | 检查是否匹配所有元素 |
anyMatch | 检查是否至少匹配一个元素 |
noneMatch | 检查是否没有匹配所有元素 |
findFirst | 返回第一个元素 |
findAny | 返回当前流中的任意元素 |
count | 返回流中元素的总个数 |
max | 返回流中最大值 |
min | 返回流中最小值 |
关于其他的具体操作,我这里就不在举例子,如果业务中有需要要使用的话,建议大家先写demo,还有,使用stream操作的时候,为了防止后续人员看你的代码懵逼,所以一定要在流上面写注释!!!,一定要在流上面写注释!!!一定要在流上面写注释!!!告诉别人你的这个操作目的是什么!!!要不我就~~~~~~