【问题标题】:When using java 8 map, filter and collect, does it create new objects or modify existing objects?使用java 8 map、filter和collect时,是创建新对象还是修改现有对象?
【发布时间】:2017-06-04 07:13:03
【问题描述】:

我有下面的代码,我在地图中使用过滤器和替换函数进行过滤,然后我正在收集来替换我的原始数组。我的问题是我在 inputArr 中的原始对象是否被丢弃并创建了新对象,或者在我进行收集时是否正在修改相同的对象?

public static void test () {
    inputArr.stream().filter(s -> toRemove.contains(s)).
            forEach(u -> u.replaceAll("2","X"));
    inputArr = inputArr.stream().map(x -> filterReplace(x,toRemove)).collect(Collectors.toList());
    System.out.println(inputArr);
}

static String filterReplace(String input, Set<String> toRemove) {
    if (toRemove.contains(input)) {
        return "X";
    }
    else
        return input;
}

【问题讨论】:

  • 提示:您可以将s -&gt; toRemove.contains(s) 替换为toRemove::contains。
  • @SriK 数组?看起来inputArr实际上是一个列表

标签: java functional-programming java-stream


【解决方案1】:

好的,如果我理解正确,您想知道collect 或forEach 是否修改了原始来源。您可以自己轻松地对此进行测试。让我们开一个小班进行测试:

static class MyObject {
    private int value;

    public MyObject(int value) {
        super();
        this.value = value;
    }

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return System.identityHashCode(this) + " " + value;
    }
}

还有一个小用法,首先是forEach:

    MyObject first = new MyObject(1);
    MyObject second = new MyObject(2);
    List<MyObject> list = Arrays.asList(first, second);

    System.out.println(list);
    list.stream().forEach(x -> x.setValue(x.getValue() + 1));
    System.out.println(list);

如果您打印这些:

[1018081122 1, 242131142 2]
[1018081122 2, 242131142 3]

注意它是相同的相同的散列 - 对象在列表中没有改变。参考文献是一样的。你改变的是一个对象的internals。

collect 也会发生同样的事情:

    System.out.println(list);
    List<MyObject> result = list.stream().filter(x -> x.getValue() > 0).collect(Collectors.toList());
    System.out.println(result);

这里有两个主要的东西。 Streams 对现有源进行迭代,如果您在流中更改了某些属性(如在 forEach 示例中),则您已更改了源。

您不应更改流的来源,因为文档禁止这样做。这被称为不干扰或副作用。

【讨论】:

  • 谢谢。很好的答案。所以在某种程度上,forEach 确实造成了副作用,但由于它没有修改输入列表中的项目数,所以这种副作用很好吗?如果我要在我的 forEach 中删除列表中的项目,那将被禁止。这是正确的解释吗?
【解决方案2】:

任何修改字符串的方法都必须返回一个新对象,因为字符串在定义上是不可变的。因此,

forEach(u -> u.replaceAll("2","X"))

为流中的每个元素创建一个新字符串,然后立即丢弃它,因为返回值被忽略。

至于第二个流中的filterReplace() 方法,根本没有修改,它只是返回输入字符串或另一个预定义值("X")。重新分配该变量后,inputArr 中的原始对象可能会被丢弃,但不会在流中创建新对象。

【讨论】:

  • 谢谢。但是让我们说它不是一个字符串,而是一个对象,而不是 replaceAll,我正在修改对象中的一个属性。在这种情况下,我的原始对象数组是被新的对象数组替换还是 .collect 修改了对原始列表中对象的引用?
  • 两者。第一个流修改现有对象,第二个流用新对象替换列表。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-01-31
  • 2011-11-28
  • 2012-07-15
  • 2014-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多