4

collect()Stream 的方法是一个可变的归约。基于 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,我将收集操作视为元素将附加到提供的 StringBuffer。

既然 String 是一个不可变对象,可变归约在这里如何工作?每次执行累加器时都会创建一个新对象的reduce操作是否相同?

4

2 回答 2

4

既然 String 是一个不可变对象,可变归约在这里如何工作?

它没有。当你运行它时,你会得到一个空字符串( 的结果Supplier only)。编译器无法强制检查供应商是否返回不可变对象,这绝对是它无法做到的。而且由于您的容器是不可变的,因此对它的更新将被忽略。就像这样做:

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);
            });

如果你想打破它;但这不是重点。

于 2018-09-12T15:18:53.270 回答
1

根据 Oracle / Java 文档:

收集

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

对此流的元素执行可变归约操作。可变归约是这样一种归约,其中归约值是一个可变结果容器,例如 ArrayList,并且通过更新结果的状态而不是替换结果来合并元素。

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-

可变归约

可变归约操作在处理流中的元素时将输入元素累积到可变结果容器中,例如 Collection 或 StringBuilder。如果我们想获取一个字符串流并将它们连接成一个长字符串,我们可以通过普通的归约来实现:

字符串连接 = strings.reduce("", String::concat)

https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#MutableReduction

因此,简而言之,它之所以有效,是因为 java 在幕后使用的是 stringbuilder

于 2018-09-12T13:26:17.970 回答