当前位置: 首页 > 知识库问答 >
问题:

在流的collect()终端操作中,如果supplier是字符串之类的不可变对象,会发生什么情况?

江琦
2023-03-14

Stream的Collection()方法是一个可变的约简。基于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操作相同?

共有2个答案

田成化
2023-03-14

根据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。如果我们想获取一个字符串流并将它们连接成一个长字符串,我们可以通过普通约简来实现这一点:

字符串连接=字符串。reduce(“”,字符串::concat)

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

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

江阳羽
2023-03-14

由于String是一个不可变对象,可变缩减在这里是如何工作的?

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

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

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

 类似资料:
  • Python中的字符串是不可变的,这意味着该值不能更改。我正在测试该场景,但看起来原始字符串已被修改。我只是想理解这个概念

  • 本文向大家介绍为什么字符串对象在Java中是不可变的?,包括了为什么字符串对象在Java中是不可变的?的使用技巧和注意事项,需要的朋友参考一下 通常,字符串用于表示重要细节,例如数据库连接URL,用户名密码等。字符串的不变性有助于使这些细节保持不变。 类似地,在加载类时,将String用作参数。那时,更改字符串可能会导致加载错误的类。 如果不可变,则变量(字符串)自动为线程安全的。

  • 我是java编程的新手。而且我不明白为什么string对象在Java中是不可变的。

  • 问题内容: 我更喜欢编译时错误-为什么不是这种情况?在不提供返回类型的情况下调用相同的问题时,可以将其应用于具有返回类型的任何方法。 可以在不提供引用/变量来保存返回类型的情况下调用: 问题答案: 该对象将立即创建并有资格进行垃圾收集(即,可能很快就会被垃圾收集)。 这不是编译时错误的原因是,并非每个返回方法的方法都需要您使用该返回值。某些方法仅因其副作用而被调用。 一个很好的例子是:它返回一个对

  • 我看到了很多关于使用字符串文字和新关键字创建对象的问题,比如: 使用新运算符的String对象数量 但这并不能澄清我的疑虑。 情况1:使用字符串文字的字符串对象。它在字符串常量池中创建一个对象,如果它不存在,则返回此对象的引用。此对象被隐式驻留。 案例2:使用new()的字符串对象。它创建了两个对象,一个在字符串常量池中,另一个在堆区域中。引用变量引用堆区域对象。对于这个对象,我们需要调用inte