The improved varargs warnings, part of the Coin proposal finally made into the latest JDK 7 build. I believe build 123 is special as this milestone marks the completion of all the planned JSR 334 features (the head side of the Coin) scheduled for implementation in Java SE 7. So, Coin minting done? I think so. Let us get the final dose of Project Coin.

I would like to list out some key points that are worth refreshing when discussing varargs:

  • Generics are implemented by erasure and hence non-reifiable and enforces element types only at compile time.
  • Arrays are reified, which makes them enforce element types at runtime.
  • Arrays are covariant, while parameterized types are invariant.
  • Varargs are implemented as an array of objects and can hold only reifiable types.
  • Arrays when mixed with parameterized types are generally the source of unchecked warnings emitted by the compiler.

In essence, Generics and arrays (including varargs) do not play well together [Item 25: Prefer lists to arrays in Effective Java 2nd Edition Pg 119]. Whenever you invoke a varargs method, an array is created to hold the varargs parameters. If the element type of this array is not reifiable, it is likely to generate a compiler warning. On the other hand, it is not permitted to create an array whose component type is a concrete parameterized type, because it is not type safe.

Here is a simple example that shows generic array creation.

// Generic array creation is illegal - won't compile
List<List<String>> numbersInThreeLanguages = Arrays.asList(new List<String>[]{Arrays.asList("Un", "Deux", "Trois"), Arrays.asList("Uno", "Dos", "Tres"), Arrays.asList("One", "Two", "Three")});

The legal code would look like, but this would generate an unchecked warning:

//[unchecked] unchecked generic array creation for varargs parameter of type List<String>[]
    List<List<String>> numbersInThreeLanguages = Arrays.asList(Arrays.asList("Un", "Deux", "Trois"),
            Arrays.asList("Uno", "Dos", "Tres"), Arrays.asList("One", "Two", "Three"));

The warning can be suppressed at the call site as this is considered a safe invocation:

    @SuppressWarnings(value = "unchecked")
    List<List<String>> numbersInThreeLanguages = Arrays.asList(Arrays.asList("Un", "Deux", "Trois"),
            Arrays.asList("Uno", "Dos", "Tres"), Arrays.asList("One", "Two", "Three"));

These unchecked warnings issued when invoking varargs methods that are tagged as candidates for inducing heap pollution are considered harmless. Some of the widely used helper methods in JDK library produce such warnings which are useless and requires the client code to explicitly suppress them at the call site, if you hate them.

  • public static List Arrays.asList(T… a)
  • public static boolean Collections.addAll(Collection c, T… elements)
  • public static > EnumSet EnumSet.of(E first, E… rest)

The Coin varargs improvement adds a new @Documented annotation type, java.lang.SafeVararags, that can be used at the declaration site to suppress unchecked warnings for certain varargs invocations which are considered safe such as the ones listed above.

When the JDK libraries are retrofitted to take advantage of this new annotation type, client code can safely remove any SuppressWarnings annotation from the call site. For example, Arrays.asList() would carry this special annotation that reduces these warnings at the call site.

  @SafeVarargs
  public static <T> List<T> asList(T... a) {
    return new ArrayList<T>(a);
  }

In addition to this annotation type, a new mandatory compiler warning “Possible heap pollution from parameterized vararg type : {0}” is generated on declaration sites of problematic varargs methods that are able to induce contributory heap pollution. To illustrate this, let us look at Alex Miller’s generics puzzler code below.

//[unchecked] Possible heap pollution from parameterized vararg type T[]
  public static <T> T[] mergeArrays2(T[]... arrays) {
      List<T> result = new ArrayList<T>();

      for(T[] array : arrays) {
          for(T item : array) {
              result.add(item);
          }
      }
      // BROKEN: This generates a compiler warning about checking against an erased type
      return (T[])result.toArray();
  }

