Our Thinking

Brace Yourselves - Java 8 is Coming! (Part 1 of 3)

Posted by Dave Gillies on Mar 18, 2013 10:11:25 AM

In the fictional lands of Westeros, the inhabitants recoil at Eddard Stark's warning of a long, many year winter as told by George R. R. Martin in A Game of Thrones. In the real world, Java 8 is coming into a world of Java that is as much in the midst of storm and turmoil as that of the House Stark of Winterfell.

Java suffered a public relations nightmare in 2012, taking a beating over security holes and exploits, at one point having both the US Department of Homeland Security and Apple publishing “considered harmful” messages. Despite this, Java finds itself back on top of the Tiobe Programming Community Index, retaking the position from C in recent months. Java 6 support ended at the end of February 2013; Java 7 has been heavily adopted. Has Java 7 been a success? That's a question requiring its own analysis, however, it's clearly not a resounding yes.

So then, Java 8 is expected in September 2013. It will include a number of deferred features that were originally planned for Java 7 and also some new ones. For a full run down of JDK enhancement proposals that were accepted and funded, check out the JDK8 features page. Or, go and download the JDK 8 Early Access and start playing with the new features now. Will this be the new release that developers have really been clamoring for? In this series, I will focus on a few features that have been anxiously awaited and discuss what I think they might mean to the community.

First up, Project Lambda. Essentially, Project Lambda (JSR 335) is about modeling code as data. In simplistic terms, being able to pass functions as first-class objects opens up some powerful constructs to programmers. The Java language is being extended in four ways to accomplish this.

Lambda Expressions

"Lambda Expressions," sometimes referred to as "Closures," will allow the programmer to store a piece of executable code as a variable, passed to a method as an argument or used as a return value in a method. A great example is this ugly use of anonymous classes for collection manipulation.

List students = // ...
students.filter(new FilerFunction() {
@Override
public boolean filter(Student s) {
return s.getEntryYear() == 2011;
}
}).map(new MapFunction () {
@Override
public Integer map(Student s) {
return s.getGrade();
}
}).reduce(new ReduceFunction () {
@Override
public Integer reduce(Integer value1, Integer value2) {
Math.max(value1, value2);
}
});

With lambdas, this could be rewritten as:

List students = // ...
students.paralell()
.filter(s -> s.getEntryYear() == 2011)
.map(s -> s.getGrade())
.reduce(Math::max)

It should be evident that the style of lambdas provides a concise syntax in a way that anonymous classes cannot.

Arrays and collections, which are heavily used by all programmers, rely on external iteration, meaning heavy use of loops over the core to execute. Lambdas will provide internal iteration, where the data structure gets passed a piece of code to execute. There is potentially a large advantage here, as the data structure has self-familiarity so can choose a better scheduling of the computation by tuning execution order, concurrent execution with threads, or even parallel execution. This will also open up new solutions that harness multiple processor cores.

Closures are supported in many common object-oriented languages already, notably C# in the .NET world and Groovy, Ruby and Scala as 3 languages that run alongside Java on the JVM. Java programmers are increasingly aware of and familiar with the programming models that these languages support, so closures have been the most asked for feature in Java for a very long time.

There are some that have complained about the syntax, but by and large, developers will be pleased with the addition of this feature and the flexibility it provides. It will take some time for developers to learn and fully adopt the new idioms. Java still isn't fully object oriented, so developers still won't be able to call closures on primitive types for example. They will end up reverting to the loop more often than in other languages like Groovy or Ruby, so won't become as Lambda-savvy as quickly as adopters of those languages. So it’s a win, but Java programmers still can’t adopt a style such as this in Ruby:

12.times do
puts “This get output 12 times”
end

At least anonymous classes will go away! And, it’ll be especially interesting to see how libraries might provide richer, more flexible interfaces using Lambdas.

Expanded Target Typing

"Expanded Target Typing" will allow programmers to bind the Lambda Expressions to objects of a specific type. These types can be a controversial new construct called "Functional Interfaces" which are Java interfaces with exactly one method.

Consider the FileFilter interface that when implemented allows a developer to filter a directory listing:

public interface FileFilter {
boolean accept(File pathname);
}

An example of using this to list Java source files might be:

