Java 8: Testing the Lambda Water

Java 8 is about a year away and comes with a language feature I really look forward to: Lambda Expression. Sadly the other big feature, Modules for the Java Platform, has been delayed to Java 9. But nevertheless, bringing lambda expressions (or closures if you like) into the language will make programming in Java much better.

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.

flattr this!

22 thoughts on “Java 8: Testing the Lambda Water

  1. Pingback: F’n A -> Lambda in Java | Daniel Moore

  2. Why are your interfaces explicitly static? Interfaces even inner ones are static anyway (until J7 at least) – is this your way of writing code or is there something more to this?

  3. This got me excited, so I downloaded and tried out the 1.8 lambda preview. Sadly, true closures are not supported (not sure if this is on the roadmap at all). This is as disappointing as type erasure was, for me.

    Simplistic example:

    public static int sum(String[] args, IntMapper summer) {
    int sum = 0;

    Arrays.asList(args).forEach((item) -> {
    sum += summer.map(item);
    });

    return sum;
    }

    Gives the compile time error:
    local variables referenced from a lambda expression must be ‘effectively final’

    Bummer :-(

  4. This seems like way too much work for a drop in anonymous function. The worst part is it has to conform to an interface, which narrows the flexibility of usage.

  5. @Alexander Shopov
    I was not aware of the fact the fact, that inner interfaces are implicitly static – although it makes sense, when I think about it. I usually don’t use static interfaces in my normal code – that’s probably why I didn’t know it. Thanks for pointing it out!

  6. @Mike Virata-Stone

    Yes, this is true. Your variables have to be effectively final. As far as I know, they are not going to change this as for now. I would have to research why it is so.

    Your example could for example be solved this way:

    public static int sum(String[] args, IntMapper summer) {
    return Arrays.asList(args).map(summer::map).reduce(0,
    (sum, value) -> sum + value);
    }

    or even this way:

    return Arrays.asList(args).map((s) -> s.length()).reduce(0,
    (sum, value) -> sum + value);

  7. To be honest, the lambda syntax of Java 8 is a bit disappointing. Scala and Groovy (not to mention Clojure) are also JVM languages, but in these language much less boilerplate code is necessary than in Java 8.

    Honestly, what is the difference between a lambda function if you need to define an explicit interface first and an anonymous class?

  8. @gefei

    Honestly, what is the difference between a lambda function if you need to define an explicit interface first and an anonymous class?

    1. You don’t have to write the new XYZ(){…} stuff and you omit the method declaration.
    2. You don’t have the difference in the semantics of this. Because function interfaces are just interfaces this refers to the class itself.
    3. You have the notion of effective final. You don’t need to define local variables final to use them inside lambdas. The can be mutable outside the lambda, but are effective final inside the lambda.

    Generally speaking I see you point. If I would start a new project, I would certainly consider using Scala or another less verbose language. But you don’t always have the choice (for different reasons depending on your context).

  9. @Johannes

    I way not saying we should switch to Scala or Groovy from Java. I just wanted to say that Java 8 lambda functions are unnecessarily verbose. They might also have done what the Scala guys have done :)

  10. @gefei

    If I remember correctly, they were thinking of introducing function types in a later version of Java – the idea is not gone, as far as I know. But they start with functional interfaces, because this does not require all the Java frameworks out there to change their APIs.

    To be more concrete. In Scala you have (to my just-learning-Scala knowlegde) to do this:

    val button: JButton = new JButton()
    button.addActionListener(new ActionListener {
    def actionPerformed(e: event.ActionEvent) {
    print("Hello, World!")
    }
    })

    Using functional interfaces with Java 8, you can as well do this:

    JButton button = new JButton();
    button.addActionListener(e -> System.out.println("Hello, World!"));

    This is why they want to make it work with functional interfaces first. To me, this seems like a good transition strategy.

  11. @Johannes Thönes Actually, Scala defines its own swing wrapper which defines the event handling a bit different, by actually using a partial function. In scala.swing your example would be more like this:

    val button = new Button {
    reactions += {
    case ButtonClicked(b) => println("Hello, World!")
    }
    }

    Collections make for a better comparison and here, Scala already does quite similar to Java:

    val nums = 1 to 10
    nums foreach(p => println(p))
    //or for brevity:
    nums foreach println

  12. To show off how you would implement eachWithIndex() in Scala: The type system basically covers the interface declaration for you and you’d just write:

    def eachWithIndex[T](l: List[T], f: (T, Int) -> Unit) {
    for {(t, i) <- l.zipWithIndex} f(t, i)
    }

  13. @Mike Virata-Stone: the purely functional map and fold (aka map and reduce) approach Johannes replied with is much safer than closing allowing a closure to rewrite stack references. If you were to close over mutable references in a parallel execution of your code it would do very strange things… rarely and non-deterministically. It would do these things at the most inopportune times (in production at 3AM) and then be very hard to reproduce for a bug fix.

    I sincerely hope that Java will never support closures that mutate stack references.

    Closing over mutable state (ie references to mutable data structures like ArrayList) is hard to prevent, but allowing a closure to rewrite references on the stack is a very bad idea.

  14. So java lambda’s are just a syntatic sugar over

    Thread t = new Thread(new Runnable() {
    public void run() {
    System.out.println("running");
    }
    })

    Well, i find that awful. Also, if you are stuck with Java, you’ve got to wait for Java 8 to get widely deployed. I’d stick to Groovy, given the enhancements.

  15. I’m kinda excited about the implementation … There are some concrete examples @http://www.infoq.com/articles/java-8-vs-scala such as …


    List photos = Arrays.asList(...)
    List output = photos.filter(p -> p.getSizeInKb() > 10000)
    .map(p -> p.name)

  16. Pingback: Java 8: Lambda Expression « Coding Madness

  17. I’m still not sure this is solving a problem that isn’t worth solving. Any of us can accomplish the same tasks without closures, and it’s just not that much extra work. One thing these new language features are doing is adding complexity. For an experienced Java programmer, it’s one more thing to learn, but for someone new, it’s another mountain to scale. Generics were a good example of that. Yes, they solved a problem, but only by creating the most complex part of the language. In this quest for simplicity, Java is turning into C++.

  18. Adam: I disagree. I’m coming from C# where closures have been a part of the language for a couple of years now. I admin that it indeed was a mountain to scale, but when you’ve done it you don’t want to go back. Right now I’m coding Java again and the single thing I miss most are closures. Why? I’d say it really boils down to this:

    It makes your code more readable.

    Operations you previously needed 4 lines of code and a nested blocks to write, you now do in one single line of code. You rid of the noise and is left with business logic. That is good for readability which is good for maintainability which is increases the quality of your product.

  19. Adam: Why Java introduce Lambda is because it can run parallell on multicore processors.

  20. I’m wondering about the impact of lambdas in Java on unit-testing. While for simple things (using lambdas to replace boilerplate class junk where the real logic is only one or two lines of code) it looks great and has no conflict with unit-testing… what about when the lambdas get complicated?

    Does that start making unit-tests *more* difficult? If I can’t get a handle on the logic in the lambda, how do I test it?

    It seems like there may be some tension between the desire to write easier-to-write-(and-read?) code, and testability of the same code. I’m not convinced in either direction yet, but I’d like to hear more about it.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>