This code would cause a ClassCastException at runtime and the warning generated by the compiler is indeed legitimate, so this is a case where the warning should never be suppressed and should be fixed. I believe there are couple different ways to solve this puzzle (details in Alex’s blog comments), but the recommended approach is to prefer collections to arrays when designing APIs (as in Puzzle #3 in the recent installment of Java Puzzlers from Josh Bloch and Bob Lee).

The solution outlined below requires the caller to provide a hint on the return type, which is kind of ugly, but works.

  @SafeVarargs
  static <T, U extends T> T[] mergeArrays(T[] returnType, U[]... arrays) {
    Class<?> componentType = returnType.getClass().getComponentType();
    // Determine total length
    int length = 0;
    for (T[] a : arrays) {
      length += a.length;
    }
    @SuppressWarnings(value = "unchecked")
    T[] result = (T[]) Array.newInstance(componentType, length);
    int j = 0;
    for (T[] anArray : arrays) {
      for (T element : anArray) {
        result[j++] = element;
      }
    }
    return result;
  }

If you notice, the use of @SafeVarargs annotation at the declaration site is valid since we have fixed the underlying problem of creating type safe array. The unsafe casting at line#10 when reflectively creating an array instance is harmless, so we can suppress that unchecked warning too.

The client code that invokes this method using a String array and an Integer array is shown below:

    String[] s1 = new String[]{"one", "two", "three"};
    String[] s2 = new String[]{"four", "five", "six"};
    String[] s3 = new String[]{"seven", "eight", "nine"};
    String[] sHint = new String[]{};
    String[] sMerged = mergeArrays(sHint, s1, s2, s3);
    System.out.println(Arrays.toString(sMerged));
//Output: [one, two, three, four, five, six, seven, eight, nine]
    Integer[] i1 = new Integer[]{1, 2, 3};
    Integer[] i2 = new Integer[]{4, 5, 6};
    Integer[] i3 = new Integer[]{7, 8, 9};
    Integer[] iHint = new Integer[]{};
    Integer[] iMerged = mergeArrays(iHint, i1, i2, i3);
    System.out.println(Arrays.toString(iMerged));
//Output: [1, 2, 3, 4, 5, 6, 7, 8, 9]

@SafeVarargs Applicability

This annotation type is applicable to Constructor and Method types only as defined by the Target meta-annotation. Here is the specification copied from the javadoc of @SafeVarargs which clearly outlines its scope and requirements in detail.

In addition to the usage restrictions imposed by its @Target meta-annotation, compilers are required to implement additional usage restrictions on this annotation type; it is a compile-time error if a method or constructor declaration is annotated with a @SafeVarargs annotation, and either:

  • the declaration is a fixed-arity method or constructor
  • the declaration is a variable-arity method that is neither static nor final.

Compilers are encouraged to issue warnings when this annotation type is applied to a method or constructor declaration where:

  • The variable-arity parameter has a reifiable element type, which includes primitive types, Object, and String. (The unchecked warnings this annotation type suppresses already do not occur for a reifiable element type.)
  • The body of the method or constructor declaration performs potentially unsafe operations, such as an assignment to an element of the variable-arity parameter’s array that generates an unchecked warning.

Another important thing Joe clarified regarding overriding on coin-dev: “As documented in its specification, the SafeVarargs annotation is only applicable to static methods, final instance methods, and constructors; therefore, overriding does not occur. Annotation inheritance only works on classes (not methods, interfaces, or constructors) so without changing annotation inheritance, a SafeVarargs-style annotation cannot be passed through general instance methods in classes or through interfaces.”

Conclusion

I think the Coin chapter for Java 7 has come to an end. Now, what is pending is the dogfooding, which has already begun as JDK libraries are getting a dose of Coin in form of Diamond finishings. IDEs are gearing up support for these new language features. Both, NetBeans 7 Beta and IntellijIDEA 10 has a decent support for some of the Project Coin features. The ride with Project Coin has been an exciting one so far. Hope you all enjoyed exploring these cool new Java 7 features with me; why wait, mint yours today 🙂

Possibly Related Posts:


Last November, Mark Reinhold announced that Closures will be added to the Java language and six months later we had an initial prototype based on the Straw-Man proposal and last month’s update was considered a significant progress for the language in years. As mentioned in Mark’s post, “Working with parallel arrays in Java, unfortunately, requires lots of boilerplate code to solve even simple problems. Closures can eliminate that boilerplate.” In my earlier post, I discussed how Lambda expressions make Aggregate operations a breeze to work with in Java. But, we still lack parallel looping constructs such as parallel for, foreach APIs that would take advantage of the multi-core machines we have today.

In this next Lambda adventure, I will be revisiting the Parallel ForEach example discussed by Howard in his “New Control Structures for Java” post, where he explains the use of anonymous inner classes to map a function that executes in parallel and retains the order of the original map, handles exceptions and implements continue operation. Here is the anonymous inner class version of the code:

The program produces the below output:

{1=H, 2=e, 3=l, 4=l, 5=o}

Now, that we have a working Lambda prototype, this code could be modified to take advantage of Lambda expressions. Let us enable the Lambda finder option in the compiler that identifies potential candidates for converting an anonymous inner class instance to an Lambda expression. Here is the updated javac.bat used to run with the latest prototype compiler.

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

Compiling Parallel.java with this hidden compiler option identifies 2 candidates for Lambda expressions.

C:\JDK7\lambda\samples&gt;javac.bat Parallel.java
Parallel.java:16: Note: This anonymous inner class creation can be turned into a lambda expression.
            return new Callable&lt;O&gt;() {
                                     ^
Parallel.java:70: Note: This anonymous inner class creation can be turned into a lambda expression.
        final ForEach&lt;Character, Integer, Character&gt; trim = new ForEach&lt;Character, Integer, Character&gt;() {
C:\JDK7\lambda\samples&gt;

Let us quickly refactor Howard’s code using Lambda expressions and here is my take.

This version does not significantly change from its anonymous counterpart, it reduces at most 10 lines of code. But, it introduces two important concepts in addition to use of Lambda expressions. Lines 6 and 13 uses the new exception transparency mechanism and Line 62 shows how lexical scoping makes Lambda expressions different from anonymous inner classes.

Exception Transparency

Exception transparency is a new feature proposed as part of the umbrella Lambda proposal. While this feature is not required to support Lambda expressions, it is useful in library implementations that require abstraction over generic exceptions. Java Generics does a decent job at abstracting over method return types and argument types, leaving abstraction over types of checked exceptions in limbo. This makes it difficult for libraries to support generic exception types in APIs. The two extreme cases where libraries usually model their exception types are :

In case of Runnable, the run() method throws nothing.

public interface Runnable {
    public abstract void run();
}

In case of Callable, the call() method throws everything.

public interface Callable<V> {
    V call() throws Exception;
}

As more and more libraries would take advantage of executing Lambda expressions as a block of code, the inability to generify thrown exception types makes this proposal a compelling use case.

A throws type parameter is a generic type parameter that is introduced with the keyword throws; throws type parameters implicitly have an upper bound of Exception (though any upper bound that is a subtype of Throwable may be explicitly specified) and can correspond to zero or more actual types that are subtypes of the upper bound.

With this support in the language, we should be able to abstract generic exception types:

	interface Block<throws E> {
		public void execute() throws E;
	}

Lexical scoping

Unlike anonymous inner classes, lambda expressions are lexically scoped. This means that code inside the Lambda body sees only what is available immediately outside the lambda expression. For instance, access to names from inherited classes/interfaces is not allowed as seen in Line #62 of our example above.

I wanted to briefly touch upon these concepts that are relevant to our discussion. Please refer to the proposal for more details.

.NET world

Let us look at how modern languages support Parallelism in their libraries. Here is an closest example using C# Task Parallel Library (TPL) (from Patterns of Parallel Programming Guide).

But this is just an attempt if someone wanted to write their own parallel foreach construct using existing C# APIs. But, this is not required. In C#, parallel constructs are available for a while now. Using the Parallel.ForEach construct in TPL, iterating all the Test records of a Student and calculate the GPA would look something like:

Fair enough, this construct is concise and abstracts all the machinery from the Client code. Are we close enough to get a similar construct in Java? I think so, we do have parallel collections library that supports parallelism using Fork-Join framework today. It looks like Doug Lea has recently revealed his plans for developing new library components for parallel operations on aggregates (collections and arrays) for JDK8 (based on proposed language support for lambdas). I believe this effort would produce these constructs in Java.

For the sake of fun, I compiled the extry166y sources with the compiler option “-XDidentifyLambdaCandidate=true”, it identified 168 candidates that can be turned into a lambda expression. Less code means more fun and you see that for real.

Update (6/11/2011) : Updated the Parallel class (Lambda version) to compile with the latest lambda prototype compiler. Abstract classes with single abstract method are no longer considered valid SAM types as per the revised rules.

Possibly Related Posts:


One of the primary uses of Lambda expressions is to implement aggregate operations that can often be parallelized using multi-core processors we have today. The computation over bulk data structures is an area where Lambda expressions provide much needed support where part of the computation is caller defined. Doug Lea’s JSR166y Concurrency interest group exactly brings these rich set of Collections that supports parallel operations to perform bulk computation over data in the Java platform.

Let us look at an aggregate operations example using a ParallelArray, that maintains a ForkJoinPool and an array in order to provide parallel aggregate operations. The jsr166y package is already included in Java 7 as part of the ForkJoin framework. The extra166y package that contains Collections supporting parallel operations is not part of the JDK yet, but you should be able to use them today as an add-on library.

import extra166y.Ops;
import extra166y.ParallelArray;
import extra166y.ParallelDoubleArray;

public class AggregateOpsExample {

    ParallelArray<Student> students;

    public AggregateOpsExample() {
        jsr166y.ForkJoinPool fjPool = new jsr166y.ForkJoinPool();
        // Create a "fictional" Student array
        Student s1 = new Student("S1", 2010, 85, 5);
        Student s2 = new Student("S2", 2010, 91, 4);
        Student s3 = new Student("S3", 2010, 95, 3);
        Student[] data = new Student[]{s1, s2, s3};
        students = ParallelArray.createFromCopy(new Student[]{s1, s2, s3}, fjPool);
    }

    public Student getStudent(int index) {
        return students.get(index);
    }

    public double getMaxSeniorGpa() {
        return students.withFilter(isSenior)
        			   .withMapping(gpaField)
        			   .max();
    }

    public ParallelDoubleArray.SummaryStatistics getSummaryStatistics() {
        return students.withFilter(isSenior)
	                   .withMapping(gpaField)
        	           .summary();
    }

    // helpers:
    static final class IsSenior implements Ops.Predicate<Student> {
        public boolean op(Student s) {
            return s.credits > 90;
        }
    }

    static final IsSenior isSenior = new IsSenior();

    static final class GpaField implements Ops.ObjectToDouble<Student> {
        public double op(Student s) {
            return s.gpa;
        }
    }

    static final GpaField gpaField = new GpaField();

    public static void main(String[] args) {
        AggregateOpsExample test = new AggregateOpsExample();
        double bestGpa = test.getMaxSeniorGpa();
        System.out.println("Best GPA : " + bestGpa);
        ParallelDoubleArray.SummaryStatistics summary = test.getSummaryStatistics();
        System.out.println("Last Best Student: " + test.getStudent(summary.indexOfMin()).name);
        System.out.println("Average GPA in class of 2010 : " + summary.average());
    }

    public class Student {
        String name;
        int graduationYear;
        int credits;
        double gpa;

        public Student(String name, int graduationYear, int credits, double gpa) {
            this.name = name;
            this.graduationYear = graduationYear;
            this.credits = credits;
            this.gpa = gpa;
        }
    }
}

In Line#10, a ForkJoinPool is created with parallelism equal to Runtime.availableProcessors(), in my case 2. Lines 24-26 and 30-32 perform aggregate operations on Students array. These operations take advantage of multi-core processors than the traditional sequential approach we used to filter and map a collection. By introducing Lambda expressions in the client code, you can remove much of the boilerplate in lines 36-50 in our code.

Let us build upon the above example to time these aggregate operations and erase some of the boilerplate using Lambda expressions.

import extra166y.Ops;
import extra166y.ParallelArray;
import extra166y.ParallelDoubleArray;

public class TimedAggregateOps {

	ParallelArray<Student> students;

	public TimedAggregateOps() {
		jsr166y.ForkJoinPool fjPool = new jsr166y.ForkJoinPool();
        // Create a "fictional" Student array
		Student s1 = new Student("S1", 2010, 85, 5);
		Student s2 = new Student("S2", 2010, 91, 4);
		Student s3 = new Student("S3", 2010, 95, 3);
		Student[] data = new Student[]{s1, s2, s3};
		students = ParallelArray.createFromCopy(new Student[]{s1, s2, s3}, fjPool);
	}

	interface Block {
		public void execute();
	}

	static void time(boolean maxGpa, Block block) throws Exception {
		long startTime = System.nanoTime();
		boolean success = true;
		try {
			block.execute();
		} catch (final Throwable ex) {
			success = false;
			throw ex;
		} finally {
			recordTiming(maxGpa, System.nanoTime() - startTime, success);
		}
	}

	static void recordTiming(boolean maxGpa, long nanoseconds,  boolean succeeded) {
		if (maxGpa) {
			System.out.println("maxGpa took " + nanoseconds + "ns and operation " + (succeeded ? "succeeded." : "failed."));
		} else {
			System.out.println("avgGpa took " + nanoseconds + "ns and operation " + (succeeded ? "succeeded." : "failed."));
		}
	}

    static final Ops.Predicate<Student> isSenior = #{s -> s.credits > 90};
    static final Ops.ObjectToDouble<Student> gpaField = #{s -> s.gpa};

    public void findMaxSeniorGpa() {
        double maxGpa = students.withFilter(isSenior)
        						.withMapping(gpaField)
        						.max();
        System.out.println("Maximum GPA : " + maxGpa);
    }

    public void findAverageGpa() {
        ParallelDoubleArray.SummaryStatistics summary = students.withFilter(isSenior)
                												.withMapping(gpaField)
                												.summary();
		double avgGpa = summary.average();
		System.out.println("Average GPA : " + avgGpa);
    }

	void test(boolean maxGpa) throws Exception {
		try {
			time(maxGpa, #{
				if (maxGpa)
					findMaxSeniorGpa();
				else
					findAverageGpa();
			});
		} catch (final Throwable t) {
			throw t;
		}
	}

	public static void main(String[] args) throws Exception {
		TimedAggregateOps tao = new TimedAggregateOps();
		tao.test(true);
		tao.test(false);
	}
}

The client code that consumes this parallel Collections library has become more concise and removes much of the boilerplate with the use of Lambda expressions. Lines 36-50 in the earlier example is reduced to Lines 44-45 in this example. When these libraries take advantage of Lambda expressions, implementations would become powerful and more efficient. For example, much of the today’s verbose APIs such as map, reduce, filter defined in ParallelArray class would benefit from executing block of code using Lambda expressions. I recommend watching Closures Cookbook JavaOne 2008 presentation from Neal Gafter.

You can run this example using the prototype compiler that supports Lambda expressions. The batch scripts used in my original post should be updated to include JSR166y libraries in classpath, which you could download from JSR-166 maintenance website.

javac.bat

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

java.bat

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

Possibly Related Posts:


Recently, Brian Goetz published modified draft of the Lambda proposal. This draft is mature in terms of the direction where Lambda is heading for in the Java world and introduces some breaking changes from earlier draft to align with this direction. While there are few things that need to be sorted out, this draft is simple to understand, unlike the earlier proposals we have seen. Last week, Maurizio pushed an updated prototype that aligns with this new draft.

Lambdas (originally knows as Closures) 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("Processing a short-lived asynchronous task.");
            }
        });

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 :

        final ExecutorService executor = Executors.newCachedThreadPool();
        // assignment context
        Runnable task = #{ System.out.println("Processing a short-lived asynchronous task.") }; //take1
        executor.submit(task);
        // cast target context
        task = (Runnable)#{System.out.println("Processing a short-lived asynchronous task.")}; //take 2
        executor.submit(task); 
        // method invocation context
        executor.submit((Runnable)#{System.out.println("Processing a short-lived asynchronous task.")}); //take 3

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

	String[] teams = {"Violet", "Indigo", "Blue", "Green", "Yellow", "Orange", "Red"};
	final Comparator<String> c = #{s1, s2 -> s1.length() - s2.length()};
	Arrays.sort(teams, c); //take1
	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 latest JDK 7 build).

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. I tested with the recent JDK 7 build (b115).

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:\JDK7\lambda\samples>javac.bat -version
javac 1.7.0-internal

