For me Java 8 wasn’t a big deal … until I had to go back to Java 7. Suddenly I started missing things I started using without even realizing it. Here comes Optional<T>:
Assume we have some sort of class (Provider
) which does something and has a “getName” method. Now we also have a method in a class managing providers which returns the provider by id
, so we pass in a string ID and get back a provider:
static class Provider {
String getName () {
return "bar";
}
}
static Provider getProvider (final String id) {
if ("foo".equals ( id )) {
return new Provider ();
}
return null;
}
In this simple example the manager only knows the provider “foo”, which will return “bar” as its name. All requests for other providers will return null
. A real life scenario might have a Map
, which also returns null
in case of a missing element.
Now a pretty common code snippet before Java 8 would look like this:
final Provider provider = getProvider ( “bar” );
final String value;
if ( provider != null ) {
value = provider.getName ();
} else {
value = null;
}
System.out.println ( “Bar (pre8): “ + value );
Pretty noisy. So the first step is to use the “Optional” type, and to guarantee that the getProvider
method never returns null
. So we don’t have to check for it:
static Optional<Provider> getOptionalProvider ( final String id ) {
return Optional.ofNullable ( getProvider ( id ) );
}
In this case a new method was added, which simply calls the old one. The next thing is to use Optional.map(…) and Optional.orElse(…) to transform the value and return a default if we don’t have a value.
String value1 = getOptionalProvider ( "foo" )
.map ( Provider::getName )
.orElse ( null );
System.out.println ( "Foo: " + value1 );
Pretty simple actually. But still readable and understandable (although some people might disagree on that one ;-) ).
So what does happen? First the call to getOptionalProvider
will now never return null
. If the value itself would be null
, it would return an empty Optional
but still a class instance. Actually always the same, since there is only one instance of an empty Optional
. Next the map
method will call the provided expression (longer version would be: value -> value.getName()
), but the method will only do this if the Optional is not empty. Otherwise it will return an empty Optional again. So after calling map
we either have an Optional<String> with the value of getName()
, or again an empty Optional. Calling orElse
on this new Optional
will either return the value of the Optional
or the default value provided, null
in this case.
Of course one could argue that internally the same logic happens as with Java 7 and before. But I think that this way, you actually can do a one-liner
which is understandable but still does not obstruct the your actual class with to many lines of code just or checking about null
.
Full sample:
import java.util.Optional;
public class Manager {
static class Provider {
String getName () {
return "bar";
}
}
static Provider getProvider ( final String id ) {
if ( "foo".equals ( id ) ) {
return new Provider ();
}
return null;
}
static Optional<Provider> getOptionalProvider ( final String id ) {
return Optional.ofNullable ( getProvider ( id ) );
}
public static void main ( final String[] args ) {
final String value1 = getOptionalProvider ( “foo” ).map ( Provider::getName ).orElse ( null );
System.out.println ( “Foo: “ + value1 );
final String value2 = getOptionalProvider ( “bar” ).map ( Provider::getName ).orElse ( null );
System.out.println ( “Bar: “ + value2 );
// before Java 8
final Provider provider = getProvider ( “bar” );
final String value3;
if ( provider != null ) {
value3 = provider.getName ();
} else {
value3 = null;
}
System.out.println ( “Bar (pre8): “ + value3 );
}
}