Best of: Java 8
In the previous part, we looked at version 7 of Java. Now it’s time to look at its successor, Java 8, a really big update with lots of great new features!
Table of Contents
New language features
The general concept of an interface
got 2 great enhancements making it so much more possible.
default methods on interfaces
One of the big differences between an interface
and an abstract class
is the ability to actually design a contract (interface
) and design a contract and provide a partial implementation (abstract class
) of it.
The disadvantage of an abstract class
lies in Java’s single inheritance restriction.
So if you want to use a contract with some kind of default implementation AND inherit from another class (abstract or not) you were out of luck… until now!
Interfaces gained the ability to provide default
methods, and to implement methods directly in the interface
without the need to override it later in a class implementing that interface.
This way you can provide additional functionality by just implementing an interface
, without any additional code.
In contrast to an abstract class
you can’t use any outside resources (except static ones), no constructors, etc.
But it will still make it possible to save a lot of code:
In the implementation we might implement the #build(List)
method as a simple for-each-loop
with some additional null
checks, so why not provide this rudimentary functionality directly in the interface instead, so every implementation benefits from it:
Moving the code from the implementation to an interface makes sense if you want to reuse the interface
and not just for a 1:1 relationship.
This way you provide a senseful default implementation for everyone implementing the interface
.
And they still can override it if they need another behaviour.
Another great aspect of default
methods is the possibility to expand the contract provided by the interface
without breaking existing implementations:
We added 2 new methods that won’t break any existing implementation.
They even get an implemented #first()
method for free!
This is actually the way Java 8 extended a lot of interfaces with new behavior, without breaking everyone’s code.
See https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html for more info.
static interface methods
Another addition to interfaces is the ability to add static
methods. It’s a little bit like default
methods, but they can’t be overridden:
Functional Programming
Lambda expressions and Functional interfaces
One of the greatest additions, especially in combination with the new Stream API, are lambda expressions, making the many steps towards a more functional programming style.
A lambda expression is a function that lives without an associated class and can be passed around like any other object.
To make this possible the concept of functional interfaces
was created.
If an interface has only a single abstract method, you can implement it like lambda.
This rule can be bent by using default
methods, as long as you got only one abstract method.
Interfaces with just one abstract method are automatically functional interfaces, but you might also mark these interfaces with the new annotation @java.lang.FunctionalInterface
:
Now that we got a functional interface, let’s look at how to use it as a lambda expression. Anonymous classes were the way to go, implementing the abstract methods inline:
Now we can implement a method in a way with less visual noise: (arg0, arg1, ...) -> { return...}
.
The parentheses around the arguments are optional if there’s only one argument. And the curly braces and return
statement are optional, too, if only a single line of code would occupy the block.
Especially in combination with streams (a little down this post), or listeners and predicates, this will make your code way more readable with less typing:
See https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html for more infos.
Method references
To make lambdas even better you can also use method references which allows us to shortcut method invocations for easier reading your code.
Instead of calling myInstance.method(arg0)
you might use myInstance::method
if another method expects an lambda as argument:
We can also call instance methods of the incoming parameters directly via the type:
And of course we can use constructors, too, by referencing new
:
Java Stream API
This is the other big thing in this update that makes our Java developer life much easier. The Java Stream API JSR-335 provides a more functional approach to working with streams of data. Streams are designed to work perfectly with lambda expressions/functional interfaces and method references.
We create a stream by calling java.util.Collection#stream()
or #parallelStream()
, or java.util.stream.Stream.of(...)
(a static method on an interface btw), and use the fluent Stream API to process it in a lazy way.
Chaining processing methods like #filter(...)
and #map(...)
is creating a processing pipeline without actually processing the items while building it, but returning another stream.
To actually process your data you must end the fluent call with a so-called terminal-operation
. The Stream API is huge and can’t be sufficiently explained in a single blog post, but here are some methods that might interest you:
non-terminal-operation:
terminal-operation:
Java Time API
Working with dates and time is always cumbersome… the Joda Time dependency fixed most of the annoyances we usually have while using java.util.Date
etc.
With Java 8, the java.time
-package (JSR-310) was added, which is mostly Joda Time directly in the JDK, so you no longer need an extra dependency for a sensible way to handle date and time.
Instead of representing date and time with java.util.date
we now have a lot of different types in our arsenal to represent the different type of dates and times with or without timezones etc.:
java.time.LocalDate
: a date without time or time-zonejava.time.LocalDateTime
: a date with time but no time-zonejava.time.ZonedDateTime
: a date with time and a time-zonejava.time.Duration
: a time-based amount of timesjava.time.Instant
: a single point on a time-line without a time-zone
You find the whole list in the documentation and you should really check out some other tutorials and guides about the time API, it will make handling dates and times so much easier!
Nashorn JavaScript Engine
A brand-new, implemented from scratch, JavaScript engine called [Nashorn](https://openjdk.java.net/projects/nashorn/)
was introduced, replacing its predecessor Rhino
.
This means better ECMAScript support and better performance.
Don’t celebrate all the JavaScript goodness too early, because Nashorn and its tools are already deprecated with Java 11.
There’s a lot more
As with my previous post about Java 7 I can’t list all the new features of the release, this was just a quick summary of things I find useful. Here’s the overview of all new features.