Share Button

Java 8 brought us the lambda expressions (and the adepts of functional programming said amen). It was possible to approach the same concept before Java 8 by using the anonymous classes, but it was very verbose. They call it a “vertical problem” (using a lots of code lines to only represent a single call to a method, for example).

I’m not saying lambda expressions are going to replace the anonymous classes, it will not. A lambda expression can’t have any field or multiple methods. The only situation where a lambda expression can replace an anonymous class is when the anonymous class implements an interface containing only one method.

Anonymous class !== lambda expression

Lambda expressions are not just about wrapping a “single method anonymous class” into a more readable syntax. They are actually different objects behind the scene in many point of view. Whether in terms of compiling, syntax or execution. Let’s dive into it.

This is an example for an anonymous class and a lambda expression, they do exactly the same thing: Implementing the java.util.function.Supplier functional interface to return a Double (by the way, 6 lines for the anonymous class and 1 line for the lambda expression, that’s the vertical problem !).

class Main {
  public static void main(String[] args) {
    // Anonymous class
    displayExpression(new Supplier<Double>() {
      @Override
      public Double get() {
        return 50.0;
      }
    });

    // Lambda expression
    displayExpression(() -> 50.0);
  }

  private static void displayExpression(Supplier<Double> supplier) {
    System.out.println(supplier);
    System.out.println("Anonymous class: " + supplier.getClass().isAnonymousClass());
  }
}

The output of this program is:

Main$1@244038d0
Anonymous class: true
Main$$Lambda$1/1123225098@33e5ccce
Anonymous class: false

We can see the toString() method returns an interesting value on the instance, they are clearly different, and isAnonymousClass confirms it. On a day to day point of view, what’s the difference ? First, there is no way to reference, inside the expression, the lambda expression itself with this. If you use this, it will reference the instance of the class where the expression is written. Contrary to the anonymous class, where inside it, this references the instance of itself.

Note: In the example above, we couldn’t use this in the lambda expression because the expression is written in a static context.

In terms of compiler and runtime behaviour (for OpenJDK), an inline lambda expression will be turned into a static or instance private method in the class it has been written. If the inline expression doesn’t capture the current instance (by using this), a private static method will be generated, otherwise a private instance method will be used.

It’s clearly visible if you use the java class file disassembler:

class Main {
  public static void main(String[] args) {
    // Lambda expression
    displayExpression(() -> 50.0);
  }

  private static void displayExpression(Supplier supplier) {
    supplier.get();
  }
}

 javap -private -c Main

class Main {
  Main();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: invokedynamic #2,  0              // InvokeDynamic #0:get:()Ljava/util/function/Supplier;
       5: invokestatic  #3                  // Method displayExpression:(Ljava/util/function/Supplier;)V
       8: return

  private static void displayExpression(java.util.function.Supplier);
    Code:
       0: aload_0
       1: invokeinterface #4,  1  // InterfaceMethod java/util/function/Supplier.get:()Ljava/lang/Object;
       6: pop
       7: return

  private static java.lang.Double lambda$main$0();
    Code:
       0: ldc2_w        #5                  // double 50.0d
       3: invokestatic  #7                  // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
       6: return
}

We can see a new private static method has been added to our Main class (lambda$main$0). So how can we go from a private method, to an object implementing the java.util.function.Supplier functional interface ? Because in the end, this is what it is about in this example: Give to the method displayExpression an implementation of Supplier !

Have a closer look to the byte code, you can see the instruction invokedynamic (line 10) is called right before calling the static displayExpression method. This instruction has been introduced in Java 7 to support dynamically typed languages to run on the JVM. On the byte code above, invokedynamic targets the index #2 in the constant pool of the class. This index points to a BootstrapMethods which links at runtime the private method, added by the compiler, to the caller. This is where the magic happens, this BootstrapMethod will initiate the construction of the lambda and provide an implementation of java.util.function.Supplier based on the private method added by the compiler.

Note: You can display the constant pool of a class by using the -verbose option of javap

They had multiple possibilities in terms of internal representation for lambda expressions (inner classes or java.lang.invoke.MethodHandle for example). But, by using invokedynamic, they thought it was the more flexible way to do it and the less “overheading”. Can you imagine the number of classes which would have to be generated by the compiler if they chose the anonymous class system for each lambda expression ?

This is a very simplified view, if you want to go deep into the implementation of the lambda expressions in the JVM, there is great article from Brian Goetz here, he is a Java Language Architect at Oracle.

