Imagine a bacon-wrapped Ferrari. Still not better than our free technical reports.
See all our reports

Java 8: The First Taste of Lambdas

UPDATE: Since releasing this post, we’ve published a full RebelLabs report entitled Java 8 Revealed: Lambdas, Default Methods and Bulk Data Operations. Click on the button below to get the full report!

Get the complete RebelLabs report



Project Lambda is the major theme in the upcoming Java 8 and probably the most awaited one among Java developers. There’s one interesting feature that is being added to Java along with lambdas – the defender methods. In this blog post my intention is to look under the covers – to see how lambdas are represented by the runtime and what bytecode instructions are involved during method dispatch.

Although Java 8 is yet to be released it is still possible to get a taste of what it will look like by downloading the early access binaries for all the target platforms.

So you want to use lambdas, huh?

If you are familiar with other languages that include lambda expressions, such as Groovy or Ruby, you might be surprised at first that it is not as simple in Java. In Java, lambda expression is “SAM type”, which is an interface with a single abstract method (yes, interfaces can include non-abstract methods now – the defender methods).

So for instance the well known Runnable interface is perfectly suitable for serving as a SAM type:

Runnable r = () -> System.out.println("hello lambda!");

Or the same could be applied to the Comparable interface:

Comparator<Integer> cmp = (x, y) -> (x < y) ? -1 : ((x > y) ? 1 : 0);

The same can be written as follows:

Comparator<Integer> cmp = (x, y) -> {
  return (x < y) ? -1 : ((x > y) ? 1 : 0);
};

So it seems like the one-liner lambda expressions have implicit return for the statement.

What if I want to write a method that can accept a lambda expression as a parameter? Well, you have to declare the parameter as a functional interface, and then you can pass the lambda in:

interface Action {
   void run(String param);
}
 
public void execute(Action action){
   action.run("Hello!");
}

Once we have a method that takes a functional interface as a parameter we can invoke it as follows:

execute((String s) -> System.out.println(s));

Effectively, the same expression can be replaced with a method reference since it is just a single method call with the same parameter:

execute(System.out::println);

However, if there’s any transformations going on with the argument, we can’t use method references and have to type the full lambda expression out:

execute((String s) -> System.out.println("*" + s + "*"));

I think the syntax is rather nice and we now have quite an elegant solution for lambdas in the Java language despite the fact Java doesn’t have functional types per se.

Functional interfaces in JDK8

As we learned, the runtime representation of a lambda is a functional interface (or a “SAM type”), an interface that defines only one abstract method. And although JDK already includes a number of interfaces, like Runnable and Comparable, that match the criteria, it is clearly not enough for API evolution. It just wouldn’t be as logical if we started using Runnables all around the code.

There’s a new package in JDK8, java.util.function, that includes a number of functional interfaces that are intended to be used by the new API. We won’t list all of them here – just do yourself a favour and study the package yourself :)

It seems that the library is evolving quite actively as some interfaces come and go. For instance it used to provide java.util.function.Block class which isn’t present in the latest build that I have at the time of writing this post:

anton$ java -version
openjdk version "1.8.0-ea"
OpenJDK Runtime Environment (build 1.8.0-ea-b75)
OpenJDK 64-Bit Server VM (build 25.0-b15, mixed mode)

As I discovered it is now replaced with Consumer interface and is used for all the new methods in the collections library. For instance, the Collection interface defines the forEach method as follows:

public default void forEach(Consumer<? super T> consumer) {
  for (T t : this) {
    consumer.accept(t);
  }
}

The interesting bit of the Consumer interface is that it actually defines one abstract method – accept(T t), and a defender method – Consumer<T> chain(Consumer<? extend T> consumer). It means that it is possible to chain the calls using this interface. I’m not quite sure how it will be used since I couldn’t find chain(..) method usages in the JDK library yet.

Also, I noticed that all the interfaces are marked with @FunctionalInterface runtime annotation. But aside its runtime presence the annotation is used by javac to verify if the interface is really a functional interface and there’s no more than one abstract method in it.

So if I try to compile code like this

@FunctionalInterface
interface Action {
  void run(String param);
  void stop(String param);
}

