Almost a year later since publishing the original Lambda proposal, JSR 335 EG has finally decided to adopt C# style syntax for Java 8 Lambda expressions. Brian has outlined the formal model for the new C# style syntax in his mail to lambda-dev:

lambda = ArgList Arrow Body
ArgList = Identifier
| “(” Identifier [ "," Identifier ]* “)”
| “(” Type Identifier [ "," Type Identifier ]* “)”
Body = Expression
| “{” [ Statement ";" ]+ “}”

Last week, Maurizio has pushed an updated compiler implementation that aligns with this new C# style syntax. I basically converted the Lambda examples used in my original post which I wrote an year ago when the initial straw-man syntax was prototyped. This post is essentially a take2, that illustrates Lambda expressions with the new C# style syntax and covers the latest developments in Lambda community. Honestly speaking, I enjoyed using the new syntax as part of this exercise. Enjoy!

Lambdas are available in the form of anonymous inner classes in Java. Anonymous inner classes are a form of nested classes that has no name and exhibits the following behavior as detailed in JLS 15.9.5.

  • An anonymous class is never abstract
  • An anonymous class is always an inner class; it is never static
  • An anonymous class is always implicitly final

One common use of anonymous inner classes is to create function objects in Java on the fly. [Refer Item 21 in Effective Java 2nd Edition pg 103]

Let us look at sorting an array of strings based on its length using an anonymous Comparator instance.

        String[] teams = {"Violet", "Indigo", "Blue", "Green", "Yellow", "Orange", "Red"};
        Arrays.sort(teams, new Comparator<String>() {
            @Override
            public int compare(String s1, String s2) {
                return s1.length() - s2.length();
            }
        });

To create process objects, such as Runnable, Thread, or TimerTask instances.

        final ExecutorService executor = Executors.newCachedThreadPool();
        executor.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("I am Runnable");
            }
        });

Anonymous classes have many limitations as outlined in Item 22 in Effective Java 2nd Edition [pg 108]. With Lambda expressions, you should be able to rewrite these samples more concisely eliminating the bulky syntax that comes with anonymous inner classes :

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Sample1 {

  public static void main(String... args) {
    final ExecutorService executor = Executors.newCachedThreadPool();
    // assignment context
    Runnable task = () -> System.out.println("I am Runnable"); //take 1
    executor.submit(task);

    // method invocation context
    executor.submit(() -> {System.out.println("I am Runnable");}); //take 2
    executor.shutdown();
  }
}

Array sorting using a comparator with Lambda expressions is a one liner:

import java.util.Arrays;
import java.util.Comparator;

public class Sample2 {
	public static void main(String... args) {
		String[] teams = {"Violet", "Indigo", "Blue", "Green", "Yellow", "Orange", "Red"};
		final Comparator<String> c = (s1, s2) -> s1.length() - s2.length();
		Arrays.sort(teams, c); //take 1
		Arrays.sort(teams, (s1, s2) -> s1.length() - s2.length()); //take 2
	}
}

So, what next? Let us do some hands-on with these Lambdas and explore what Lambdas has to offer for Java developers. I setup the new prototype on my Windows environment following Remi’s instructions. It was fairly straight forward (all you need is Mercurial Client, Apache Ant, and JDK 7).

Here is a simple build script (build.bat) I used in Windows, that you can place in the “make” sub-directory under “langtools” :

ant -Dboot.java.home=C:\jdk1.7.0 clean build

This would create classes.jar under “dist\lib” sub-directory. You need to place this jar in your classpath when using the prototype.

You can use the following batch scripts for compiling and running your Lambda examples (tested with the JDK 7 GA release).

javac.bat

@echo off
C:\jdk1.7.0\bin\java.exe -cp classes.jar com.sun.tools.javac.Main %1

java.bat

@echo off
C:\jdk1.7.0\bin\java.exe -cp classes.jar;. %1

It is required to include classes.jar in the classpath due to runtime dependencies that are not available in the binary build. To make sure if you are running the prototype compiler, the output should show “internal” tag:

C:\jdk8-lambdas\samples>javac.bat -version
javac 1.7.0-internal

Let us look at a simple example:

public class SimpleLambda {
  interface HelloWorld {
    void greet();
  }

  {
    HelloWorld greeting = () -> System.out.println("Hello World!");//nilary Lambda expression
    greeting.greet();
  }

  public static void main(String... args) {
    new SimpleLambda();
  }
}

To compile this example:

javac.bat SimpleLambda.java

To run this example:

java.bat SimpleLambda

Voila, you ran your first lambda example successfully if you see “Hello World!” output.

Let us look at another example which uses parameterized types in this case.

public class Sample3 {
  interface Squarer<X, Y> {
    Y square(X x);
  }

  public static void main(String... args) {
    Squarer<Integer, Integer> s = (x) -> x * x;// 1-ary Lambda expression
    System.out.println(s.square(5));
  }
}

In both these examples, you notice a pattern commonly referred to as single abstract method (SAM), defined using an interface with exactly one abstract method. This is a structural property identified by the compiler and it does not take into account methods inherited from java.lang.Object (as in java.util.Comparator).

For example, Runnable, Callable, etc belongs to this category of SAM types that can be converted in the context of assignment as shown below.

