Java 8 - 在字符串流上不同 - IllegalStateException

时间:2017-02-24 11:20:05

标签: java java-8 java-stream

我对\b stream的{​​{1}}采取截然不同的行动有疑问。

String

然后,我收到了例外:

Stream<String> names = Arrays.asList("NAME A", "NAME B", "NAME A").stream();
names.distinct();
System.out.println(names.collect(Collectors.joining(",")));

但是,如果我像这样编写这部分代码:

Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:229)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
at com.Test.main(Test.java:62)

一切都好。

distinct的文档说:

  

Stream distinct()   返回由此流的不同元素(根据Object.equals(Object))组成的流。   对于有序流,不同元素的选择是稳定的(对于重复元素,保留在遇到顺序中首先出现的元素。)对于无序流,不进行稳定性保证。   这是一个有状态的中间操作。

我做错了什么?

感谢您的帮助

3 个答案:

答案 0 :(得分:4)

基本上你使用的是流API错误。

你忽略了你不应该做的distinct()的返回值。它类似于任何不直接对参数进行操作的方法,但会返回它的修改版本。

惯用版将是

String names = Arrays.asList("NAME A", "NAME B", "NAME A").
    stream().distinct().collect(Collectors.joining(",");
System.out.println(names);

答案 1 :(得分:4)

文档和错误消息说明了原因:stream has already been operated upon or closeddistinct() Returns a stream

当您在distinct上致电names时,会返回一个包含不同元素的新流。但是再次collect再次names。但是此流已由distinct运算符使用。

在第二个示例中,您正确地使用它,因为您收集了不同的流。

所以基本上,你总是要像第二个例子那样,或者简而言之

names.distinct().collect(Collectors.joining(","));

答案 2 :(得分:3)

正如the documentation所说:

  

应该只对一个流进行操作(调用中间或终端流操作)。例如,这排除了&#34;分叉&#34;流,相同的源提供两个或多个管道,或同一流的多个遍历。如果流实现检测到正在重用流,则可以抛出IllegalStateException

因此,一旦您在流上调用distinct(),就不能再使用它。而是使用返回的流。当您以source.stream().intermediateOp().anotherIntermediateOp().terminalOp()形式链接操作时,永远不会出现此错误。

所以在你的情况下,它将是

String s = Arrays.asList("NAME A", "NAME B", "NAME A").stream()
         .distinct().collect(Collectors.joining(","));
System.out.println(s);

但你可以直接使用

String s = Stream.of("NAME A", "NAME B", "NAME A")
         .distinct().collect(Collectors.joining(","));
System.out.println(s);

而不是使用Arrays.asList