什么是流
一种可以在比集合更高概念级别上指定计算的数据视图
操作流
- 创建一个初始流。
- 将初始流转换为其他流,可能包含多个步骤。
- 应用终止操作,产生结果。这个流从此以后不能再用。
创建流
1. Collection接口的stream方法将集合转换为流
假设已存在如下列表sList
List<String> sList = Arrays.asList("hello", "world", "java");
Stream<String> words = sList.stream();
List
接口继承了Collection
接口,直接调用stream()
方法创建流。
2. 静态的Stream.of方法
Stream<String> words = Stream.of("hello", "world");
Stream<String> words = Stream.of("hello world".split(" ")); // split方法返回一个String[] 数组
3. 创建不包含任何元素的流
Stream<String> empty = Stream.empty();
4. 创建无限流
Stream.generate(Supplier)
// 一个常量值的无限流
Stream<String> hellos = Stream.generate(() -> "hello");
// 可以理解这样 ["hello", "hello", ...] 的流
// 一个随机值的无限流
Stream<Double> randoms = Stream.generate(Math::random);
Stream.iterate(T, UnaryOperator)
接受一个”种子“和一个函数,反复将该函数应用到之前的结果上
// 产生一个0 1 2 3 ... 无限流
Stream<BigInteger> integers = Stream.iterate(BigInteger.ZERO,
n -> n.add(BigInteger.ONE));
流转换
流的转换会产生一个新的流,它的元素派生自另一个流中的元素。
1. filter转换会产生一个流,它的元素与某种条件相匹配
// 过滤得到所有元素小于3的流
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> nums = list.stream().filter(x -> x < 3);
2. map方法传递一个函数,并对流中的元素执行该函数
// 得到所有元素字符串大写的流
List<String> wordList = Arrays.asList("hello", "world");
Stream<String> upperWords = wordList.stream().map(String::toUpperCase);
3. flatMap方法传递一个函数,这个函数返回的是流,将每个流中的元素放到一个流中
List<Integer> list1 = Arrays.asList(0, 1, 2);
List<Integer> list2 = Arrays.asList(3, 4, 5);
List<List<Integer>> lists = Arrays.asList(list1, list2);
Stream<Integer> nums = lists.stream().flatMap(a -> a.stream());
// 相当于这样的流 [0, 1, 2, 3, 4, 5]
4. distinct方法,去除重复元素
Stream<String> words = Stream.of("java", "java", "python", "c++").distinct();
5. sorted方法,用于排序
// 根据字符串长度排序
Stream<String> longestFirst = Stream.of("java", "python", "c++").sorted(Comparator.comparing(String::length).reversed());
6. peek方法,每次获取一个函数,调用一次函数
便于调试代码
Stream<String> longWords = Stream.of("one", "two", "three", "four")
.filter(e -> e.length() > 3 )
.peek(e -> System.out.println("Filtered value: " + e));
终止操作
约简是一种终止操作,将流约简为在程序中可以使用的非流值。
1. count方法返回流中元素数量
Stream.of(1, 2, 3).count();
// 3
2. forEach方法将某个函数应用于每个元素
Stream.of("a", "b", "c").forEach(System.out::println);
// a
// b
// c
3. collect方法,将流中的元素收集到另一个目标中
List<Integer> list = Stream.of(1, 2, 3, 4, 5).filter(e -> e < 3).collect(Collectors.toList());
// list ==> [1, 2]
Note
- 流并不存储元素。这些元素可能存储于底层集合中或者按需生成。
- 流的操作不会修改数据源。
- 流的操作是尽可能惰性执行的。直至需要其结果时,操作才会执行。
我只想看例子
生成等差数列1, 4, 7, 10......
int n = 5;
Stream<Integer> s = Stream.iterate(1, x -> x + 3);
List<Integer> list = s.limit(n).collect(Collectors.toList());
// [1, 4, 7, 10, 13]
计算List的和
List<Integer> list = Arrays.asList(1, 2, 3, 4);
list.stream().mapToInt(x -> x).sum();
list.stream().reduce((x, y) -> x + y).get();