Let us look at a simple example:

public class SimpleLambda {
	abstract class HelloWorld {
		abstract 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.

	interface Squarer<X, Y> {
		Y square(X x);
	}
	{
		Squarer<Integer, Integer> s = #{ Integer 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 or an abstract class 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(“Processing a short-lived asynchronous task.”) };

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


Lambda expressions begin with ‘#’ special character and an arrow token ‘->’ is used to separate the formal parameters from the body of the Lambda. In case of single line Lambda expression, return keyword and trailing semicolon can be omitted. For nilary Lambda expression, the arrow token can be omitted.

Lambdas in Java exhibit the following behavior :

  • An interface, or abstract class, with exactly one abstract method are referred to as a SAM types.
  • Lambdas are not instances of classes.
  • Lambdas are converted to SAM types.
  • 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.

	enum Decision {
	    APPROVE, DECLINE, APPROVE_REFER
	}

	abstract class DecisionService {
	    abstract 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());
	}

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

	class Payment {
		private int amount;
		Payment(int amount) {
			this.amount = amount;
		}
		public int getAmount() {
			return amount;
		}
	}
	interface PaymentProcessor {
		void process(Payment pmt);
	}
	{
		invokeProcessor(#{pmt -> log("Processed # " + pmt.getAmount() + " at " + new Date())});
	}
	void invokeProcessor(PaymentProcessor processor) {
		processor.process(new Payment(42));
	}

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

Extension Methods

One of the significant benefits of Lambdas is that it enables the development of more powerful libraries with less code and more efficiency. To enhance the core libraries to take advantage of these powerful language features without compromising backward compatibility, the concept of public defender methods was introduced. This proposal suggests adding virtual extension methods to existing interfaces allowing the use of new language features to enhance the capabilities of core libraries.

While, extension methods by itself is more useful and when combined with Lambdas, they can be powerful. The traditional way of sorting a collection.

        Collections.sort(people, new Comparator<Person>() {
            public int compare(Person x, Person y) {
                return x.getLastName().compareTo(y.getLastName());
            }
        });	        

With Lambdas, this can be expressed more concisely (this works with the prototype).

Collections.sort(people, #{ x, y -> x.getLastName().compareTo(y.getLastName()) });

And this still leaves room for improvement where virtual extension methods come to rescue. When core libraries are enhanced to take advantage of Lambda expressions, this can be made less verbose.

people.sortBy(#Person.getLastName);

Virtual extension methods are declared using the ‘extension’ keyword.

public interface List<T> extends Collection<T> {
	// .... The existing List methods 
  	extension void sort() default Collections.sort;
}

When Collections library is enhanced to support extensions methods, we should be able to use many of the Collections APIs directly in a collection:

List.sort();
//instead of
Collections.sort(List);

Some of these minor improvements are most sought after and makes Java less verbose and one less class to deal with.

Conclusion

I haven’t touched upon other fundamental concepts such as Exception transparency, Method references and Lexical Scoping. I will be covering them once I do some hands-on with these concepts. The prototype is still evolving around these areas and has made some good progress in catching up with this new draft. As we know, Lambdas are scheduled to go in Java 8 (in late 2012), almost six years after Closures were originally proposed in 2006. I believe there are plans to make binary builds available for all platforms, so the hassle of building from the source would no longer be required.

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

Update (10/25/2010) : Omitted the use of optional trailing semicolon and return keyword in single line Lambda expressions.

Update (6/11/2011) : The definition of SAM types have changed since this post was originally written. Here is the latest definition.

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 overridden 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 sub-signature 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 sub-signature of all other methods

With these new rules, some of the examples won’t compile. Abstract classes with single abstract method are no longer considered valid SAM types. Switching to an interface should fix these examples.

Possibly Related Posts:


Project Coin includes the following proposals that will make into Java 7.

Binary literals and underscores in literals

Strings in switch

– Simplified Varargs Method Invocation

– Improved Type Inference for Generic Instance Creation (Diamond)

– Improved Exception Handling for Java

– try-with-resources (ARM)

I have briefly touched upon try-with-resources construct in my earlier post. ARM was implemented in July and JDBC APIs were recently retrofitted to support these changes. In this installment, I will give you an overview of other Coin proposals.

Binary literals and underscores in literals

This feature is again we are trying to catch up with languages such as Ruby and Python where this is already supported.

You need to prefix the literal with 0b or 0B. Now, we can define binary literals in our code as show below.

int maxInteger = 0b01111111111111111111111111111111;// Integer.toBinaryString(2147483647)
byte nybbles = 0b00100101;// Math.pow(2, 5)+Math.pow(2, 2)+Math.pow(2, 0) = 37

Now, this can be better represented visually using underscores, which is addressed in the supplementary proposal:

int maxInteger = 0b0111_1111_1111_1111_1111_1111_1111_1111;// Integer.toBinaryString(2147483647)
byte nybbles = 0b0010_0101;// Math.pow(2, 5)+Math.pow(2, 2)+Math.pow(2, 0) = 37

Some more common usage of this feature,

int phoneNumber = 123_456_7890;
long creditCardNumber = 1234_5678_9012_3456L;
int socialSecurityNumber = 999_99_9999;
int hexEquivalentOfIntegerMAX = 0x7f_ff_ff_ff;// Integer.toHexString(2147483647)
int hexBytes = 0xFF_EC_DE_5E;// Integer.toHexString(-1253794)
int hexWords = 0xFFEC_DE5E;// Integer.toHexString(-1253794)
long maxLong = 0x7fff_ffff_ffff_ffffL;// Long.toHexString(9223372036854775807L)
int weirdBitfields = 0b000_10_101;// Integer.toBinaryString(21)

System.out.println("The value 10100001 in decimal is " + 0B10100001);// 161

More advanced example (from the proposal), do you see the happy face in bitmap?

// Binary literals can be used to make a bitmap more readable:
public static final short[] HAPPY_FACE = {
       (short)0b0000011111100000,
       (short)0b0000100000010000,
       (short)0b0001000000001000,
       (short)0b0010000000000100,
       (short)0b0100000000000010,
       (short)0b1000011001100001,
       (short)0b1000011001100001,
       (short)0b1000000000000001,
       (short)0b1000000000000001,
       (short)0b1001000000001001,
       (short)0b1000100000010001,
       (short)0b0100011111100010,
       (short)0b0010000000000100,
       (short)0b0001000000001000,
       (short)0b0000100000010000,
       (short)0b0000011111100000
};

This feature was implemented more than a year ago.

Strings in switch

We are familiar with the purpose of switch and what types are allowed in them.

A simple example from the Joe Darcy’s JavaOne Coin presentation:

    GregorianCalendar c = new GregorianCalendar();
    int monthNameToDays(String s, int year) {
        switch (s) {
            case "April":
            case "June":
            case "September":
            case "November":
                return 30;
            case "January":
            case "March":
            case "May":
            case "July":
            case "August":
            case "December":
                return 31;
            case "February":
                int days = 28;
                days += c.isLeapYear(year) ? 1 : 0;
                return days;
            default:
                return -1;
        }
    }

Here is a more complex one with nested switch :

public class SwitchTest {
    private static class Member {
        int id;
        String type;
        String category;

        private Member(int id, String type, String category) {
            this.id = id;
            this.type = type;
            this.category = category;
        }
    }

    public static int getMemberFee(Member member) {
        int fee = 50;
        switch (member.type) {
            case "BUSINESS":
                switch (member.category) {
                    case "LICENSED":
                    case "GOVERNMENT":
                    case "FARMERS":
                    case "RANCHERS":
                        break;

                    case "NON_PROFIT":
                        fee = 25;
                }
            case "GOLD_STAR":
                break;
            case "EXECUTIVE":
                fee = 100;
                break;
        }
        return fee;
    }

    public static int getMemberDiscount(Member member) {
        int discount = 5;
        switch (member.type) {
            case "BUSINESS":
                discount = 10;
                //fall through
            case "GOLD_STAR":
                break;
            case "EXECUTIVE":
                discount = 15;
                break;
        }
        return discount;
    }

    public static void main(String... args) {
        Member member = new Member(1234_5678_90, "BUSINESS", "NON_PROFIT");
        System.out.println("$" + SwitchTest.getMemberFee(member) + " fee for " + member.category);
        System.out.println(SwitchTest.getMemberDiscount(member) + "% discount for " + member.category);
    }
}

This feature was implemented almost a year ago.

Simplified Varargs Method Invocation

Before going into the details of this proposal, I would like to provide some background so it helps to understand the problem better. One of the well known restrictions introduced by Generics is its inability to create generic arrays. For example, the following code would not compile in Java:

    public static List<String>[] mergeLists() {
        List<String> a = Arrays.asList("one", "two", "three");
        List<String> b = Arrays.asList("four", "five", "six");
        return new List<String>[]{a, b};  // compile-time error: generic array creation
    }

For instance, let us compile the above code using Java 6 compiler using the printflat hidden option

javac -d /tmp -XD-printflat MergeLists.java

The generated file in /tmp would look something like:

    public static List[] mergeLists() {
        List a = Arrays.asList(new String[]{"one", "two", "three"});// type information is lost here
        List b = Arrays.asList(new String[]{"four", "five", "six"});// type information is lost here
        return List[] {a, b};// added for completion, this is illegal.
    }

As a consequence of Generics, type information is erased after compilation, making it unavailable at run time. So, types such as E, List, and List are called non-reifiable types [JLS 4.7]. Varargs are implemented as an array of objects and can hold only reifiable types.

When a programmer tries to invoke a varargs method with non-reifiable varargs type, the compiler currently generates an “unchecked” warning. This proposal moves the warning from the call site to the method declaration.

    static List<List<String>> listOfListOfStrings() {
      List<String> a = new ArrayList<String>(), b = new ArrayList<String>(), c = new ArrayList<String>();

      // Warning: [unchecked] unchecked generic array creation for varargs parameter of type List<String>[]
      return Arrays.asList(a, b, c);
    }

It looks like a new annotation is being planned to support this at the declaration and varargs warnings will be revised. Callers may be able to remove @SuppressWarnings(“unchecked”) from their code once this is supported by the compiler. This support is not yet available as of build b114.

Improved Type Inference for Generic Instance Creation (Diamond)

This one is much easier of all the Coin proposals, at least in terms of simplicity and eliminates much of the Generics verbosity. Generics enforced type redundancy during declaration. For example, the traditional way (>=1.5) of declaring a Generic type is shown below.

    static class Library<E> {
        Set<Method> methods = new HashSet<Method>();

        Library(Set<Method> methods) {
            this.methods = methods;
        }
    }

    Set<Method> methods = new HashSet<Method>();
    Library<Set<Method>> library = new Library<Set<Method>>(methods);

Now, with this language support, the declaration can be simplified as shown below:

    static class Library<E> {
        Set<Method> methods = new HashSet<>(); // saves typing

        Library(Set<Method> methods) {
            this.methods = methods;
        }
    }

    Set<Method> methods = new HashSet<>(); // saves typing
    Library<Set<Method>> library = new Library<>(methods); // saves typing

While libraries such as Guava have attempted similar support for this, language level sugar is more intuitive than alternatives. This feature was implemented more than a year ago.

Improved Exception Handling for Java

Prior to Java 7, it was very cumbersome to catch multiple exception types leading to boilerplate code. This proposal addresses this concern by catching multiple exception types with a single catch clause and improves checking for rethrown exceptions.

Here is a simple class we will be using to test reflection:

public class CoinByReflection {
    public int code = 10_10_2010;

    public void printTheme() {
        System.out.println("Making things programmers do everyday easier.");
    }
}

This pattern is noticed when working with reflective operations where we may need to handle different types of exceptions.

    public void multicatch() throws ClassNotFoundException, InstantiationException, NoSuchMethodException, NoSuchFieldException, IllegalAccessException, InvocationTargetException {
        try {
            Class clazz = Class.forName("CoinByReflection");
            Object instance = clazz.newInstance();
            Field field = clazz.getField("code");
            int code = field.getInt(instance);
            System.out.println(code);
            Method method = clazz.getMethod("printTheme");
            method.invoke(instance);
        } catch (ClassNotFoundException cnfe) {
            log(cnfe);
            throw cnfe;
        } catch (InstantiationException ie) {
            log(ie);
            throw ie;
        } catch (NoSuchMethodException nsme) {
            log(nsme);
            throw nsme;
        } catch (NoSuchFieldException nsfe) {
            log(nsfe);
            throw nsfe;
        } catch (IllegalAccessException iae) {
            log(iae);
            throw iae;
        } catch (InvocationTargetException ite) {
            log(ite);
            throw ite;
        }
    }

With this proposal, we should be able to simplify the exception handling when performing reflection with single catch.

    public void singlecatch() throws ClassNotFoundException, InstantiationException, NoSuchMethodException, NoSuchFieldException, IllegalAccessException, InvocationTargetException {
        try {
            Class clazz = Class.forName("CoinByReflection");
            Object instance = clazz.newInstance();
            Field field = clazz.getField("code");
            int code = field.getInt(instance);
            System.out.println(code);
            Method method = clazz.getMethod("printTheme");
            method.invoke(instance);
        } catch (final ClassNotFoundException|
        InstantiationException |
                NoSuchMethodException |
                NoSuchFieldException |
                IllegalAccessException |
                InvocationTargetException
        e){
            log(e);
            throw e;
        }
    }

ReflectiveOperationException, a new common super class of exceptions thrown by reflective operations was introduced to simplify this further. You can catch this exception and precisely rethrow one of the exceptions defined in the method signature.

    public void singlecatch() throws ClassNotFoundException, InstantiationException, NoSuchMethodException, NoSuchFieldException, IllegalAccessException, InvocationTargetException {
        try {
            Class clazz = Class.forName("CoinByReflection");
            Object instance = clazz.newInstance();
            Field field = clazz.getField("code2");
            int code = field.getInt(instance);
            System.out.println(code);
            Method method = clazz.getMethod("printTheme");
            method.invoke(instance);
        } catch (final ReflectiveOperationException e){
            log(e);
            throw e;
        }
    }

This feature was implemented in May.

Conclusion

With more than 80% of the Coin features implemented and “ready” for battle test, it is evident from the fact that these features live up to its expectations:

Making things programmers do everyday easier.

[as quoted from JavaOne Coin presentation]. Now that we have a definitive plan for Java 7, IDEs should start supporting these features as mid-2011 is not very far and play a vital role in accelerating adoption of these new syntaxes. It looks like Coin 2 will include other interesting proposals such as Collection literals, Multi-line strings, Large arrays, etc, possibly for Java 8?

Recently, NetBeans announced that it will support JDK 7 language features in its forthcoming 7.0 release and Eclipse plans to include Java 7 support in its next release 3.7 (Indigo). Intellij 9 has some support for Java 7, and I hope Intellij X brings the rest.

Possibly Related Posts:


Try-with-resources (originally known as Automatic Resource Management) is one of the Project Coin proposals that made its way into recent JDK 7 builds. Traditionally, developers had to manually terminate any resources (Files, Database connections, etc) they use in their applications and sometimes it was painful to keep track of those things and failing to do so may have serious problems such as resource leaks which could potentially lead to application failures that are hard to debug and triage. The burden of managing resources is no more a developer’s headache as this will be natively supported in Java 7.

C# has “using” blocks and C++ destructors served a similar purpose. This is a more sought after language feature for years and Joshua Bloch brings this to real for Java developers with some syntax sugaring. While this construct looks alien to Java, I believe this is something we have to accept and move forward as this solves common programming errors. IDEs can fill this space to support intelligent code completion for ARM constructs and make it easy for developer adoption. The other disadvantage outlined in the proposal is increased coupling between the language specification and libraries. To support this feature, a class must implement a designated interface AutoCloseable to make it eligible for automatic resource management.

Let us look at the example used in the ARM proposal, copying a file involving two resources.

    public void copy(String src, String dest) throws IOException {
        InputStream in = new FileInputStream(src);
        try {
            OutputStream out = new FileOutputStream(dest);
            try {
                byte[] buf = new byte[8192];
                int n;
                while ((n = in.read(buf)) >= 0)
                    out.write(buf, 0, n);
            } finally {
                out.close();
            }
        } finally {
            in.close();
        }
    }

With the new try-with-resources construct, we should be able to rewrite the above code with much simplicity:

    public void copy(String src, String dest) throws IOException {
        try(InputStream in = new FileInputStream(src);
            OutputStream out = new FileOutputStream(dest)){
            byte[] buf = new byte[8192];
            int n;
            while ((n = in.read(buf)) >= 0)
                out.write(buf, 0, n);
        }
    }

The bloated code we use these days will become more crisp with fewer lines of code, while continuing to maintain readability.

Java APIs that involve dealing with resources are mostly retrofitted to support this new AutoCloseable interface. This feature brings heap of benefits to the JDBC world where this may prove very useful when managing database connections and its subsidiaries.

Here is the traditional way of programming in JDBC where the user has to manage JDBC resources such as ResultSet, Statement and Connection.

        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            conn = DriverManager.getConnection("jdbc:h2:mem:test", "sa", "");
            stmt = conn.createStatement();
            rs = stmt.executeQuery("SELECT * FROM INFORMATION_SCHEMA.USERS");
            while (rs.next()) {
                System.out.println(rs.getString(1));
            }
        } catch (SQLException e) {
            // handle exception
        } finally {
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                }
                rs = null;
            }
            if (stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException e) {
                }
                stmt = null;
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                }
                conn = null;
            }

        }

