Pages - Menu

Friday, September 21, 2012

Start Hacking With Java 8

This article aims to give some quick background on Java 8 and help you get set up so you can try out the new features. Java veterans (and PL veterans) won't learn anything new, this article is for general Java programmers who want to learn more about what's coming next year.

The list of planned features for Java 8 is available on the OpenJDK page.

I intend to follow up with articles describing each new feature in further details so stay tuned. In the mean time, you can read more about lambdas, virtual extension methods and type annotations.

Background

We have shifted from a single core world to a multi core world. In fact, we have reached a physical limit to how many transistors can fit on a chip. For this reason, to perpetuate Moore's law, today we achieve additional performance by parallelizing computations across several cores.

This shift brings new challenges. Programmers need to learn how to write software that parallelize gracefully to leverage multiple cores and therefore gain more performance.

Programming language designers can help by providing better abstractions and easier to use libraries with the goal to reduce the conceptual and syntactic gap between sequential and parallel expression of a computation.

Functional to the rescue?

Functional programming provides a mechanism to achieve this goal. In fact, a computation is described as a combination of functions that are side-effect free. In practice, this allows to specify what a computation does and let the compiler decide how to implement it. The programmer doesn't specify how the computation is implemented anymore.

Take as an example, a code to filter a list based on a condition in Scala:

val listOfRedBoxes = boxes.filter(b => b.getColor() == RED);

This is possible through the use of the filter method which abstracts away the internal filtering implementation. One can pass as an argument an anonymous function that evaluates to the filtering condition. Other programming languages such as Groovy, Clojure provide similar facilities to pass code as data, which many refer to as closures. As a result, the compiler can decide whether the filtering logic should be executed sequentially or in parallel.

Contrast the code above with the typical Java idiom that programmers write to filter a list based on a condition:

List<Box> listOfRedBoxes = new ArrayList<>();
for(Box b : boxes)
{
    if(b.getColor().equals(RED))
        listOfRedBoxes.add(b);
}

Here, the use of an accumulator and a for-each loop to describe the traversal logic of the filtering enforces a sequential execution. Sometimes a for-each loop is desirable as it is in-order, however, sometimes this specification is too tight and prevents additional performance.

Java 8 brings a revamped collection library together with a mechanism to pass code as data refered to as lambda expressions in order to facilitate writing code that parallelize gracefully.

The example above can be written as follows:

List<Box> listOfRedBoxes = boxes.stream().filter(b -> b.getColor().equals(RED))
                                .into(new ArrayList<Box>());

The traversal logic is not fixed by the language anymore and can be chosen by the library implementation or compiler. As a result, paralellism and out-of-order execution can be chosen to improve performance.

One could argue that passing code as data in Java is already possible via anonymous inner classes. However, lambda expressions bring many advantages over anonymous inner classes such as better readability, simpler semantics and stronger inference which we discuss in more details in the next article.

Set Up JDK8

At the time of this writing, there isn't a stable version of jdk8 yet. However, you can download an early access implementation of the lambda project and a separate early access implementation of the type annotations project.

After downloading the archive containing the jdk, set the environment variable JAVA_HOME to the path where the unpacked directory is located. To check it's set up correctly, try the following commands:

$ java -version
openjdk version "1.8.0-ea"
OpenJDK Runtime Environment (build 1.8.0-ea-lambda-nightly-h1171-20120911-b56-b00)
OpenJDK 64-Bit Server VM (build 24.0-b21, mixed mode)

$ javac -version
javac 1.8.0-ea

You can now try the following code:

import java.util.*;
public class TestLambda
{
    public static void main(String... args)
    {
        List<Integer> l = Arrays.asList(1,2,3,4,5);
        int sum = l.stream().map(x -> x*2).reduce(0, (a,b) -> a+b);  
        System.out.println(sum);
    }
}

Can you guess the output? Compile it and run it!

$ javac TestLambda.java 
$ java TestLambda
30

Note that most IDEs don't provide support for Java 8 yet so you will have to compile files using javac.

IntellJ seems to be the only IDE supporting lambdas at the moment.

Start hacking!

Monday, September 3, 2012

Java 8 Features: Discover Repeating Annotations

Java 8 will bring many features including lambdas, virtual extension methods, type annotations as well as various library enhancements. The full list is available on the OpenJDK/JDK8 website.

In this blog post, I would like to describe a less advertised feature: repeating annotations. The implementation in the Java 8 compiler was pushed a few days ago. More information and discussions can be found on the dedicated OpenJDK mailing list. It is important to stress that this feature was designed for EE library designers and users. The usability requirements are therefore different than standard Java users.

Currently Java forbids more than one annotation of a given annotation type to be specified on a declaration. For this reason, the following code is invalid:

@interface Foo { int value(); }

@Foo(1) @Foo(2) // error: Duplicate annotation
class Functr{}

Java EE programmers often make use of an idiom to circumvent this restriction: declare a new annotation which contains an array of the annotation you want to repeat. It looks like this:

@interface Foo { int value(); }
@interface Foos {
    Foo[] value();
}

@Foos({@Foo(1), @Foo(2)})
class Functr{}

Java 8 essentially removes this restriction. Programmers will now be able to specify multiple annotations of the same annotation type on a declaration provided they stipulate that the annotation is repeatable. It is not the default behaviour, annotations have to opt-in to be repeatable.

A set up is required to specify that an annotation can be repeated. You specify the containing annotation type using @ContainedBy and the repeatable annotation type using @ContainerFor:

@ContainedBy(Foos.class)
@interface Foo { int value(); }

@ContainerFor(Foo.class)
@interface Foos {
    Foo[] value();
}

@Foo(1) @Foo(2) // valid in Java 8!
class Functr{}

There is some discussion as to why this set up is actually required because it adds code verbosity. In a nutshell, it is needed for compatibility reasons with the updated reflection API. In fact, the previous idiom and the new set up compile down to the same structure (provided @Retention(RetentionPolicy.CLASS) is specified on the annotations otherwise annotations are not stored in the generated class file by the compiler). For this reason, the reflection API needs a mechanism to differentiate between implicit and explicit repetitions. The language designers introduced the two new markups to tackle this issue.

Now you might ask why do we actually need @ContainedBy and @ContainedFor? Why do we have to define an extra container? We could just have one new annotation to specify an annotation type to be repeatable. The reason is that EE libraries use the previous idiom and language designers wanted to give them a straightforward transition to use repeating annotations. It is convenient to simply annotate the existing annotation declarations: the code update required is minor and low risk (nothing is removed).