Java 8 添加了一个新的抽象称为流 Stream,可以让你以一种声明的方式处理数据。这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。Stream API 可以极大提高 Java 程序员的生产力,让程序员写出高效率、干净、简洁的代码。
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
定义一个学生类
@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));
}
// 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
// 过滤出身高在 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
// 是否有满足年龄小于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
// 输出年龄最小的学生
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
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]
// 按照年纪从小到大的排序
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]
// 计算出学生的最高身高
Optional reduce = students.stream().map(Student::getHeight).reduce(Integer::max);
System.out.println(reduce.get());
190
Collectors 类实现了很多归约操作,例如将流转换成集合和聚合元素。前面的示例中有使用到 toList()。
除此之外,还有 toSet(),joining(),groupingBy()等等一系列的方法。