You guessed it right, there is so much boilerplate code that is involved here. Here is the same code with our try-with-resources construct.

        try(Connection conn = DriverManager.getConnection("jdbc:h2:mem:test", "sa", "");
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery("SELECT * FROM INFORMATION_SCHEMA.USERS")) {// no trailing semicolon in the last line of the block containing automatic resource definition
            while (rs.next()) {
                System.out.println(rs.getString(1));
            }
        } catch (SQLException e) {
            // handle exception
        }

Wow, it is compact and powerful. JDBC support for the new try-with-resources construct will be part of JDBC 4.1 specification and the implementation is available in the recent JDK 7 build 112.

In these try-with-resources examples, an exception thrown during the lifetime of a try-with-resources statement receives priority over an exception thrown by an automatically generated close invocation. The proposal addresses automatic retention of those suppressed exceptions which are associated with the primary exception thrown during the try-with-resources statement.

The following methods are added to java.lang.Throwable to support extraction of these suppressed exceptions.

    public synchronized void addSuppressedException(Throwable exception);

    public synchronized Throwable[] getSuppressedExceptions();

You may want to go through the recent JavaOne presentation which details Project Coin features that are included in Java 7, slated for release in mid 2011.

Do you think Project Coin will become a crown jewel of Java 7, since Lambda expressions and Project Jigsaw are no longer the main contenders? In the coming days, I will be exploring many other language features that are included in Java 7 and help you decide the crown jewel of Java 7.

Keep watching this space for more Java 7 delicacies 🙂

Possibly Related Posts: