参考:
强大的Stream API以及并行流与串行流_wangwren的博客-CSDN博客_stream并行和串行使用
Stream API
Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API对集合数据进行操作,就类似于使用SQL执行的数据库查询。也可以使用Stream API来并行执行操作。简而言之,Stream API提供了一种高效且易于使用的处理数据的方式。
Stream
流(Stream)是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
集合讲的是数据,流讲的是计算。
注意
Stream自己不会存储元素。
Stream不会改变源对象。相反,它们会返回一个持有结果的新Stream。
Stream操作是延迟执行的。这意味着它们会等到需要结果的时候才执行。
Stream操作的三个步骤
创建Stream
一个数据源(如:集合、数组),获取一个流。
Java8中的Collection接口被扩展,提供了两个获取流的方式:
-
default Stream<E> stream()
:返回一个顺序流。 -
default Stream<E> parallelStream()
:返回一个并行流。
中间操作
一个中间操作链,对数据源的数据进行处理。
多个
中间操作
可以连接起来形成一个流水线,除非流水线上触发
终止操作
,否则
中间操作不会执行任何的处理
!而在
终止操作时一次性全部处理,称为“惰性求值”,也叫延迟加载
。
中间操作返回的值,还是一个Stream流对象
。
终止操作
一个终止操作,执行中间操作链,并产生结果。
终止操作会从流的流水线生产结果。其结果可以是任何不是流的值。例如:List、Integer,甚至是void。
终止操作与中间操作相比,终止操作返回值已经不再是Stream流对象了,所以叫终止操作,能够获取到对应的值了
。
并行流与串行流
-
并行流
就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。 -
Java8中将并行进行了优化,可以很容易的对数据进行并行操作。Stream API可以声明性地通过
parallel()
与
sequential()
在并行流与顺序流之间进行切换。
stream的常用方法示例如下:
创建学生实体类
/**
*创建学生类
**/
@Data
public class StudentEntity {
/**
* 学生姓名
*/
private String name;
/**
* 学生班级
*/
private String classes;
/**
* 学生年龄
*/
private Integer age;
public StudentEntity(String name,String classes,Integer age){
this.name=name;
this.classes=classes;
this.age=age;
}
}
/**
*创建学生List集合
*/
List<StudentEntity> newsEntities = new ArrayList<>();
//创建学生1
StudentEntity student1 = new StudentEntity("赵一", "A班", 12);
//创建学生2
StudentEntity student2 = new StudentEntity("钱二", "B班", 13);
//创建学生3
StudentEntity student3 = new StudentEntity("孙三", "A班", 11);
//创建学生4
StudentEntity student4 = new StudentEntity("李四", "C班", 15);
//添加到集合
newsEntities.add(student1);
newsEntities.add(student2);
newsEntities.add(student3);
newsEntities.add(student4);
OK,准备工作完毕,下面开始针对上面代码中的List进行我们的stream操作,达到操作sql一样的效果。
1.按班级对学生进行分组
//按班级对学生进行分组,分组后的key为班级
Map<String, List<StudentEntity>> groupBy = newsEntities.stream().
collect(Collectors.groupingBy(StudentEntity::getClasses));
//分组之后的结果
groupBy.forEach((k,v)->{
System.out.println(k+":"+v);
});
//输出结果
C班:[StudentEntity(name=李四, classes=C班, age=15)]
B班:[StudentEntity(name=钱二, classes=B班, age=13)]
A班:[StudentEntity(name=赵一, classes=A班, age=12), StudentEntity(name=孙三, classes=A班, age=11)]
这样分组就跟我们平时写的sql用的groupBy 达到的效果是一样的。
2.查询A班的学生信息
//查询A班的学生信息
List<StudentEntity> filter = newsEntities.stream().filter((s) -> s.getClasses().equals("A班")).collect(Collectors.toList());
//输出结果
filter.forEach((v)->{
System.out.println(v);
});
//输出结果
StudentEntity{name='赵一', classes='A班', age=12}
StudentEntity{name='孙三', classes='A班', age=11}
stream的filter是过滤方法,需要传入一个boolean值,为true则会保留,false则会过滤掉。
3.获取所有学生的姓名
//获取所有学生姓名
List<String> filter = newsEntities.stream().map(StudentEntity::getName).collect(Collectors.toList());
//输出结果
filter.forEach((v)->{
System.out.println(v);
});
//打印结果
赵一
钱二
孙三
李四
4.获取A班学生的年龄总数
//获取A班学生的年龄总数
int sumAge = newsEntities.stream().filter((s) -> s.getClasses().equals("A班")).mapToInt(StudentEntity::getAge).sum();
//输出结果
System.out.println(sumAge);
//打印结果如下
23
mapToInt方法是需要传入int/Integer类型的值,也可以有mapToDouble,这时候传入的值就是double类型了,后面的sum方法则代表将这些数值汇总计算,是不是很像sql的函数?
好,分享到这里就结束了,有不明白的可以进群讨论哦~~~~~