java 8 lambda Predicate<Integer> 我做错了什么?
What am i doing wrong with java 8 lambda Predicate<Integer>?
不是我的问题的重复。我检查了一下,我的是如何使用 proper Predicate,THAT 是关于 removeIf 和 remove.
之间的区别
我是初学者 Java 程序员。
昨天,我尝试按照本教程进行操作 https://dzone.com/articles/why-we-need-lambda-expressions
在学会了Lambda表达式和Predicate的使用后,我自己写代码练习
比如,对所有数字求和 if(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 循环要慢。
我不知道为什么会这样。
我究竟做错了什么?或者只是谓词使用起来太慢了?
首先我们来看事物的尺度。您说的是 100000000 个项目的差异大约为 1505 毫秒,或者每个项目大约 15 纳秒。开销不是很大。
也就是说,开销是为了 Predicate<Integer>
而将所有这些 int
自动装箱到 Integers
中。 Predicate::test
需要一个 Integer
,所以 p.test(i)
实际上被编译为 p.test(Integer.valueOf(i))
。这种方法不是超级昂贵,但它不是免费的。显然在您的计算机上大约需要 15 纳秒。
如果您改用 IntPredicate
— 它使用 int
原语作为输入,从而避免装箱 — 您会发现直接方法和基于 lambda 的方法之间的区别几乎消失了。
除此之外,Java 中还有关于微基准测试的常见警告(预热循环,使用 JMH 等框架等)。关于该主题有丰富的知识,如果您想继续像这样对快速操作进行基准测试,我强烈建议您阅读它。
性能和 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
我是初学者 Java 程序员。
昨天,我尝试按照本教程进行操作 https://dzone.com/articles/why-we-need-lambda-expressions
在学会了Lambda表达式和Predicate的使用后,我自己写代码练习
比如,对所有数字求和 if(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 循环要慢。
我不知道为什么会这样。
我究竟做错了什么?或者只是谓词使用起来太慢了?
首先我们来看事物的尺度。您说的是 100000000 个项目的差异大约为 1505 毫秒,或者每个项目大约 15 纳秒。开销不是很大。
也就是说,开销是为了 Predicate<Integer>
而将所有这些 int
自动装箱到 Integers
中。 Predicate::test
需要一个 Integer
,所以 p.test(i)
实际上被编译为 p.test(Integer.valueOf(i))
。这种方法不是超级昂贵,但它不是免费的。显然在您的计算机上大约需要 15 纳秒。
如果您改用 IntPredicate
— 它使用 int
原语作为输入,从而避免装箱 — 您会发现直接方法和基于 lambda 的方法之间的区别几乎消失了。
除此之外,Java 中还有关于微基准测试的常见警告(预热循环,使用 JMH 等框架等)。关于该主题有丰富的知识,如果您想继续像这样对快速操作进行基准测试,我强烈建议您阅读它。
性能和 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