【问题标题】:Modify list - stream approach修改列表-流方法
【发布时间】:2019-06-30 14:27:33
【问题描述】:

我想修改流中已创建对象的列表。我意识到三种方法可以做到这一点,但我不确定它们的性能和可能的缩小尺寸。

  1. 返回相同的对象 - 创建新对象不会浪费时间,但对象是可变的
  2. 创建新对象 - 参数未修改,但创建大型对象非常耗时
  3. 修改参数-只能使用ForEach,不能并行使用

代码下面的代码解释了 cmets。

public class Test {

    public static void main(String[] args) {
        //Already created objects
        List<Foo> foos0 = Arrays.asList(new Foo("A"));

        //However I need to apply some modification on them, that is dependent on themselves

        //1. Returning same object
        List<Foo> foos1 = foos0.stream().map(Test::modifyValueByReturningSameObject).collect(Collectors.toList());

        //2. Creating new object
        List<Foo> foos2 = foos0.stream().map(Test::modifyValueByCreatingNewObject).collect(Collectors.toList());

        //3. Modifying param
        foos0.stream().forEach(Test::modifyValueByModifyingParam);
    }

    //Lets imagine that all methods below are somehow dependent on param Foo
    static Foo modifyValueByReturningSameObject(Foo foo) {
        foo.setValue("fieldValueDependentOnParamFoo");
        return foo;
    }

    static Foo modifyValueByCreatingNewObject(Foo foo) {
        Foo newFoo = new Foo("fieldValueDependentOnParamFoo");
        return newFoo;
    }

    static void modifyValueByModifyingParam(Foo foo) {
        foo.setValue("fieldValueDependentOnParamFoo");
        return;
    }
}

public class Foo {

    public String value;

    public Foo(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }

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

那么问题是哪种方法最流畅?

编辑: 我所说的流方法是指性能方面的最大优势。

编辑2: 1. 哪个是函数式方法? 2. 哪一个在性能方面最好?

【问题讨论】:

  • 您能解释一下“大多数流方法”吗?注意:您也可以执行等效的for 循环,并且仍然具有足够的性能。用什么来定义性能?此外,案例 2 在功能上与案例 1 不同。
  • 答案似乎是 1。对于 2。人们会期望 flatMap / 一个子集结果。
  • 使用蒸汽时的最佳性能。
  • 最“实用”的方法依赖于不变性,因此创建新对象而不是修改现有对象。理想情况下,Streams 不应该有副作用。
  • 我想我会把它移到代码审查中

标签: java performance arraylist functional-programming java-stream


【解决方案1】:

javadoc 声明 Streams 应该避免副作用:

通常不鼓励对流操作的行为参数产生副作用,因为它们通常会导致无意中违反无状态要求以及其他线程安全隐患。

因此,您应该更喜欢创建新对象而不是修改现有对象的解决方案。

【讨论】:

    【解决方案2】:

    在您的情况下,不同的方法很可能不会导致性能差异。

    原因:优化。 Java 不会真正创建新类,而是使用对字段的直接访问。它可能(并且如果分析建议它会)甚至跳过整个调用链并将其替换为预先计算的值。 Java 运行时甚至利用分析器来优化和查找热点...

    另外:关于性能,通常(特定情况可能不同)更重要的是创建一个简单的结构并帮助运行时做出正确的假设。 因此,如果您在不合理的手动“优化”中隐藏您正在做的事情,这会在运行时隐藏优化可能性(大量分支/决策、不必要的固定、“未知”方法链......),您最终可能会得到较慢的结果.

    为了清晰和副作用(另见其他答案),我宁愿使用创建新实例的版本。

    【讨论】:

      猜你喜欢
      • 2015-11-27
      • 2020-07-22
      • 2011-06-12
      • 2014-06-22
      • 1970-01-01
      • 2021-10-19
      • 1970-01-01
      • 2020-04-13
      • 2022-07-03
      相关资源
      最近更新 更多