尽管在软件构造实验中,stream仅用于短平快地优化IO,但是作为对集合 (Collection) 对象功能的聚合操作和大批量数据操作的增强,stream还是很值得我们深入学习的。
所谓Stream
不是集合元素,不是数据结构并不保存数据
是有关算法和计算的,更像一个高级版本的Iterator,直接进行操作,而且是优化地进行操作
流的操作类型分为两种:
Intermediate:一个流可以后面跟随零个或多个 intermediate 操作。主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历。(例如map(mapToInt,flatMap等), filter, distinct, sorted, peek, limit, skip, parallel, sequential, unordered)
Terminal:一个流只能有一个 terminal 操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。Terminal 操作的执行,才会真正开始流的遍历,并且会生成一个结果,或者一个 side effect。(例如:forEach, forEachOrdered, toArray, reduce, collect, min, max, count, anyMatch, allMatch, noneMatch, findFirst, findAny, iterator)
还有一种操作被称为short-circuiting :
对于一个 intermediate 操作,如果它接受的是一个无限大的 Stream,但返回一个有限的新 Stream。
对于一个 terminal 操作,如果它接受的是一个无限大的 Stream,但能在有限的时间计算出结果。(例如:anyMatch, allMatch, noneMatch, findFirst, findAny, limit)
示例:
int sum = widgets.stream()
.filter(w -> w.getColor() == RED)//根据条件getColor() == RED筛选
.mapToInt(w -> w.getWeight())//转换getWeight()为int
.sum();//求和
stream() 获取当前小物件的 source,filter 和 mapToInt 为 intermediate 操作,进行数据筛选和转换,最后一个 sum() 为 terminal 操作,对符合条件的全部小物件作重量求和。
运用Stream操作分三步:创建Stream流、流中间操作、终止流操作
注意:
1. Stream本省不会存储元素;
2. Stream不会改变原来源对象,相反,会返回一个持有结果的新Stream;
3. Stream操作是延迟执行的,这意味着需要数据流通道的计算结果时才执行
功能演示:
- 构造流
// 1. Individual values 单独值 Stream stream = Stream.of("a1", "b1", "c1"); // 2. Arrays 数组 String[] strArray = new String[] {"a2", "b2", "c2"}; stream = Stream.of(strArray); stream = Arrays.stream(strArray); // 3. Collections 集合 List<String> list = Arrays.asList(strArray); stream = list.stream();
- 数值流的构造
IntStream.of(new int[] {1, 2, 3});// 123 IntStream.range(1, 3);// [1,3) 12 IntStream.rangeClosed(1, 3);// [1,3] 123
- 流转换为其他数据结构 (一个Stream只可以使用一次,否则会报错)
Stream stream = Stream.of("a1", "b1", "c1"); // 1. Array String[] strArray1 = (String[]) stream.toArray(String[]::new); // 2.Collection list stream = Stream.of("a1", "b1", "c1");// stream has already been operated upon or closed List<String> list1 = (List<String>) stream.collect(Collectors.toList()); // 3.Collection list stream = Stream.of("a1", "b1", "c1");// stream has already been operated upon or closed List<String> list2 = (List<String>)stream.collect(Collectors.toCollection(ArrayList::new)); // 4.Collection set stream = Stream.of("a1", "b1", "c1");// stream has already been operated upon or closed Set<String> set = (Set<String>) stream.collect(Collectors.toSet()); // 5.Collection stack stream = Stream.of("a1", "b1", "c1");// stream has already been operated upon or close Stack<String> stack = (Stack<String>)stream.collect(Collectors.toCollection(Stack::new)); // 6. String stream = Stream.of("a1", "b1", "c1");// stream has already been operated upon or closed String str = stream.collect(Collectors.joining()).toString();
- 转换大写
Stream<String> stream = Stream.of("hello", "world", "java8", "stream"); //方法1 List<String> wordList = stream.map(String::toUpperCase).collect(Collectors.toList()); //方法2 wordList = stream.map(s -> { return s.toUpperCase(); }).collect(Collectors.toList()); //方法3 wordList = stream.map(s -> s.toUpperCase()).collect(Collectors.toList());
- 计算(平方数)
//map 生产的是个1:1的映射,每个输入元素,都按照规则转换成另一个元素 Stream<Integer> stream = Arrays.asList(1, 2, 3, 4).stream(); List<Integer> squareList = stream.map(n -> n * n).collect(Collectors.toList());
- 一对多
//flatMap把input stream中的层级结构扁平化,就是将底层元素抽出来放到一起 //最终output的Stream里面已经没有List了,都是直接的数字 Stream<List<Integer>> inputStream = Stream.of(Arrays.asList(1), Arrays.asList(2, 3), Arrays.asList(4, 5, 6)); Stream<Integer> outputStream = inputStream.flatMap(childList -> childList.stream());
- 留下偶数
Integer[] sixNums = {1, 2, 3, 4, 5, 6}; Integer[] evens = Stream.of(sixNums).filter(n -> n % 2 == 0).toArray(Integer[]::new);
- 把单词挑出来
//首先把每行的单词用flatMap整理到新的Stream // 1. Java 8 Read File + Stream try (Stream<String> stream = Files.lines(path)) { List<String> output = stream.flatMap(line -> Stream.of(line.split(" "))) .filter(word -> word.length() > 0).collect(Collectors.toList()); } catch (IOException e) { e.printStackTrace(); } //然后保留长度不为0的,就是文章中的全部单词了 // 2. BufferedReader + Stream try (BufferedReader br = Files.newBufferedReader(path)) { List<String> output = br.lines().flatMap(line -> Stream.of(line.split(" "))) .filter(word -> word.length() > 0).collect(Collectors.toList()); } catch (IOException e) { e.printStackTrace(); }
- 排序
List<String> userList = users.stream() .limit(2) .sorted((p1, p2) -> p1.getName().compareTo(p2.getName())) .map(User::getName) // name_1,name_0,name_0,name_1, .collect(Collectors.toList());