So it does differ a lot from the anonymous class where everything is done at the compilation stage. With an anonymous class, the code above would generate a whole new class Main$1.class which contains the implementation of the anonymous class, just like any other class, with its constructor and methods. And before calling the displayExpression method, a new instance of Main$1.class would be created and passed to the method as a parameter, without any necessity of invokedynamic.

Contrary to lambda expressions, (private method and runtime linking), with anonymous classes everything is wired at the compilation process.

No need to go further, a lambda expression is NOT an anonymous class.

Method referencing

This is what I like about the stuff coming with lambda expressions: the method referencing. But before talking about this new feature, let’s talk about how to reference a method before Java 8.

The only way to get a reference to a method was to use reflection and use the method’s name in a String parameter to get a java.lang.reflect.Method object:

Method displayExpression = Main.class.getDeclaredMethod("displayExpression");

And then, it was possible to call the invoke method on the Method object. There’s a lot of potential problems, for example if the name is wrong, a NoSuchMethod exception will be raised, if we refactor our code, we need to change the value of the String parameter too (same problem with java.lang.invoke.MethodHandle from Java 7).

I wish the method reference of Java 8 provides a better way to get a  java.lang.reflect.Method or java.lang.invoke.MethodHandle, but this is not what it is about.

The method reference feature is about using existing method as a lambda expression. When you write a lambda expression, you don’t always have to write an inline one. If you have a method in a class with the same signature as the functional interface you target, you can use this method as a lambda expression with the double colon syntax:

class Main {
  public static void main(String[] args) {
    // Lambda expression with method reference
    displayExpression(Main::getDoubleValue);
  }

  private static Double getDoubleValue() {
    return 50.0;
  }

  private static void displayExpression(Supplier<Double> supplier) {
    supplier.get();
  }
}

Let’s have a quick look at the bytecode to see the difference compare to an inline lambda expression:

class Main {
  Main();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: invokedynamic #2,  0              // InvokeDynamic #0:get:()Ljava/util/function/Supplier;
       5: invokestatic  #3                  // Method displayExpression:(Ljava/util/function/Supplier;)V
       8: return

  private static java.lang.Double getDoubleValue();
    Code:
       0: ldc2_w        #4                  // double 50.0d
       3: invokestatic  #6                  // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
       6: areturn

  private static void displayExpression(java.util.function.Supplier);
    Code:
       0: aload_0
       1: invokeinterface #7,  1            // java/util/function/Supplier.get:()Ljava/lang/Object;
       6: pop
       7: return
}

As you can imagine, this time, the compiler didn’t add any private method to the class (the way it would do with an inline lambda). But the mechanic stays the same, the link between the existing method and the “lambda object” is made at runtime by the invokedynamic instruction.

There are 4 kinds of method reference:

  • Reference to a static method (MyClass::MyStaticMethod)
  • Reference to an instance method of an instance of an object (myInstance::myInstanceMethod)
  • Reference a constructor (MyClass::new)
  • Reference to an instance method of an arbitrary object of a particular type (MyClass::myInstanceMethod)

The first three types are pretty self explanatory, the last one is (a little bit) less ! How can I reference an instance method without an instance of the object containing this method ?

The example of the Oracle documentation is not very helpful on this one:

String[] stringArray = { "Barbara", "James", "Mary", "John"};
Arrays.sort(stringArray, String::compareToIgnoreCase);

Oracle: The equivalent lambda expression for the method reference String::compareToIgnoreCase would have the formal parameter list (String a, String b), where a and b are arbitrary names used to better describe this example. The method reference would invoke the method a.compareToIgnoreCase(b).

The most important thing they don’t say is that, if the referenced method is the instance method of an arbitrary object of a particular type, the object (the receiver of the method) is considered to be the first argument in the functional interface used.

An example will tell more:

class Main {
  public static void main(String[] args) {
    // Lambda expression
    transformToUppercase(String::toUpperCase);
  }

  private static void transformToUppercase(Function<String,String> transformer) {
   System.out.println(transformer);
  }
}

The java.util.function.Function<String,String> means the lambda expression has to respect the signature:

String apply(String t)

The method toUpperCase of the String object, gave as a lambda in this example, does not  respect the signature of the functional interface (toUpperCase doesn’t expect any parameter where the apply method is expecting one).

But it’s working here, because we referenced the method by using the arbitrary object of a particular type syntax (ClassName::instanceMethod). As said earlier, with this syntax, the compiler expects the first argument of the functional interface to be the same type as the class providing the instance method. By giving an instance of String as a parameter to apply, the method toUpperCase will be called on the instance and the value returned.

This method reference syntax is a little bit more tricky, but once you get used to, it can be very powerful.

Share Button