This is not a duplicate of my question. I checked it and mine is how to use proper Predicate, and THAT is about differences between removeIf & remove.
I'm beginner Java programmer.
Yesterday, I tried to follow this tutorial https://dzone.com/articles/why-we-need-lambda-expressions
After I leared how to use Lambda expressions and Predicate, I made my own code to practice.
like, sum all numbers if(n % 3 == 0 || n % 5 == 0).
here is my code.
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);
}
}
In this code, did timing tests.
and result is like this.
Total execution time conv: 1761
Total execution time lambda: 3266
lambda / conv : 1.8546281
As you can see, lambda expression with predicate is slower than simple for-loop.
I have no idea why does the result like this.
What am I doing wrong? or just predicate is too slow way to use?
First of all, let's look at the scale of things. You're talking about a difference of about 1505 ms for 100000000 items, or about 15 nanoseconds per item. That overhead is not very substantial.
That said, the overhead is from autoboxing all those int
s into Integers
for the sake of the Predicate<Integer>
. Predicate::test
takes an Integer
, so p.test(i)
is really getting compiled down to p.test(Integer.valueOf(i))
. That method isn't super duper expensive, but it's not free. Apparently it takes about 15 nanoseconds on your computer.
If you use an IntPredicate
instead — which uses an int
primitive as its input, and thus avoids the boxing — you'll find that the difference between the direct and lambda-based approach is virtually gone.
Aside from that, there are the usual warnings about microbenchmarking in Java (warmup loops, using a framework like JMH, etc). There is a wealth of knowledge out there about that subject, and I strongly encourage you to read up on it if you want to continue benchmarking quick actions like this.
Performance and lambda can be tricky. In your case the use of wrapper type Integer and auto boxing slow down stuff.
Switch
public long sumAllLambda(Predicate<Integer> p)
to
public long sumAllLambda(IntPredicate p)
the results are almost the same
Total execution time conv: 3190
Total execution time lambda: 3037
lambda / conv : 0.95203763
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With