final Runnable task = () -> System.out.println(“I am Runnable”);

In this code, “task” is an Runnable instance, while the lambda expression () -> … is not. Only after conversion, the target type becomes an instance of that SAM type.

Syntax – The Holy Grail of Lambda

A lambda expression is written as a parameter list, followed by the -> token, followed by an expression or a statement block. In case of single line Lambda expression, return keyword can be omitted. Block of statements are surrounded with {} and if you need to return a result, you need to specify the return keyword.

Note ‘thin’ arrow is still used (instead of ‘fat’ (=>) arrow as used in C#). This is still under discussion. I personally like ‘thin’ arrow and ‘fat’ arrow does not really help visually.

Lambdas in Java exhibit the following behavior :

  • An interface with exactly one abstract method is referred to as an functional interface (fka SAM types).
  • Lambdas are not instances of classes.
  • Lambdas can only be converted to SAM interfaces.
  • SAM types are instances of classes.
  • Lambdas are lexically scoped.

Lambda definition (excerpt from draft)

A lambda expression e is convertible-to a SAM type S if an anonymous inner class that is a subtype of S and that declares a method with the same name as S’s abstract method and a signature and return type corresponding to the lambda expressions signature and return type would be considered assignment-compatible with S.

The return type and exception types of a lambda expression are inferred by the compiler; the parameter types may be explicitly specified or they may be inferred from the assignment context.

The type of a formal parameter can be omitted, in which case the compiler will infer a type from the target type of the lambda conversion. Let us see couple examples where the types are inferred by the compiler.

public class Sample4 {

  enum Decision {
    APPROVE, DECLINE, APPROVE_REFER
  }

  interface DecisionService {
    Decision getRiskDecision(Applicant applicant);
  }

  class Applicant {
    private int score;

    public Applicant(int score) {
      this.score = score;
    }

    public int getScore() {
      return score;
    }
  }

  public void test() {
    DecisionService cs = (a) -> {
    if (a.getScore() > 700) {
      return Decision.APPROVE;
    } else if (a.getScore() > 600 && a.getScore() < 650) {
      return Decision.APPROVE_REFER;
    } else {
      return Decision.DECLINE;
    }};
    Decision decision = cs.getRiskDecision(new Applicant(800));
    System.out.println(decision.toString());
  }

  public static void main(String... args) {
    new Sample4().test();
  }
}

In line #24 above, the type of the formal parameter Applicant is inferred by the compiler.

public class Sample5 {

  class Payment {
    private int amount;

    Payment(int amount) {
      this.amount = amount;
    }

    public int getAmount() {
      return amount;
    }
  }

  interface PaymentProcessor {
    void process(Payment pmt);
  }

  public void test() {
    invokeProcessor((pmt) -> log("Processed # " + pmt.getAmount() + " at " + new Date()));
  }

  void invokeProcessor(PaymentProcessor processor) {
    processor.process(new Payment(42));
  }

  void log(String message) {
    System.out.println(message);
  }

  public static void main(String... args) {
    new Sample5().test();
  }
}

In line #20, the type of the formal parameter Payment is inferred by the compiler.

Here is the definition of SAM and non-SAM types as explained in one of the Lambda test case.

SAM types:
1. An interface that has a single abstract method
2. Having more than one distinct methods, but only one is “real”, the others are overriden public methods in Object – example:

Comparator<T>

3. Having more than one methods due to inheritance, but they have the same signature
4. Having more than one methods due to inheritance, but one of them has a subsignature of all other methods

    a) parameter types compatible
    b) return type substitutable
    c) thrown type not conflicting with the thrown clause of any other method
    d) mixed up

5. Type-dependent SAM types

non-SAM types:
6. An interface that has a single abstract method, which is also public method in Object
7. Having more than one methods due to inheritance, and none of them has a subsignature of all other methods

What has changed since then in the Lambda community?

Well, the first thing that happened in the past year was the formation of expert groups; JSR 335 for Lambda support in Java 8 and JSR 337 umbrella JSR for Java 8. Two polls were conducted in June on lambda-dev mailing list and the results mostly favored BGGA style syntax. Choosing the syntax that C# and Scala broadly share is a wise move by the JSR 335 EG. Did any one catch up with the replacement term for SAM? It is called “functional interface”, although SAM is widely popular among lambdaphiles.

Virtual extension methods approach was revised since the original strawman proposal. Brian explains this beautifully from conception to implementation in this paper Interface evolution via virtual extension methods. Virtual extension methods will be implemented as a VM feature, which makes it transparent like any other method invocation for non-Java languages. The following JVMLS talks explain the latest developments in virtual extension methods and lambda implementation strategies. I strongly encourage to watch them as it is the only source of information for people outside the JSR 335 Expert Group.


[Photo credit: http://www.lumaxart.com/]

Possibly Related Posts:


2 Responses to “Lambda expressions in Java 8 adopts C# style syntax”

  • Arul

    Hi Davide,

    Lambda support is planned for JDK 8. The process I used was to build the patched compiler from langtools repository (bleeding edge) that supports Lambda expressions. It was outlined in my original entry, in case if you missed it. JDK 8 dev builds are starting to appear here, unfortunately it does not yet support lambda expressions. I am hoping that day is not too far.

    -Arul