Java 8 closures compared to C# and Scala

One of the longest awaited and most urgently demanded features for Java are Closures, also called Lambda Expressions or Anonymous Functions. C# has it, Scala and most other modern dynamic languages anyway, so, it’s about time 😉 Since early access releases of Java 8 are already available, time to have look and compare it with other languages.

Closures can be used to pass functions as method arguments, or even as return values. One particularity of such anonymous methods is, that they have access to the local context (scope) they have been created in, e.g. to local variables. They “enclose” this context – and that’s the origin of the name.

Closures are actually a pretty old concept and Lisp already used them more than 60 years ago. They have always been basic build blocks of functional languages (so called first class objects) and are also widely used in hybrid languages such as Ruby, Python or Scala. Even C# supports Closures since version 3.0 and they unfold their strength especially in LINQ, where you can write strongly typed queries we can only dream of in JPA:

var boyNames = names
  .Where((n) => n.Gender == Gender.Boy)
  .Select((n) => new { n.Name });

Java 8

So, let’s have a look how a Closure or Lambda Expression is going to look in Java 8. A lot of proposals have been made and discussed, but at the end it looked quite similar to Scala and C#:

Calculator adder =
 (double summand1, double summand2) -> summand1 + summand2;

The basic syntax is (arg1, arg2, …) -> { <expression> }. Please note the single dash arrow instead of the equal sign arrow in Scala and C#. But what is on the left hand of the assignment, how do we hold references to Closures? Instead of introducing something new (e.g. a generic interface Function as also proposed), Interfaces with a single method are used and they also got a fancy name: SAM – Single Abstract Method. The Calculator SAM from the example above is defined like this:

//Single Abstract Method (SAM) interface to hold Closures
public static interface Calculator {
  double execute(double arg1, double arg2);
}

One good thing is, there are already plenty of existing SAMs in Java and all methods which take one of them as an argument are now automatically higher order functions (functions that take functions). E.g. Runnable:

new Thread(
 () -> { for (int i = 0; i < 10; i++) System.out.println(i); } 
).start(); 

I mean, the first time I’ve seen that, I thought, wow that’s smart. And all the books which state, that in Java Interfaces are used to pass “methods” or some logic to other method, are still correct ;-). But at the other hand, it makes calling Closures quite clumsy:

 
Calculator adder =    
  (double summand1, double summand2) -> summand1 + summand2;

double result = adder.execute(10, 5);
//How it should look:
//double result = adder(10, 5);

Why do I have to call execute() here? It seems to me that Closures in Java 8 are mainly a convenient syntax sugar for anonymous inner classes, why not introducing a shortcut for calling the single method of a SAM?

Well, in fact Closures are a bit more than anonymous inner classes, for example, non-final local classes can be part of the Closure expression:

int localNonFinalVar = 1;

Calculator multiplier =
  (factor1, factor2) -> factor1 * factor2 * localNonFinalVar;

The second thing you can see in this example is, that the argument types can be omitted, since the compiler can infer it from the interface Calculator.

A last interesting features is, that existing methods can be used as Closures, well, more precise, SAMs can refer to existing methods. For that aim the double colon operator will be introduced in Java 8 (in older drafts the hash symbol has been used):

public class Test {
  private static double substractor
    (double minuend, double subtrahend) {
      return minuend - subtrahend;
  }
  
  public static void main(String[] args) {
    Calculator substractor = Test::substractor;
		
    //Closure from a build in method!
    Calculator maximum = Math::max;
  }
}

So we can just pass java.lang.Math::max as an argument to a higher order function – pretty neat!

C#

The C# delegates are used to hold references to Closures. This decision was somehow obvious, since a delegate already represented a function signature:

delegate double Calculator(double arg1, double arg2);

Calculator adder =
 (Double summand1, Double summand2) => summand1 + summand2;

The argument types can also be omitted and it is also possible to include local variables:

int localVariable = 1;

Calculator multiplier = 
  (factor1, factor2) => factor1 * factor2 * localVariable;

And referring to existing methods is of course possible, that’s the original aim of delegates. Although the syntax feels a bit odd compared to Java 8:

class Test
{
  private static double Substractor
  (double minuend, double substrahend)
  {
    return minuend - substrahend;
  }
  
  static void main(string[] args(string[] args)
  {
    Calculator substractor = new Calculator(Substractor);
  
    //Closure from a build in method
    Calculator maximum = new Calculator(Math.Max);
  }
}

Calling C# Closures works like it is supposed to be, that’s an advantage over the Java 8 approach with SAMs:

var result = adder(10, 5);

Short and simple. By the way, implicitly typed variables (var) would also be handy in Java… which brings me to Scala.

Scala

In Scala neither SAMs nor something like a delegate is needed and thanks to type inference we can just write:

val adder =
 (summand1: Double, summand2: Double) => summand1 + summand2

Here you can of course not simply omit the argument types, but defining a function type in Scala is straight forward: (Double, Double) => Double. Or in a full example:

val multiplier: (Double, Double) => Double 
  = (factor1, factor2) => factor1 * factor2;

Referring to existing methods is concise and clean, as to be expected from Scala:

def substractor(minuend: Double, substrahend: Double) =
  minuend - substrahend

val substractorRef: (Double, Double) => Double = substractor

//Closure from a build in method
val maximum : (Double, Double) => Double = math.max

And executing a Closure is as simple as in C#:

val result = adder(10, 5)

Summary

Java 8 Closures will greatly enhance the readability, especially in GUI development, where a lot of anonymous inner classes for event handling clutter the code. Also, they will give a boost to internal DSLs (see LINQ example at the top of the post) and allow functional coding style to some extend (e.g. map/reduce on collections).

I’m glad that they’ve reused the existing syntax of Scala and C#, the dash arrow is probably an attempt to appear distinct.

There is not much bad to say, I personally don’t like the approach with SAMs, because that will lead to confusion. I would have preferred an approach which separates Closures and the concept of anonymous inner classes more strictly. It seems to much just a syntactic sugar, a very useful though. To draw the equation anonymous inner class = anonymous function | when interface is SAM is maybe too simple.

A closer look into the generated bytecode reinforces the impression of syntactic sugar: Closures are just compiled to anonymous inner classes – currently it is even possible to run the generated bytecode with an Java 7 JRE. Used local variables are simply passed to the constructor and stored in attributes of the inner class. Here the multiplier example from above on the byte-code level:

//Calculator multiplier =
//  (factor1, factor2) -> factor1 * factor2 * localNonFinalVar;

class Test$2 implements Test$Calculator {
  int cap$0; // localNonFinalVar

  Test$2(int);
       0: aload_0
       1: invokespecial #1 // Super constructor call
       4: aload_0
       5: iload_1
       6: putfield      #2 // Field cap$0:I
       9: return

  public double execute(double, double);
       0: dload_1
       1: dload_3
       2: dmul
       3: aload_0
       4: getfield      #2 // Field cap$0:I
       7: i2d
       8: dmul
       9: dreturn
}

To sum up, the implementation is not as clean and concise as in Scala, but comparable to C#, and yet a big improvement. That we actually have to call the single method of the SAM when executing a Closure is quite confusing.

So, I’m, really looking forward to Java 8.