Java 8 新特性——Stream

一.Stream简介

Java 8 添加了一个新的抽象称为流 Stream,可以让你以一种声明的方式处理数据。这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。Stream API 可以极大提高 Java 程序员的生产力,让程序员写出高效率、干净、简洁的代码。

1.什么是Stream

Stream 是一个来自数据源的元素队列并支持聚合操作

  • 元素是特定类型的对象形成一个队列。 Java 中的 Stream 并不会存储元素,而是按需计算。
  • 数据源是流的来源。 可以是集合,数组,I/O channel 等。
  • 聚合操作类似 SQL 语句一样的操作, 比如 filter, map, reduce, find, match, sorted 等。

二.Stream操作分类

1.中间操作

中间操作可以有多个,每次返回一个新的流,可以进行链式操作。 

中间操作又可以分为两种:

  1. 无状态操作:指元素的处理不受之前元素的影响
  2. 有状态操作:该操作只有拿到所有元素之后才能继续下去

2.最终操作

最终操作只能有一个,每次执行完,流就会结束。

最终操作又可以分为两种:

  1. 非短路操作:指必须处理所有元素才能得到最终结果
  2. 短路操作:指遇到某些符合条件的元素就可以得到最终结果

三.创建Stream的方式

1.通过集合接口有两个方法来生成流:

  • stream() :为集合创建串行流

  • parallelStream() :为集合创建并行流

ArrayList list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);

// 创建一个串行流
Stream stream = list.stream();
// 创建一个并行流,如果流中的数据量很大,并行流可以加快处理速度
Stream parallelStream = list.parallelStream();
// 串行流也可以转化成并行流
Stream parallel = stream.parallel();

2.通过数组的工具类 Arrays 创建流

int[] array = {1, 2, 3};
IntStream stream = Arrays.stream(array);

3.通过 Stream 的静态方法 of()、iterate()、generate()

// of()的参数是一个可变参数列表
Stream ofStream = Stream.of(1, 2, 3);
ofStream.forEach(System.out::println);

// limit():限制流中的元素个数
Stream iterateStream = Stream.iterate(4, f -> f + 1).limit(3);
iterateStream.forEach(System.out::println);

// 生成三个随机的UUID
Stream generateStream = Stream.generate(UUID::randomUUID).limit(3);
generateStream.forEach(System.out::println);
1
2
3
4
5
6
abc33303-4154-4657-ae00-896fc46e020f
a9eda10c-b716-4ad6-ab8e-b68a28992d66
36f821a9-080b-48a7-8dae-6072cf165c9c

四.Stream API示例演示

定义一个学生类

@Data
public class Student {
    private String name;
    private int age;
    private int height;

    @Override
    public String toString() {
        return "name = " + name + " | age = " + age + " | height = " + height;
    }
}

预置数据

private static final ArrayList students = new ArrayList<>();
    
static {
    students.add(new Student("jack", 18, 180));
    students.add(new Student("lisa", 17, 160));
    students.add(new Student("rose", 16, 165));
    students.add(new Student("peter", 19, 190));
    students.add(new Student("jim", 18, 175));
}

1.使用 Stream 的 forEach 遍历

// forEach遍历
students.stream().forEach(System.out::println);
name = jack | age = 18 | height = 180
name = lisa | age = 17 | height = 160
name = rose | age = 16 | height = 165
name = peter | age = 19 | height = 190
name = jim | age = 18 | height = 175

2.使用 Stream 的 filter 按条件过滤

// 过滤出身高在 170 以上的学生,并全部输出
students.stream().filter(student -> {
    if (student.getHeight() > 170) {
        return true;
    }
    return false;
}).forEach(System.out::println);

// 过滤出身高在 170 以上的学生,并保存到一个新的集合
List newStudents = students.stream().filter(student -> student.getHeight() > 170).collect(Collectors.toList());

System.out.println("---------------------------");

