Java 在性能方面,Lambda和simple循环哪个更好?

Java 在性能方面,Lambda和simple循环哪个更好?,java,lambda,java-8,Java,Lambda,Java 8,我已经很快地阅读了文档 不过,这种例子帮助我更好地理解: //Old way: List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7); for(Integer n: list) { System.out.println(n); } //New way: List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7); list.forEach(n -> Sys

我已经很快地阅读了文档

不过,这种例子帮助我更好地理解:

//Old way:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
for(Integer n: list) {
System.out.println(n);
}

//New way:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
list.forEach(n -> System.out.println(n));


//or we can use :: double colon operator in Java 8
list.forEach(System.out::println);
//旧方法:
List=Arrays.asList(1,2,3,4,5,6,7);
for(整数n:list){
系统输出println(n);
}
//新方式:
List=Arrays.asList(1,2,3,4,5,6,7);
list.forEach(n->System.out.println(n));
//或者我们可以在Java8中使用::双冒号运算符
list.forEach(System.out::println);
不过,我不明白为什么这是一种创新。当“方法变量”结束时,它只是一个死亡的方法,对吗?为什么我要用这个而不是真正的方法?
就性能而言,哪一个是更好的选择。Lambda或简单循环。

就性能而言,普通函数比Lambda更好,因为groovy中存在与Lambda类似的闭包

这些东西的工作方式类似于,如果您为任何集合编写闭包,它将在内部创建另一个类,该类实际上对所提到的闭包或lambda表达式执行操作


但是,通过使用lambda和闭包,我可以以更好的方式进行迭代,并且可以轻松地进行调试。你可以写更少的代码行

在代码中使用lambda时,您是在告诉应该做什么,而不是如何做。上面的代码传递了一个方法参考,而不是在列表上循环,我认为lambda更符合人体工程学

就性能而言,打印100万个项目的列表几乎花费了相同的时间,但我没有在其他类型的操作中做基准测试

上面的代码是一个简单的操作,但是lambda有很多优点,因为您可以拥有可以传递的函数,使用多核(并行流)很容易等等

为什么我要用这个而不是真正的方法

你不应该。使用你更喜欢的方法


至于性能,我想,所有这些版本的速度大致相同。这里的I/O操作(
println
)比调用lambda或创建迭代器的所有可能开销都慢得多。一般来说,
forEach
可能会稍微快一点,因为它在单个方法中执行所有操作,而无需创建
迭代器
并调用
hasNext
next
(这是由for each循环隐式完成的)。无论如何,这取决于许多因素,例如调用此代码的频率、列表的长度、JIT编译器是否成功地对迭代器和/或lambda进行了反虚拟化等等。

它允许您在一行(同时具有足够的可读性)中编写以前不可能的内容。性能在这里不是问题
O(n)
停留
O(n)

例如,在我的Windows Phone应用程序中,我有会话,其中会话是表演者,我希望选择所有具有一个具体表演者的会话(就像您希望看到一些演员在其中播放的所有电影一样)。在Java1.7或更低版本中,我必须使用内部循环创建循环,检查它,如果没有执行者,则返回null等。 使用lambda表达式,我可以做到:

//performerId is parameter passed by method before
Sessions.Where(x => x.Performers.Where(y => y.PerformerId == performerId).FirstOrDefault() != null)
现在在Java中也是如此(但我现在不在从事1.8项目,我没有Java示例,但我很期待它)

运行后输出为: 我的建议是:

  • 使用你和同事认为最容易维护的风格

  • 如果您和您的同事对lambdas还不满意,请继续学习

  • 不要过分关注性能。这往往不是最重要的事情

  • 一般来说,lambdas和streams提供了一种更简洁、更可读的方式来表达这种算法。绩效不是主要目标

    如果性能确实成为一个问题,那么标准的建议是编码、测试、基准测试、评测和优化。按这个顺序做!在编码阶段进行优化,或者优化对整体应用程序性能影响最小的代码,很容易浪费大量时间

    • 让应用程序基准测试告诉您是否需要进行优化
    • 让探查器指出代码中值得优化的部分

    在这个特定的示例中,性能差异太小,无法测量。如果你放大到一个包含数百万个元素的列表,那么构建列表和写数字所需的时间将决定性能。不同的迭代方式只会对整体性能贡献一小部分


    对于那些仍然想知道使用lambda还是传统循环更快的人(尽管有上述所有内容),最好的一般答案是:

    “这取决于各种各样的因素,1)没有被很好地理解,2)随着Java编译器技术的发展,可能会发生变化


    我们可以为您提供一个关于特定Java major/minor/patch发行版的特定示例的答案,但概括起来是不明智的。

    如果您想了解lambda表达式的值,您不应该查看唯一一个具有以前存在的语言对应项的新方法。这些示例如何:

    button.addActionListener( ev -> BACKGROUND_EXECUTOR_SERVICE.execute( () -> {
       String result = longComputation();
       SwingUtilities.invokeLater( () -> label.setText(result) );
    });
    
    只要想想等价的Java 8之前的代码是什么样子,您就会发现这里的主要优势不是性能

    如果你想看看收集操作,这个如何

    map.merge(key, 1, Integer::sum);
    
    如果映射中还不存在键,则这会将
    1
    放入映射中,否则会将
    1
    添加到现有映射的值中。再次,请考虑旧映射的外观。如果映射具有适当的方法,只是一个额外的好处

    当然,
    forEach
    方法不能像for-e那样提供如此大的表现力增益
    # Run complete. Total time: 00:00:34
    
    Benchmark                                  Mode  Cnt     Score   Error  Units
    CheckLamdaPerformance.testPerDoubleColon  thrpt        776.008          ops/s
    CheckLamdaPerformance.testPerNew          thrpt       1096.423          ops/s
    CheckLamdaPerformance.testPerOld          thrpt        873.542          ops/s
    
    button.addActionListener( ev -> BACKGROUND_EXECUTOR_SERVICE.execute( () -> {
       String result = longComputation();
       SwingUtilities.invokeLater( () -> label.setText(result) );
    });
    
    map.merge(key, 1, Integer::sum);
    
    Map<ContainerOrderFocusTraversalPolicy, List<AttributedCharacterIterator>> map;
    //…
    
    map.forEach((p,l)->l.forEach(i->{ /* do your work using p and i */}));
    
    for(Map.Entry<ContainerOrderFocusTraversalPolicy, List<AttributedCharacterIterator>> e:
                                                                          map.entrySet()) {
        ContainerOrderFocusTraversalPolicy p=e.getKey();
        for(AttributedCharacterIterator i: e.getValue()) {
            /* do your work using p and i */
        }
    }
    
     // Group employees by department
     Map<Department, List<Employee>> byDept
         = employees.stream()
                    .collect(Collectors.groupingBy(Employee::getDepartment));