0

I am currently reading the book 'Java 8 in Action: Lambdas, streams, and functional-style programming' by Raoul-Gabriel Urma, Mario Fusco, and Alan Mycroft and this question is about an example which introduces to Lambda expressions in chapter 2.

Based on the text book example, I've written these Java classes.

It appears that Java 8 lambda expressions are performing worse than pre-java8 code written using anonymous inner classes.

  • Java 8 lambda - 51145201 nanos
  • Plain java - 1859449 nanos

I would like to hear your opinions, have I understood something wrong or is my test incorrect? At this moment, I am not getting motivated to proceed further with learning Java 8.

To try the examples, please copy these classes (Apple.java, Formatter.java, AppWithLambda.java and AppWithoutLambda.java) under package 'com.prash.parametarisedbehaviour' into your IDE and execute both AppX main classes.

package com.prash.parametarisedbehaviour;

public class Apple {
private String colour;
private Integer weight;

public Apple(String colour, int weight) {
    super();
    this.colour = colour;
    this.weight = weight;
}

public String getColour() {
    return colour;
}

public void setColour(String colour) {
    this.colour = colour;
}

public Integer getWeight() {
    return weight;
}

public void setWeight(Integer weight) {
    this.weight = weight;
}
}


package com.prash.parametarisedbehaviour;

public interface Formatter<T> {
String accept(T t);
}

package com.prash.parametarisedbehaviour;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;

public class AppWithoutLambda {

public static void main(String[] args) throws IOException {
    runWithoutLambda();
}

@SuppressWarnings("unchecked")
public static <T> void runWithoutLambda() throws IOException {
    long start = System.nanoTime();
    List<T> inventory = (List<T>) Arrays.asList(new Apple("red", 100), new Apple("green", 160),
            new Apple("yellow", 170), new Apple("blue", 130));
    System.out.println("Applying weight formatter...");
    prettyPrint(inventory, new Formatter<T>() {
        public String accept(T a) {
            String characteristic = ((Apple) a).getWeight() > 150 ? "heavy" : "light";
            return "A " + characteristic + " apple.";
        }
    });
    System.out.println("Applying colour formatter...");
    prettyPrint(inventory, new Formatter<T>() {
        public String accept(T t) {
            return "A " + ((Apple) t).getColour() + " apple.";
        }
    });
    long end = System.nanoTime() - start;
    System.out.println("Time taken without lambda: " + end + " nanos");
}

public static <T> void prettyPrint(List<T> inventory, Formatter<T> formatter) {
    for (T t : inventory) {
        String output = formatter.accept(t);
        System.out.println(output);
    }
}

}

package com.prash.parametarisedbehaviour;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;

public class AppWithLambda {

public static void main(String[] args) throws IOException {
    runWithLamda();
}

@SuppressWarnings("unchecked")
public static <T> void runWithLamda() throws IOException {
    long start = System.nanoTime();
    List<T> inventory = (List<T>) Arrays.asList(new Apple("red", 100), new Apple("green", 160),
            new Apple("yellow", 170), new Apple("blue", 130));
    System.out.println("Applying weight formatter...");
    prettyPrintWithStream(inventory, (T a) -> {
        String characteristic = ((Apple) a).getWeight() > 150 ? "heavy" : "light";
        return "A " + characteristic + " apple.";
    });
    System.out.println("Applying colour formatter...");
    prettyPrintWithStream(inventory, (T a) -> "A " + ((Apple) a).getColour() + " apple.");
    long end = System.nanoTime() - start;
    System.out.println("Time taken with Lambda: " + end + " nanos");

}

public static <T> void prettyPrintWithStream(List<T> inventory, Formatter<T> formatter) {
    inventory.stream().forEach((t) -> {
        String output = formatter.accept(t);
        System.out.println(output);
    });
}
}
  • How in the world does that answer my question? my question was specific to the code example in my post. –  Jan 28 '16 at 13:23
  • 4
    Your benchmark is flawed. So redirecting this question to how to do a proper benchmark is how to handle it. – Tunaki Jan 28 '16 at 13:27
  • Or, alternately, just don't worry about it. Measurements done by performance experts show that lambdas are at least as performant as inner classes, and on some measures, significantly more so. – Brian Goetz Jan 28 '16 at 13:36
  • @prashant2402 All your printing to the console takes **a lot** more time than whatever the lambda is doing - you are not measuring what you think you are measuring. And measuring timing with `Date` is not going to be very precise. And running both tests from main means that one test may affect the other. And you only run each method once, leaving no time for the JVM to warmup. Etc. – assylias Jan 28 '16 at 13:36
  • @Tunaki now those are called proper responses. when you don't know how to interpret the question, please refrain from posting useless responses. Thanks Brian and assylias. i will look at improving my examples and update –  Jan 28 '16 at 13:40
  • @assylias updated the code in my post. even after running the tests separately, replacing Date with nano yields similar results. lambda is almost 50 times slower which can't be true..have I written a very poor lambda code, can't think of a more basic example?? thanks –  Jan 28 '16 at 13:56
  • 2
    @prashant2402 most of my comments still apply - in particular the lack of proper JVM warmup. – assylias Jan 28 '16 at 14:04
  • Well, I've found the reason. this article helped me to understand [link](http://stackoverflow.com/questions/22637900/java8-lambdas-vs-anonymous-classes). lambdas will have some overhead in the initial run. So I've repeated invocations and in subsequent calls, the execution times are almost same as plain java or only slightly better. thanks all for your time though. –  Jan 28 '16 at 14:07

0 Answers0