Java 8: Testing the Lambda Water
So nearly one year to go – but as Java is developed open source now, we can have a look and try to use it right now. So let’s go!
Download and Install Lambda enabled Java 8
First, I expected that I have to compile Java 8 myself, as it has not yet been release. But I was pleasantly surprised to see, that there are binary build available for all platforms at http://jdk8.java.net/lambda/. So I just downloaded the latest developer preview build and installed it on my computer.
To make sure it works, I created an LambdaIntro class containing a “Hello, World!”, compiled and executed it:
~ $ export JAVA_HOME=~/Devtools/Java/jdk1.8.0/ ~ $ cd spikes/lambda-water ~ $ $JAVA_HOME/bin/javac src/net/jthoenes/blog/spike/lambda/LambdaIntro.java ~ $ $JAVA_HOME/bin/java -cp src net.jthoenes.blog.spike.lambda.LambdaIntro Hello from Java 8!
Note: I use the command-line to compile and execute here, because IDEs do not support Java 8 as of now.
The Non-Lambda Way
As an example lets assume I want to loop through a list of objects. But for my business logic, I need to have the value and the index of the list item. If I want to do it with current Java, I have to handle the index together with the actual logic:
List list = Arrays.asList('A', 'B', 'C'); for (int index = 0; index < list.size(); index++) { String value = list.get(index); String output = String.format('%d -> %s', index, value); System.out.println(output); }
This will output
0 -> A 1 -> B 2 -> C
This is not too bad, but I did two things in the same few lines of code: controlling the iteration and providing some (very simple) business logic. Lambda expressions can help me to separate those two.\
The eachWithIndex method signature
So I want to have a method eachWithIndex which can be called like this:
List list = Arrays.asList('A', 'B', 'C'); eachWithIndex(list, (value, index) -> { String output = String.format('%d -> %s', index, value); System.out.println(output); } );
The method receives two parameter. The first one is the list and the second one is a lambda expression or closure which instructs the method what to do with each list item. As you can see in line 3, the lambda expression receives two argument: the current value und the current index. These arguments do not have a type declaration. The type information will be inferred by the Java 8 compiler. After the arguments, there is a -> and a block of code which should be executed for every list item.
Note: You will have to write this method in a normal text editor or ignore the error messages inside your IDE.
Implement the eachWithIndex method
To use a lambda in Java 8, you need to declare a functional interface. A functional interface is an interface which has exactly one method – the method which will be implemented by the lambda expression. In this case, I need to declare a method which receives an item and an index and returns nothing. So I define the following interface:
public static interface ItemWithIndexVisitor<E> { public void visit(E item, int index); }
With this interface I can now implement the eachWithIndex method.
public static <E> void eachWithIndex(List<E> list, ItemWithIndexVisitor<E> visitor) { for (int i = 0; i < list.size(); i++) { visitor.visit(list.get(i), i); } }
The method makes use of the generic parameter <E>, so the item passed to the visit method will be inferred to be of the same type than the list.
The nice thing about using functional interfaces is, that there are a lot of them already out there in Java. Think for example of the java.util.concurrent.Callable interface. It can be used as a lambda without having to change the code which consumes the Callable. This makes a lot of the JDK and frameworks lambda enabled by default.
Using a method reference
One little handy thing coming from Project Lambda are method references. They are a way, to re-use existing methods and package them into a functional interface object. So let’s say I have the following method
public static <E> void printItem(E value, int index) { String output = String.format('%d -> %s', index, value); System.out.println(output); }
and I want to use this method in my eachWithIndex method, than I can use the :: notation inside my method call:
eachWithIndex(list, LambdaIntro::printItem);
Looks nice and concise, doesn’t it?
Summary
This makes my first lambda example run. I couldn’t avoid a smile on my face to see closures running in one of my Java program after longing for them so long. Lambda Expression are currently only available as a developer preview build. If you want to find out more, read the current Early Draft Review or go to the Project Lambda project page.
I uploaded the full example code to gist.
Reference: Java 8: Testing The Lambda Water from our JCG partner Johannes Thoenes at the Johannes Thoenes blog blog.
This would be one line in java 8 (:p)
list.forEach((item)-> System.out.println(String.format(“%d -> %s”, list.indexOf(item),item)));