// 过滤出身高在 170 以上的学生,并匹配第一个
Optional first = students.stream().filter(student -> student.getHeight() > 170).findFirst();
System.out.println(first.get());

System.out.println("---------------------------");

// 过滤出身高在 170 以上的学生,并任意匹配一个
Optional any = students.stream().filter(student -> student.getHeight() > 170).findAny();
System.out.println(any.get());
name = jack | age = 18 | height = 180
name = peter | age = 19 | height = 190
name = jim | age = 18 | height = 175
---------------------------
name = jack | age = 18 | height = 180
---------------------------
name = jack | age = 18 | height = 180

3.使用 Stream 的 anyMatch/AllMatch 匹配

// 是否有满足年龄小于18,身高大于180的学生
boolean anyMatch = students.stream().anyMatch(student -> student.getAge() < 18 && student.getHeight() > 180);
System.out.println(anyMatch);
// 是否所有的学生年龄都大于15
boolean allMatch = students.stream().allMatch(student -> student.getAge() > 15);
System.out.println(allMatch);
false
true

4.使用 Stream 的聚合方法 max/min/count

// 输出年龄最小的学生
Optional min = students.stream().min((t1, t2) -> {
    if (t1.getAge() < t2.getAge()) {
        return -1;
    }

    if (t1.getAge() > t2.getAge()) {
        return 1;
    }

    return 0;
});
System.out.println(min.get());

System.out.println("----------------------");

// 输出身高最高的学生
Optional max = students.stream().max((t1, t2) -> {
    if (t1.getHeight() < t2.getHeight()) {
        return -1;
    }

    if (t1.getAge() > t2.getAge()) {
        return 1;
    }

    return 0;
});
System.out.println(max.get());

System.out.println("----------------------");

// 统计身高在170以上的学生个数
long count = students.stream().filter(student -> student.getHeight() > 170).count();
System.out.println(count);
name = rose | age = 16 | height = 165
----------------------
name = peter | age = 19 | height = 190
----------------------
3

5.使用 Stream 的 map/flatMap

map:将每个元素通过指定方法映射成一个新的元素

// 假设 1 年后,每个学生的身高增加了 1
List newStudents = students.stream().map(student -> {
    int age = student.getAge();
    int height = student.getHeight();
    student.setAge(age + 1);
    student.setHeight(height + 1);
    return student;
}).collect(Collectors.toList());

System.out.println(newStudents);
[name = jack | age = 19 | height = 181, name = lisa | age = 18 | height = 161, name = rose | age = 17 | height = 166, name = peter | age = 20 | height = 191, name = jim | age = 19 | height = 176]

flatMap:将每个元素通过指定方法映射成一个新的流

// 将数组中的元素拆分成字符,然后组成一个新的集合
String[] origin = {"hello", "world"};
List result = Arrays.stream(origin).flatMap(str -> {
    String[] strings = str.split("");
    // 返回一个流
    return Arrays.stream(strings);
}).collect(Collectors.toList());

System.out.println(result);
[h, e, l, l, o, w, o, r, l, d]

6.使用 Stream 的 sorted 排序

// 按照年纪从小到大的排序
List sort = students.stream().sorted((t1, t2) -> {
    if (t1.getAge() < t2.getAge()) {
        return -1;
    }

    if (t1.getAge() > t2.getAge()) {
        return 1;
    }
    return 0;
}).map(Student::getName).collect(Collectors.toList());

System.out.println(sort);
[rose, lisa, jack, jim, peter]

7.使用 Stream 的 reduce 归约

// 计算出学生的最高身高
Optional reduce = students.stream().map(Student::getHeight).reduce(Integer::max);

System.out.println(reduce.get());
190

8.Collectors

Collectors 类实现了很多归约操作,例如将流转换成集合和聚合元素。前面的示例中有使用到 toList()。

除此之外,还有 toSet(),joining(),groupingBy()等等一系列的方法。

你可能感兴趣的:(java)