【问题标题】:What am i doing wrong with java 8 lambda Predicate<Integer>? [duplicate]java 8 lambda Predicate<Integer> 我做错了什么? [复制]
【发布时间】:2016-03-22 04:07:28
【问题描述】:

This 不是我的问题的重复。我查了一下,我的是如何使用 proper Predicate,而 THAT 是关于 removeIf 和 remove 之间的区别。

我是初学 Java 程序员。
昨天,我尝试按照本教程进行操作https://dzone.com/articles/why-we-need-lambda-expressions
在我学会了如何使用 Lambda 表达式和 Predicate 之后,我编写了自己的代码来练习。
比如,如果(n % 3 == 0 || n % 5 == 0),求和所有数字。 这是我的代码。

public class Euler1Lambda {
    long max;
    public Euler1Lambda(long max) {
        this.max = max;
    }
public static boolean div3remainder0(int number) {
    return number % 3 == 0;
}

public static boolean div5remainder0(int number) {
    return number % 5 == 0;
}

public long sumAll() {
    long sum = 0;
    for(int i=1; i<max; i++) {
        if (div3remainder0(i) ||div5remainder0(i)) {
            sum += i;
        }
    }
    return sum;
}

public long sumAllLambda(Predicate<Integer> p) {
    long total = 0;
    for (int i = 1; i< max; i++){
        if (p.test(i)) {
            total += i;
        }
    }
return total;
}

public static void main(String[] args) {
    //conv
    long startTime = System.currentTimeMillis();
    for(int i = 0; i < 10; i++){
        new Euler1Lambda(100000000).sumAll();
    }
    long endTime = System.currentTimeMillis();
    long conv = (endTime - startTime);
    System.out.println("Total execution time: " + conv);
    //lambda
    startTime = System.currentTimeMillis();
    for(int i = 0; i < 10; i++){
        new Euler1Lambda(100000000).sumAllLambda(n -> div3remainder0(n) || div5remainder0(n));
    }
    endTime = System.currentTimeMillis();
    long lambda = (endTime - startTime);
    System.out.println("Total execution time: " + lambda);
    System.out.println("lambda / conv : " + (float)lambda/conv);
}
}

在这段代码中,进行了计时测试。 结果是这样的。

Total execution time conv: 1761
Total execution time lambda: 3266

lambda / conv : 1.8546281

如您所见,带有谓词的 lambda 表达式比简单的 for 循环慢。
我不知道为什么会这样。
我究竟做错了什么?还是只是谓词太慢了?

【问题讨论】:

    标签: java for-loop lambda java-8 predicate


    【解决方案1】:

    首先,让我们看看事物的规模。您说的是 100000000 个项目的差异约为 1505 毫秒,或每个项目约 15 纳秒。这个开销不是很大。

    也就是说,开销是为了Predicate&lt;Integer&gt;,将所有ints 自动装箱到IntegersPredicate::test 接受Integer,所以p.test(i) 真的被编译成p.test(Integer.valueOf(i))。这种方法不是超级昂贵,但它不是免费的。显然,在您的计算机上大约需要 15 纳秒。

    如果您改用 IntPredicate — 它使用 int 原语作为其输入,从而避免了装箱 — 您会发现直接方法和基于 lambda 的方法之间的区别几乎消失了。

    除此之外,还有一些关于 Java 中的微基准测试的常见警告(预热循环、使用 JMH 等框架等)。关于该主题有丰富的知识,如果您想继续对此类快速操作进行基准测试,我强烈建议您阅读它。

    【讨论】:

    • 非常感谢。 :) 这个答案真的很有帮助。我会尝试更多地了解 Java 中的微基准测试。
    • 我猜,如果有足够的预热,任何一种情况下的差异都会消失,因为执行时间会收敛到零(提示:在所有情况下,整个操作都是无副作用的,其结果不会在任何地方使用) …
    【解决方案2】:

    性能和 lambda 可能很棘手。在您的情况下,使用包装器类型 Integer 和自动装箱会减慢速度。

    切换

    public long sumAllLambda(Predicate<Integer> p) 
    

    public long sumAllLambda(IntPredicate p) 
    

    结果几乎一样

    Total execution time conv: 3190
    Total execution time lambda: 3037
    lambda / conv : 0.95203763 
    

    【讨论】:

    • 这个简单的代码也帮助我解决了一个问题。非常感谢:)
    猜你喜欢
    • 2019-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-29
    • 2012-07-07
    • 2016-03-04
    • 2013-06-28
    • 2016-05-26
    相关资源
    最近更新 更多