The compiler will tell me:

java: Unexpected @FunctionalInterface annotation
  Action is not a functional interface
	multiple non-overriding abstract methods found in interface Action

While the following will compile just fine:

@FunctionalInterface
interface Action {
  void run(String param);
  default void stop(String param){}
}

Decompiling lambdas

I’m usually not as curious about the syntax and language features as I am about the runtime representation of those features. That is why one natural thing for me was to grab my favourite javap utility and start reading the bytecode of the classes that include lambdas.

Currently (as of Java 7 and before), if you wanted to emulate lambdas in Java, you have to define an anonymous inner class. This results in a dedicated class file after compilation. And if you have multiple such classes defined in the code they just get a number suffix in the name of the class file. What about lambdas?

Consider code like this:

public class Main {
 
  @FunctionalInterface
  interface Action {
    void run(String s);
  }
 
  public void action(Action action){
    action.run("Hello!");
  }
 
  public static void main(String[] args) {
    new Main().action((String s) -> System.out.print("*" + s + "*"));
  }
 
}

The compilation produces two class files: Main.class and Main$Action.class, and no numbered class which would usually appear for the anonymous class implementation. So there must be something in Main.class now that represents the implementation of the lambda expression that I’ve defined in main method.

$ javap -p Main 

Warning: Binary file Main contains com.zt.Main
Compiled from "Main.java"
public class com.zt.Main {
  public com.zt.Main();
  public void action(com.zt.Main$Action);
  public static void main(java.lang.String[]);
  private static java.lang.Object lambda$0(java.lang.String);
}

Aha! There’s a generated method lambda$0 in the decompiled class! The -c -v switches will give us the real bytecode along with the constants pool definitions.

The main method reveals that invokedynamic is now issued to dispatch the call:

public static void main(java.lang.String[]);
  Code:
   0: new               #4    // class com/zt/Main
   3: dup          
   4: invokespecial #5        // Method "":()V
   7: invokedynamic #6,  0    // InvokeDynamic #0:lambda:()Lcom/zt/Main$Action;
   12: invokevirtual #7       // Method action:(Lcom/zt/Main$Action;)V
   15: return        

And in the constant pool it is possible to find the bootstrap method that links it all at runtime:

BootstrapMethods:
  0: #40 invokestatic java/lang/invoke/LambdaMetafactory.metaFactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
  Method arguments:
    #41 invokeinterface com/zt/Main$Action.run:(Ljava/lang/String;)Ljava/lang/Object;
    #42 invokestatic com/zt/Main.lambda$0:(Ljava/lang/String;)Ljava/lang/Object;
    #43 (Ljava/lang/String;)Ljava/lang/Object;

You can see that MethodHandle API is used all around but we won’t dive in this right now. For now we can just confirm that the definition refers to the generated method lambda$0.

I was curious, what if I define my own static method with the same name – “lambda$0″ is a valid identifier after all! So I defined my own lambda$0 method:

public static Object lambda$0(String s){ return null; }

With this compilation failed, not allowing me to have this method in the code:

java: the symbol lambda$0(java.lang.String) conflicts with a 
           compiler-synthesized symbol in com.zt.Main

At the same time, if I removed the piece of code that defined lambda expression, the code compiled just fine. It actually tells us that lambdas are captured before the other structured in the class during the compilation, but that’s only my assumption.

Please note that in this example the lambda did not capture any of the variables and did not refer to any methods of the enclosing class. That is why the generated lambda$0 method is static. If the lambda refers to any of the enclosing context variables or methods, then a non-static method is generated. So don’t be mislead by the simple example – lambdas can capture enclosing context just fine!

Summary

We can definitely say that lambdas and the accompanied features (defender methods, collections library improvements) will have a great impact on Java very soon. The syntax is quite nice and once developers realize that these features provide value to their productivity, we will see a lot of code that leverages these features.

It was quite interesting for me to see what lambdas are compiled to and I was very happy when I saw the total utilization of the invokedynamic instruction in action without any anonymous inner classes involved at all.

