Java8 isn’t scheduled for for release until March 2014, but early release versions have been available for a while. Some of the most interesting new features of Java 8 are:
- Streams
- Functional interfaces
- Default methods
- Lambdas
- Java Time
Streams
The new java.util.stream package contains “classes to support functional-style operations on streams of elements”. Streams aren’t a new type of collection and don’t replace any of the existing ones such as Lists and Queues. Instead, they provide a way to interact with an existing collection, and in that respect are more similar to iterators.
The javadocs describe a stream as “a sequence of elements supporting sequential and parallel aggregate operations.” A stream pipeline consists of a source (e.g. a collection), intermediate operations (e.g. a filter or map) and a terminal operation, which produce a result (e.g. sum or count). Streams are lazy in that the operations on the data are only performed at the last minute i.e. when the terminal operation is called, and the stream is processed only once.
For example:
int totalFxTrading = blocks.stream()
.filter(trade -> trade.getType() == FX)
.mapToInt(b -> b.getTradedAmount())
.sum();
Functional interfaces
Java 8 will have a new feature called functional interfaces. A functional interface has exactly one abstract method. There are many such interfaces that you have probably used as a Java developer, such as Runnable, ActionListener, Comparator and Callable. In Java 8 these types of interfaces are now more formally called Functional interfaces. They can be identified using a new @FunctionalInterfaceannotation, and most importantly, can be represented using Lambda expressions (more later). For example, to use an ActionListener in the past, you needed to create an implementation, often using an anonymous inner class.
For example:
JButton button = new JButton();
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
System.out.println(ae.getSource());
}
});
Using functional interfaces, this becomes much simpler:
JButton myButton = new JButton();
button.addActionListener(
ae -> {System.out.println("You clicked the button");}
);
We never need to even mention ActionEvent – the compiler derives the type of ‘ae’ from the context. Note that the @FunctionalInterfaceannotation, like the @Override annotation, is not required. Instead it signals to the compiler your intentions so that it can warn you if something looks amiss e.g. more than one abstract method is available.
Default methods
Prior to Java7, an interface was a fairly simply thing. It could contain abstract methods only (and constants) which had to be implemented by concrete subclasses. An interface was basically a bunch of method signatures, but could never contain a method definition/implementation.
In Java8, things gets more interesting. Default methods can now be added to an interface. These are methods that do have an implementation, do not have to be overridden in the interface implementation and can be run directly from the interface.
These default methods were added as a necessity to provide backwards compatibility. If they had not been added, it would not have been possible to extend/improve the existing collection interfaces, for example, without breaking all the implementations. So for that reason, default methods are sometimes referred to as defender methods.
To me, the really interesting thing about default methods is that they allow a form of multiple inheritance. Since a class can implement more than one interface, and each of those interfaces can now potentially have a default method with the same name, which version does the subclass inherit? I think this is referred to as the diamond problem. If such a scenario arises when using Java8, the compiler will provide a warning. You can use the syntax X.super.m(…) to explicitly choose one of the parent class’s implementations.
On a side note, why do these new default methods need the default keyword at all? Couldn’t they have worked just as well without that keyword? The answer is yes, the default keyword is redundant, just like the abstract keyword. Both were added to make things a little more clear. This post has some more details are links.
Lambda
According to Wikipedia, a lambda expression is “a function defined without being bound to an identifier”. Lambda expressions are coming to Java in version, designed to allow code to be streamlined.
Many of the other changes I discussed above(default methods, functional interfaces) are very closey related to the introduction of lambas.
When a Lambda expression is written, it is translated into a functional interface at compile time. Here is an example of using Lambda expressions to replace an anonymous inner class with much cleaner and more readable code.
Old way without Lambda:
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
System.out.println(“Action Detected”);
}
});
New way with Lambda:
button.addActionListener(e -> {
System.out.println(“Action Detected”);
});
Using Lambda expressions will often make the code easier to read and require fewer lines.
Java time
Dealing with dates and time in Java has never been ideal. At best it has been quirky, and at worst, a bit of a nightmare. The Date class was clunky and is now littered with deprecated methods. The Calendar class was an improvement, but I personally always seem to spend more time that I would like having to trawl through the API docs, even for things I have done before. Other 3rd party libraries tried to deal with times in a more elegany fashion (e.g. Joda time). There have been rumors of improved handling in Java itslef anf with Java8, it is here – the java.time package.
A new (abstract) Clock class provides some useful static methods such as systemUTC() and systemDefaultZone() to get the current time and timezone. And a number of new classes such as LocalDate and LocalTime, and YearMonth and MonthDay provide more elegant handing of day to day (pardon the pun) date operations.
What’s not in Java8
On a side note, although date/time handling will be improved in Java8, amazingly there is still no good way to handle currency in Java (something I have blogged about in the past). Doubles (and all floating point numbers) are inherently unsuitable for money, or anywhere exact calculations are required. Using int or long requires keeping track of decimal points, and BigDecimal isn’t ideal either.Those guys may improve things, but it looks like we will have to wait until Java 9 for that :-)