1. 流(Stream)
- 流(Stream)中保存对集合或数组数据的操作。和集合类似,但集合中保存的是数据
- 流到底是什么?简短的定义就是“从支持数据处理操作的源生成的元素序列”
- 类似于生活中的流水线
1.1 Stream 特点
- Stream 自己不会存储元素
- Stream 不会改变源对象。相反,它们会返回一个持有结果的新 Stream
- Stream 操作是延迟执行的,这意味着它们会等到需要结果的时候才执行
优点:
- 声明性—更简洁,更易读;
- 可复合—更灵活;
- 可并行——性能更好
for-each 外部迭代;Stream库使用内部迭代
和迭代器类似,流只能遍历一次
管道( | ) 一个程序的输出流作为另一个程序的输入流
1.2 Stream 使用步骤
- 构建流:创建一个流
- 中间操作:在一个或多个步骤中,将初始 Stream 转化到另一个 Stream 的中间操作
- 终止操作:使用一个终止操作来产生一个结果。该操作会强制它之前的延迟操作立即执行,在这之后,该 Steam 就不能使用了
使用链接方法(chaining):
可以连接起来的流操作称为中间操作,关闭流的操作称为终端操作
1.3 三类接口
- 中间方法:将流转换为另一个流
- 终止方法:返回结果或执行操作,在执行方法终止后,流会自动关闭
- 静态方法:创建一个流
2. 构建流
public interface Stream<T> extends BaseStream<T, Stream<T>> {
public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) {}
public static<T> Stream<T> generate(Supplier<T> s) {}
}
示例:
List<String> list = new ArrayList<>();
list.add("aaa");
Stream<String> stream = list.stream();
Stream<String> parallelStream = list.parallelStream();
// Arrays.stream
String[] arr = {"aaa", "bbb"};
Stream<String> stream = Arrays.stream(arr);
stream.forEach(System.out::println);
2.2 迭代流
无限流 iterate(...) 接受一个初始值,还有一个依次应用在每个产生的新值上的 Lambda UnaryOperator<T>类型
Stream<Integer> iterate = Stream.iterate(0, n -> n + 2);
// limit(...)中间操作,限制下数量,不然会一直迭代
iterate.limit(10).forEach(System.out::println);
// Stream.iterate(0, n -> n + 2).limit(10).forEach(System.out::println);
2.4 生成流
generate(...) 不是依次对每个新生成的值应用函数的。它接受一个Supplier<T>类型的Lambda提供新的值
Stream<Integer> generate = Stream.generate(() -> new Random().nextInt());
generate.limit(5).forEach(System.out::println);
Stream.generate(Math::random).limit(5).forEach(System.out::println);
2.5 IntStream / LongStream / DoubleStream
range(...) / rangeClosed(...)
IntStream intStream = IntStream.rangeClosed(0, 10);
intStream.forEach(System.out::println);
3. 惰性中间方法
- 流是惰性的,仅仅当终止操作开始时才会进行计算
- filter, distinct, sorted
- limit(n) 截断流;skip(n) 返回一个扔掉了前n个元素的流
- map, flatMap, mapToInt
- sorted
3.1 filter(...)
- Stream<T> filter(Predicate<? super T> predicate)
- filter(Predicate) 接受一个谓词作为参数,并返回一个包括所有符合谓词的元素的流
list.stream()
.filter(str -> {
System.out.println("filter run....");
return str.equals("111");
});
// .forEach(System.out::println);
// 不加 forEach(), filter() 里的内容不会执行
3.2 map(...)
- <R> Stream<R> map(Function<? super T, ? extends R> mapper);
-
map(Function<T, R>)
接受一个函数作为参数,这个函数会被应用到每个元素上,并将其映射成一个新的元素
3.3 flatMap
- 流的扁平化
- flatMap(Arrays::stream) 生成的单个流都被合并起来,即扁平化为一个流
- flatMap() 把一个流中的每个值都换成另一个流,然后把所有的流连接起来成为一个流
flatMap(Function<? super List<Child>, ? extends Stream<? extends R>> mapper)
// .flatMap(Collection::stream)
flatMap(Function<? super String[], ? extends Stream<? extends R>> mapper)
// .flatMap(Arrays::stream)
List<String> words = Arrays.asList("hello", "world");
List<String> collect = words.stream().distinct().collect(Collectors.toList());
List<String> list = words.stream()
.map(str -> str.split("")) // Stream<String[]>
.flatMap(Arrays::stream) // Stream<String>
.distinct()
.collect(Collectors.toList());
System.out.println(list);
Student student = new Student();
Student student2 = new Student();
List<Student> students = Arrays.asList(student, student2);
List<Child> childList = students.stream() // Stream<Student>
.map(Student::getChilds) // Stream<List<Child>>
.flatMap(Collection::stream) // Stream<Child>
.collect(Collectors.toList());
Stream<List<Child>> listStream = students.stream().map(Student::getChilds);
Stream<Child> childStream = students.stream().map(Student::getChilds).flatMap(Collection::stream);
Stream<Child> childStream2 = students.stream().map(Student::getChilds).flatMap(childs -> childs.stream());
public class Student {
List<Child> childs;
}
4. 终止方法
- void forEach(Consumer<? super T> action)
- collect
- max, min, count, sum, average
- reduce
- findFirst, firstAny, anyMatch, allmatch, noneMath, toArray
4.1 collect
List<String> aaa = list.stream().filter(str -> str.equals("aaa")).collect(Collectors.toList());
4.2 reduce(...)
- 归约操作:将流中的元素规约为单一值(通过重复应用二元运算符)
- Stream.reduce(T identity, BinaryOperator<T> accumulator)
// map 和 reduce 的连接通常称为 map-reduce 模式
Optional<Integer> reduce = list.stream()
.map(OrderDO::getId)
.reduce(Integer::sum);
// Integer.sum(int a, int b)
public static int sum(int a, int b) {
return a + b;
}
Optional<Integer> count = list.stream()
.map(OrderDO::getId)
.reduce((a, b) -> a + b);
Reference
- 《Java 实战》
- 尚硅谷Java8新特性-李贺飞
网友评论