File[] sourcefiles = directory.listFiles(new FileFilter() {
public boolean accept(File file) {
return file.getName().endsWith(".java");
}
});

Using Lambdas, we could rewrite this as:

File directory = new File("src");
directory.listFiles((File file) -> file.getName().endsWith(".java"));

However, the Lambda expression’s signature is compatible to the signature of the single method of the interface, so target typing allows you to shorten this to:

File directory = new File("src");
directory.listFiles(file -> file.getName().endsWith(".java"));

This syntactic sugar will definitely be appreciated, especially by those who have complained about the syntax for Lambdas in general.

Method and Constructor References

"Method References" and "Constructor References" will allow existing methods on objects to be bound to a Functional Interface. Programmers can reference a method using the :: syntax. Method references are treated the same way as Lambda expressions and can be used wherever a functional interface is accepted. Method References refer to a method and allow it to be passed without executing it. For example:

class SomeClass {
private static void saySomething() {
System.out.println("Hi");
}
private void saySomethingElse() {
System.out.println("Bye");
}
public static void main(String… args) {
SomeClass sc = new SomeClass();
SomeService service = new SomeService();
service.doSomething(SomeClass::saySomething());
service.doSomething(sc::saySomething());
}
}

Constructor references are similar, but will allow class constructors to be transformed into factories. Constructor References are used to refer to a constructor without instantiating the named class. For example:

java.util.functions.Factory
    
  
  
  
    cookieFactory = Cookie::new; 
   
Cookie cookie = cookieFactory.make();

Lambdas are convincing. However, there are constructs, especially involving checked expressions, where Lambdas are still not pretty and don't fit on a single line and where you may be better off with a method reference. They are a nice addition, but not earth shattering. Constructor references offer even more power and will be a nice way to implement the Factory pattern.

Virtual Extension Methods

"Default Methods" or "Virtual Extension Methods" allow programmers to add more methods to existing interfaces without breaking exiting implementations.

You might know these as "mixins" in about two dozen other languages. Using the "default" keyword, methods can be added to interfaces, allowing implementations to override, but executing this code if they don't.

This construct was added to allow existing APIs to have new methods added without adding method signatures to existing interfaces and breaking all the code out there. For example, getFirst() has been added to the Iterable<T> interface. This returns the first element from the iterable, but existing binaries won't break if executed against the new Java 8 environment. Even a custom Iterable with a custom getFirst() method will work, calling that code and ignoring the new virtual extension method. For example:

interface Animal{
default public String speak() {
return "Hi!";
}
}

class Dog implements Animal {}

class Cat implements Animal {
public String speak() {
return "Meow!";
}
}

class TestAnimal {
public void main(String… args[]) {
Animal dog = new Dog();
Animal cat = new Cat();
System.out.println(dog.speak());
System.out.println(cat.speak());
}
}

Returns:

Hi!
Meow!

This will elicit a very mixed reaction. Already the debate has begun. "Interfaces do not hold implementation details" will no longer be true and some will see this as pollution in the already tenuous interfaces vs. abstract classes design discussion. Some will point out that it is likely to be abused when creating inheritance hierarchies. Others will point to the success of mixins in any number of other languages as a great way to offer multiple inheritances without the headaches of constructor chaining, name interference and polymorphic ambiguity. Many will agree that it's a far better solution than breaking existing code bases and making the move from Java 7 to 8 more difficult.

All in all, Lambdas are exciting, long awaited addition to the Java language. The syntax has been evolving over the past years and, while still controversial, has been cleaned up and simplified. Will you be using Lambas in the fall?

Please tune in later for an upcoming post where I’ll discuss these other changes coming in Java 8:

  • Date and Time (JSR 310)
  • Type Annotations (JSR 308)
  • Metaspace replacing PermGen (JEP 122)
  • Project Nashorn Javascript Engine (JEP 174)

I’ll also talk about Project Jigsaw, the effort to bring full modularization to Java, something that was originally planned for a Java 7 release, delayed to Java 8, and just this past month, deferred again until Java 9.

 

Topics: Languages

Our Thinking - The Online Blog is a source for insights, resources, best practices, and other useful content from our multi-disciplinary team of Onliners.

Subscribe to Blog Updates