在Stream的collect()终端操作中,如果供应商是诸如String之类的不可变对象,将会发生什么?

时间:2018-09-12 13:15:05

标签: java java-stream collectors

Stream的

collect()方法是可变的。基于Java文档:

  

可变归约运算在处理流中的元素时将输入元素累积到可变结果容器(例如Collection或StringBuilder)中。

我尝试了以下内容,并且编译没有问题。

Stream<String> stream1 = Stream.of("w", "o", "l", "f");
String word = stream1.collect(String::new, String::concat, String::concat);
System.out.println(word);

如果供应商是StringBuffer,则我将查看collect操作,因为元素将附加到提供的StringBuffer上。

由于String是不可变的对象,可变约简在这里如何工作?会与每次执行累加器时创建新对象的reduce操作一样吗?

2 个答案:

答案 0 :(得分:4)

  

由于String是不可变的对象,因此可变约简在这里如何工作?

不是。运行该命令时,将得到一个空字符串(Supplier only的结果)。编译器无法强制检查Supplier是否返回一个不可变的对象,这绝对是它不能执行的操作。而且由于您的容器是不可变的,因此只需忽略对其的更新。就像这样做:

String s = "abc";
s.concat("def"); // the result is ignored here

如果您将其写为lambda,可能会更有意义:

Stream<String> stream1 = Stream.of("w", "o", "l", "f");
    String word = stream1.collect(
            String::new,
            (left, right) -> {
                left.concat(right); // result is ignored
            },
            String::concat);

另一方面,当您使用reduce时,会强制返回某些内容:

String word = stream1.reduce(
            "",
            (x, y) -> {
                return x.concat(y);
            },
            (x, y) -> {
                return x.concat(y);
            });

当然,您仍然可以这样做:

String word = stream1.reduce(
            "",
            (x, y) -> {
                x.concat(y);
                return x; // kind of stupid, but you could
            },
            (x, y) -> {
                return x.concat(y);
            });

如果您想破坏它;但这不是重点。

答案 1 :(得分:1)

根据Oracle / Java文档:

收集

<R> R collect(Supplier<R> supplier, <R,? super T> accumulator, <R,R> combiner)

对此流的元素执行可变的归约运算。可变归约法是将归约值作为一个可变结果容器(例如ArrayList),并且通过更新结果的状态而不是通过替换结果来合并元素的方法。

Expression.Call

可变削减

可变归约运算在处理流中的元素时将输入元素累积到可变结果容器(例如Collection或StringBuilder)中。 如果我们想获取字符串流并将其连接为单个长字符串,则可以通过普通归约来实现:

  

串联的字符串= strings.reduce(“”,String :: concat)

https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#collect-java.util.function.Supplier-java.util.function.BiConsumer-java.util.function.BiConsumer-

因此,总而言之,它之所以有效,是因为Java在后台使用了stringbuilder