Get the complete RebelLabs report

  • johndurbinn

    Java is such a fucking mess

  • http://zeroturnaround.com Jevgeni Kabanov

    I would have actually liked more in-depth on how lambda$0 is instantiated as Main$Action :(

  • arhan

    It would take me another 10 pages to write about the method handles :) Maybe next time.

  • arhan

    Which language is your favorite then?

  • http://www.facebook.com/mikeylove Michael DeFreitas

    Great overview! Thanks for the tour!

  • http://davidchambersdesign.com/ David Chambers

    The icons on the left which lag behind as one scrolls up and down the screen are very distracting.

  • Z

    It’s “moral”, not “morale”.

  • Daniel Varab

    100 bucks he says Scala :D Cheers for the look through. One weird thing I actually find annoying is the “->” notation instead of =>…1. world problem.

  • arhan

    :D I think it is a matter of taste which depends on the phase of the Moon. I used to like => but recently changed my mind and now I like -> more

  • arhan

    Thanks

  • http://twitter.com/t4ffer Erkki Lindpere

    -> is based on mathematical notation so it is better than => :)

  • grandfatha

    Open Firebug -> Remove HTML -> Read article :)

  • arhan

    Or one can use Clearly plugin in Chrome to copy the content into Evernote. I do that with articles which I don’t want to loose.

  • http://twitter.com/gfrison Giancarlo Frison

    copied from Groovy

  • arhan

    Languages seem to copy each other quite often. That’s not bad. Learning from each other is good.

  • http://twitter.com/ladislavGazo Ladislav Gazo

    is there a version of JRebel that supports JDK8 already? I have tried it but it failed upon starting the agent…

  • arhan

    Could you send the exception/thread dump/jrebel.log to our support for that? we have tested with in with previous builds of JDK8, but as this evolves our integration might be a bit outdated.

  • http://devtalk.net Dmitri

    Coming from a C# world, I must admit this is all really weird. For example, a lambda is an interface with a single abstract method…. what? How does this even make sense? First of all, interfaces, as far as I know, cannot really have either abstract or non-abstract methods. Interfaces are just contracts, they define a set of methods (and properties, which Java does not have) that implementors use. Second, why on earth do you need an interface to define something that’s essentially a function pointer? Why not just define a lambda as a pointer to a function which takes certain parameters and returns a particular type of value? Also, the -> operator is actually pointer deref, so using it instead of => as was planned is very strange though I guess since Java doesn’t have pointers, people don’t see this as a problem.

  • arhan

    Interfaces as lambda representation is a bit WAT to everyone who have tried lambdas before in any other language, not only C#. As the article mentions, interfaces can have default methods which are referred as “defenders”. That is required for library evolution, otherwise adding new methods to the collections interfaces would break backwards compatibility which is a big thing in Java.
    There’s no pointers in Java and therefore no pointer dereference also. Hence thin arrow looks even more natural than the fat arrow, but imo that’s a matter of taste.

  • http://devtalk.net Dmitri

    Java just needs delegates or first-class functions. This whole ‘interface’ business is alien to me, I just don’t get *why* one would go to the trouble of… ah wait, backward-compatibility, right?

  • arhan

    Correct. Backwards compatibility is the curse. Sure it looks like first-class functions would be the right thing to do. And obviously the fathers of Java know about that too.

  • http://twitter.com/gfrison Giancarlo Frison

    Sure, but jcp is already too late. Anyway, better now than never

  • http://freemusicformormons.com/lds-ward-choir-music roger pack

    Is there a multi line lambda option?

  • arhan

    Yes. Here’s an example:

    Comparator cmp = (Integer x, Integer y) -> {
    int number = (x > y) ? one : zero;
    return (x < y) ? minus_one : number;
    };

  • http://twitter.com/ladislavGazo Ladislav Gazo

    done

  • Brett Ryan

    In Safari I just “Right Click Element > Inspect Element” then right-click the element in the inspector and “Delete”.

  • Brett Ryan

    I prefer -> as I find hitting = take more time when typing. Though => would have been more consistent with C#, not that that makes a difference though.

  • Brett Ryan

    Backwards compatibility is not the only reason for virtual extension methods (previously known as defender methods). The lambda team did originally going down the static extension method path though found it too restrictive such as not being able to be overridden. If static extension methods were used as in the original spec it may look a whole lot different, and be more akin to how C# handles lambdas, though of course inheriting the same limitations.

    You may also want to examine how a lambda expression in C# gets compiled down to MSIL also, you might find yourself asking similar questions of C#.

  • Brett Ryan

    Note that while the parser has been added to javac and available in the latest JDK8 builds the library additions are still only available in the lambda builds (http://jdk8.java.net/lambda/). Looking forward to this being merged in, should be soon.

  • http://www.facebook.com/sergey.chunayev Sergey Chunayev

    I wish it were the case with Java. But honestly I’m disappointed they simply didn’t copy it from Groovy.
    Why does it have to be so messy with parenthesis?
    Compare this: execute((String s) -> System.out.println(“*” + s + “*”));
    To this: execute(String s -> System.out.println(“*” + s + “*”));
    In the worst case to this: execute({String s -> System.out.println(“*” + s + “*”)});

    Or the example from above:

    Comparator cmp = (Integer x, Integer y) -> {
    int number = (x > y) ? one : zero;
    return (x < y) ? minus_one : number;
    };

    Could have been written much eye-friendly:

    Comparator cmp = {Integer x, Integer y ->
    int number = (x > y) ? one : zero;
    return (x < y) ? minus_one : number;
    };

    Less typing. Less parenthesis. Easier to read and understand what's going on in the code.
    But no. They just desperately assumed developers will be happy to use parenthesis more and more.

  • arhan

    Honestly, I don’t see any big heartbreaking difference.

    In the example with comparator you claim to do less typing? Where? How much less? You got rid of two braces – that’s it. Not a big thing.

  • http://www.facebook.com/sergey.chunayev Sergey Chunayev

    2 braces here, 2 braces there and you suddenly you realize you have to read tons of braces in order to understand the code. Imagine if you have chain of 5 lambdas. That’s already 10 braces more your brain needs to skip mentally. Given same characteristics of the code, why you need something at all when you can do things without it? I was talking about KISS principle where braces are not needed garbage that you have to carry on your shoulders.

  • Lokesh Gupta

    Thanks for summarizing.. enjoyed the post.

  • boosook

    Scala is a mess too, but it’s great! ;)

  • tomo_taka

    I think it is very interesting.

    When I tried to transcribe your code(Main.java) the error occurred in b92 . So I changed return of the Action Interface to void. Then it works fine!

    Thank you for your nice work!!!

  • srihari konakanchi

    In Java lamdas appears anonymous functions similar to anonymous classes
    thanks for the post arhan

    srihari konakanchi

  • arhan

    Syntactically, yes, you can find the similarities. But the implementation is very different: with anonymous classes javac generated some syntactic bytecode, with lambdas – it is all invokedynamic based now.

  • Ray

    check out some cool examples when using java 8 lambda and jdeferred (http://jdeferred.org)

  • Scoochalot

    You can do it without all the parenthesis on the left:

    execute( s -> System.out.println(s) );

    That works the same and the compiler will infer it is a String.

  • Paul Araujo

    This article is nice, and I could get a good idea about how lambdas are used in Java 8, but it is missing something which I think it’s very important. It’s missing an example of assignment of a lambda to an object.
    Something like:
    Action printText = (String s) -> System.out.print(“*” + s + “*”);
    And now we can use printText wherever we need an Action.
    Reading this article I thought we were not allowed to do that, but I found it in the Oracle tutorial.

  • arhan

    This is indeed possible. Thanks for pointing this out. However, if you check out the full PDF report, this kind of assignment is totally there. Enjoy!

  • Paul Araujo

    My bad. I read the article again and found the examples in the beginning of the article.

  • Balázs Csordás

    I just started studying lambda expressions, I have the impression that they are overrated. It surely decreases the amount of code you need to write but also decreases the code readability, and reusability. It is elegant, that is true, but I see more mess around testing and debugging. I don’t really see the purpose of it just for saving few lines of code. Same as when you leave {} for a single line. I always use brackets, code quality is about readability too.