Java8新特性——Stream API详解

  • Post author:
  • Post category:java


参考:

强大的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的函数?

好,分享到这里就结束了,有不明白的可以进群讨论哦~~~~~



版权声明:本文为weixin_41763995原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。