关于for循环:java 8 lambda Predicate< Integer&gt ;?我做错了什么

What am i doing wrong with java 8 lambda Predicate<Integer>?

本问题已经有最佳答案,请猛点这里访问。

这不是我问题的副本。我检查过它,我的是如何使用适当的谓词,这是关于removeif&remove之间的区别。

我是初学者Java程序员。昨天,我试着遵循本教程https://dzone.com/articles/why-we-need-lambda-expressions在我学习了如何使用lambda表达式和谓词之后,我编写了自己的代码来练习。例如,如果(n%3==0 n%5==0),则对所有数字求和。这是我的密码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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);
}
}

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

1
2
3
4
Total execution time conv: 1761
Total execution time lambda: 3266

lambda / conv : 1.8546281

如您所见,带有谓词的lambda表达式比简单的for循环慢。我不知道为什么结果是这样的。我做错什么了?或者只是谓词的使用速度太慢?


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

也就是说,开销来自于为了Predicate,把所有这些int自动氧化成IntegersPredicate::testInteger,所以p.test(i)实际上被编译成p.test(Integer.valueOf(i))。这种方法并不昂贵,但也不是免费的。显然,你的电脑需要15纳秒。

如果您使用一个IntPredicate,它使用一个int原语作为输入,从而避免装箱,您会发现直接方法和基于lambda的方法之间的差异实际上已经消失了。

除此之外,还有一些关于Java中的微标杆的警告(热身循环,使用像JMH之类的框架)。关于这个主题有很多知识,如果你想继续以这样的快速行动为基准,我强烈建议你读一读。


性能和lambda可能很棘手。在您的例子中,使用包装类型integer和自动装箱会减慢速度。

开关

1
public long sumAllLambda(Predicate<Integer> p)

1
public long sumAllLambda(IntPredicate p)

结果几乎相同

1
2
3
Total execution time conv: 3190
Total execution time lambda: 3037
lambda / conv : 0.95203763