为什么在同一流上调用两个终端操作后不抛出 IllegalStateException?
Why is IllegalStateException not thrown after calling two terminal operations on the same stream?
我了解到 collect()
和 forEach()
都是流终端操作,在同一个流上调用它们会抛出 IllegalStateException
。但是,以下代码编译成功并按升序打印每个字符串的长度。没有异常被抛出。怎么会这样?
List<String> list = Arrays.asList("ant", "bird", "chimpanzee", "dolphin");
list.stream().collect(Collectors.groupingBy(String::length))
.forEach((a, b) -> System.out.println(a));
为 list.stream()
生成的流被 collect
操作消耗。但是,作为分组的结果,该操作会根据字符串的大小生成 Map<Integer, List<String>>
。
然后 forEach
会根据 collect
生成的 Map
的条目调用,因此不会为后者抛出 IllegalStateException
。
您正在调用的 forEach
方法不是 Stream::forEach
方法,而是 Map::forEach
方法,因为您在 return 值上调用它 collect(...)
,这是一个Map
。 Map::forEach
方法的一个特点是它采用 BiConsumer
,而不是 Consumer
。流的 forEach
从不接受带有两个参数的 lambda!
所以你只在流上调用一个终端操作,即collect
。在那之后,您再也没有对流进行任何操作(您开始使用 returned Map
),这就是为什么没有 IllegalStateExcepton
被抛出的原因。
要在同一个流上实际调用两个终端操作,需要先将流放入一个变量中:
List<String> list = Arrays.asList("ant", "bird", "chimpanzee", "dolphin");
Stream<String> stream = list.stream(); // you need this extra variable.
stream.collect(Collectors.groupingBy(String::length));
stream.forEach((a) -> System.out.println(a)); // this will throw an exception, as expected
我了解到 collect()
和 forEach()
都是流终端操作,在同一个流上调用它们会抛出 IllegalStateException
。但是,以下代码编译成功并按升序打印每个字符串的长度。没有异常被抛出。怎么会这样?
List<String> list = Arrays.asList("ant", "bird", "chimpanzee", "dolphin");
list.stream().collect(Collectors.groupingBy(String::length))
.forEach((a, b) -> System.out.println(a));
为 list.stream()
生成的流被 collect
操作消耗。但是,作为分组的结果,该操作会根据字符串的大小生成 Map<Integer, List<String>>
。
然后 forEach
会根据 collect
生成的 Map
的条目调用,因此不会为后者抛出 IllegalStateException
。
您正在调用的 forEach
方法不是 Stream::forEach
方法,而是 Map::forEach
方法,因为您在 return 值上调用它 collect(...)
,这是一个Map
。 Map::forEach
方法的一个特点是它采用 BiConsumer
,而不是 Consumer
。流的 forEach
从不接受带有两个参数的 lambda!
所以你只在流上调用一个终端操作,即collect
。在那之后,您再也没有对流进行任何操作(您开始使用 returned Map
),这就是为什么没有 IllegalStateExcepton
被抛出的原因。
要在同一个流上实际调用两个终端操作,需要先将流放入一个变量中:
List<String> list = Arrays.asList("ant", "bird", "chimpanzee", "dolphin");
Stream<String> stream = list.stream(); // you need this extra variable.
stream.collect(Collectors.groupingBy(String::length));
stream.forEach((a) -> System.out.println(a)); // this will throw an exception, as expected