Java 8 Optional In Depth Example
1. Introduction
This is an in-depth article about Java 8 Optional. A new class Optional was introduced in Java 8. The optional class is part of java.util package. Optional is used to represent a value. It can be present or absent. No more null checks and NullPointerException are needed. Optional helps in avoiding any runtime NullPointerExceptions. It helps in developing clean and neat Java APIs. Optional Object is also a Container which holds at most one value. The Advantages of Optional are Null checks, NullPointerException at run-time not required and no more boiler plate code.
2. Optional In Depth
The Optional class is used to make a field optional. The field may or may not have values.
2.1 Creation of Optionals
Optional objects can be created using empty, of and ofNullable methods.
2.1.1 Empty method
The following code snippet shows how to create an Optional object using empty method:
Creating Optional Empty
import java.util.Optional; public class OptionalCreator { public Optional getEmptyOptional() { Optional empty = Optional.empty(); return empty; } public static void main(String[] args) { OptionalCreator creator = new OptionalCreator(); Optional empty = creator.getEmptyOptional(); System.out.println(empty.isPresent()); } }
The command below executes the above code snippet:
Run command
javac OptionalCreator.java java OptionalCreator
The output of the executed command is shown below.
2.1.2 of Method
An Optional object can be created using Of method. The code snippet below shows the implementation :
OptionalOfCreator
import java.util.Optional; public class OptionalOfCreator { public Optional GetOptionalOf() { String name = "optioncheck"; Optional opt = Optional.of(name); return opt; } public static void main(String[] args) { OptionalOfCreator creator = new OptionalOfCreator(); Optional opt = creator.GetOptionalOf(); System.out.println(opt.toString()); } }
The command below executes the above code snippet:
Run command
javac OptionalOfCreator.java java OptionalOfCreator
The output of the executed command is shown below.
2.1.3 ofNullable
An Optional object can be created using ofNullable method. The code snippet below shows the implementation :
OptionalOfNullableCreator
import java.util.Optional; public class OptionalOfNullableCreator { public Optional getNullable() { String name = "optioncheck"; Optional opt = Optional.ofNullable(name); return opt; } public static void main(String[] args) { OptionalOfNullableCreator creator = new OptionalOfNullableCreator(); Optional opt = creator.getNullable(); System.out.println(opt.toString()); } }
The command below executes the above code snippet:
Run command
javac OptionalOfNullableCreator.java java OptionalOfNullableCreator
The output of the executed command is shown below.
2.2 Checking Value
An Optional object’s value can be checked using isPresent method. IsEmpty can be used if you want to check if object is empty. The sections below show the isPresent implementation.
2.2.1 Optional created using of method
The code snippet below shows the implementation for checking value for optional created using of method:
OptionalEmptyChecker
import java.util.Optional; public class OptionalEmptyChecker { public Optional getOptionalOf() { Optional opt = Optional.of("Option Empty"); return opt; } public static void main(String[] args) { OptionalEmptyChecker creator = new OptionalEmptyChecker(); Optional opt = creator.getOptionalOf(); System.out.println(opt.isPresent()); } }
The command below executes the above code snippet:
Run command
javac OptionalEmptyChecker.java java OptionalEmptyChecker
The output of the executed command is shown below.
2.2.2 Optional created using ofNullable method
The code snippet below shows the implementation for checking value for optional created using of method:
OptionalNullableEmptyChecker
import java.util.Optional; public class OptionalNullableEmptyChecker { public Optional getNullable() { Optional opt = Optional.ofNullable(null); return opt; } public static void main(String[] args) { OptionalNullableEmptyChecker creator = new OptionalNullableEmptyChecker(); Optional opt = creator.getNullable(); System.out.println(opt.isPresent()); } }
The command below executes the above code snippet:
Run command
javac OptionalNullableEmptyChecker.java java OptionalNullableEmptyChecker
The output of the executed command is shown below.
2.3 Defaults
The orElseGet method is used to get the default value which is the Optional The code snippet below shows the implementation of using orElseGet method:
OptionalOfNullOrElseGetChecker
public class OptionalOfNullOrElseGetChecker { public String getNullable() { String name = null; String opt = Optional.ofNullable(name).orElseGet(() ->"value"); return opt; } public static void main(String[] args) { OptionalOfNullOrElseGetChecker creator = new OptionalOfNullOrElseGetChecker(); String opt = creator.getNullable(); System.out.println(opt); } }
The command below executes the above code snippet:
Run command
javac OptionalOfNullOrElseGetChecker.java java OptionalOfNullOrElseGetChecker
The output of the executed command is shown below.
2.4 Exception Handling
The orElseThrow method handles an absent value by throwing exception. The code snippet below shows the implementation of using orElseThrow method:
OptionalOfNullOrElseThrowChecker
import java.util.Optional; public class OptionalOfNullOrElseThrowChecker { public void throwElseException() throws Exception { String nullName = null; String name = Optional.ofNullable(nullName).orElseThrow( IllegalArgumentException::new); } public static void main(String[] args) throws Exception { OptionalOfNullOrElseThrowChecker creator = new OptionalOfNullOrElseThrowChecker(); creator.throwElseException(); } }
The command below executes the above code snippet:
Run command
javac OptionalOfNullOrElseThrowChecker.java java OptionalOfNullOrElseThrowChecker
The output of the executed command is shown below.
2.5 Value Return
Get method is used to return the optional value. The code snippet below shows the implementation of using get method:
OptionalOfGetChecker
import java.util.Optional; public class OptionalOfGetChecker { public Optional getOptional() { String name = "optioncheck"; Optional opt = Optional.of(name); return opt; } public static void main(String[] args) { OptionalOfGetChecker creator = new OptionalOfGetChecker(); Optional opt = creator.getOptional(); System.out.println(opt.get()); } }
The command below executes the above code snippet:
Run command
javac OptionalOfGetChecker.java java OptionalOfGetChecker
The output of the executed command is shown below.
2.6 Filtering
The filter method is used to filter the optionals based on the predicate. The code snippet below shows the implementation of using filter method:
OptionalFilter
import java.util.Optional; public class OptionalFilter { public Optional getOptional() { String name = "optioncheck"; Optional opt = Optional.of(name); return opt; } public static void main(String[] args) { OptionalFilter optional = new OptionalFilter(); Optional opt = optional.getOptional(); System.out.println(opt.filter(name -> name.equals("optioncheck"))); } }
The command below executes the above code snippet:
Run command
javac OptionalFilter.java java OptionalFilter
The output of the executed command is shown below.
2.8 Map Optional for transforming
The map method is used for transforming the Optional value. The code snippet below shows the implementation of using the map method:
OptionalMap
import java.util.Optional; import java.util.List; import java.util.Arrays; public class OptionalMap { public Optional<List> getOptional() { List companies = Arrays.asList( "ibm", "oracle", "Qubit", "microsoft", "", "google"); Optional<List> opt = Optional.of(companies); return opt; } public static void main(String[] args) { OptionalMap optional = new OptionalMap(); Optional<List> opt = optional.getOptional(); int size = opt.map(List::size).orElse(0); System.out.println(size); } }
The command below executes the above code snippet:
Run command
javac OptionalMap.java java OptionalMap
The output of the executed command is shown below.
2.9 Optional Chains
Stream class is used to chain Optional objects. The code snippet below shows the implementation of using the Stream class:
OptionChain
import java.util.Optional; import java.util.stream.*; public class OptionChain { private Optional getEmpty() { return Optional.empty(); } public Optional getCheck() { return Optional.of("check"); } private Optional getExit() { return Optional.of("exit"); } private Optional createOptional(String value) { if (value == null || value == "" || value == "empty") { return Optional.empty(); } return Optional.of(value); } public void getChain() { Optional found = Stream.of(getEmpty(), getCheck(), getExit()) .filter(Optional::isPresent) .map(Optional::get) .findFirst(); } public static void main(String[] args) { OptionChain chain = new OptionChain(); chain.getChain(); Optional opt = chain.getCheck(); System.out.println(opt.toString()); } }
The command below executes the above code snippet:
Run command
javac OptionChain.java java OptionChain
The output of the executed command is shown below.
2.10 Java Standalone Application
A java standalone application is presented to show the implementation of Optional in the application features. Without using optional, the application is presented first.
2.10.1 No Optional
ImageSize, ImageFeatures, Photo, PhotoService and PhotoTesterNoOption classes are part of the photo management application.
The code snippet below shows the ImageFeatures class.
Image Features
public class ImageFeatures { private String fileSize; private ImageSize imageSize; public ImageFeatures(String size, ImageSize imageSize){ this.fileSize = size; this.imageSize = imageSize; } public String getFileSize() { return fileSize; } public ImageSize getImageSize() { return imageSize; } }
The code snippet below shows the ImageSize class.
ImageSize
public class ImageSize { private int width; private int height; public ImageSize(int width, int height){ this.width = width; this.height = height; } public int getWidth() { return width; } public int getHeight() { return height; } }
The code snippet below shows the Photo class.
Photo
public class Photo { private long id; private String company; private String name; private ImageFeatures features; public Photo(long id, String company, String name, ImageFeatures features){ this.id = id; this.company = company; this.name = name; this.features = features; } public long getId() { return id; } public String getCompany() { return company; } public String getName() { return name; } public ImageFeatures getFeatures() { return features; } }
The code snippet below shows the PhotoService class.
PhotoService
public class PhotoService { public int getPhotoScreenWidth(Photo photo){ if(photo != null){ ImageFeatures features = photo.getFeatures(); if(features != null){ ImageSize size = features.getImageSize(); if(size != null){ return size.getWidth(); } } } return 0; } }
The code snippet below shows the PhotoTesterNoOption class.
PhotoTesterNoOption
public class PhotoTesterNoOption { public static void main(String[] args) { ImageSize size = new ImageSize(750,1334); ImageFeatures features = new ImageFeatures("8.7", size); Photo photo = new Photo(31591, "Google", "pixel", features); PhotoService photoService = new PhotoService(); int width = photoService.getPhotoScreenWidth(photo); System.out.println(" Width = " + width); } }
The command below executes the above code snippet:
Run command
javac PhotoTesterNoOption.java java PhotoTesterNoOption
The output of the executed command is shown below.
2.10.2 With Optional
ImageSize, ImageFeatures, Photo, PhotoService and PhotoTesterOption classes are part of the photo management application in which Optionals are used.
The code snippet below shows the ImageFeatures class.
ImageFeatures
import java.util.Optional; public class ImageFeatures { private String fileSize; private Optional imageSize; public ImageFeatures(String size, Optional imageSize){ this.fileSize = size; this.imageSize = imageSize; } public String getFileSize() { return fileSize; } public Optional getImageSize() { return imageSize; } }
The code snippet below shows the ImageSize class.
Image Size
public class ImageSize { private int width; private int height; public ImageSize(int width, int height){ this.width = width; this.height = height; } public int getWidth() { return width; } public int getHeight() { return height; } }
The code snippet below shows the Photo class.
Photo
import java.util.Optional; public class Photo { private long id; private String company; private String name; private Optional features; public Photo(long id, String company, String name, Optional features){ this.id = id; this.company = company; this.name = name; this.features = features; } public long getId() { return id; } public String getCompany() { return company; } public String getName() { return name; } public Optional getFeatures() { return features; } }
The code snippet below shows the PhotoService class.
PhotoService
import java.util.Optional; public class PhotoService { public int getPhotoScreenWidth(Optional photo){ return photo.flatMap(Photo::getFeatures) .flatMap(ImageFeatures::getImageSize) .map(ImageSize::getWidth) .orElse(0); } }
The code snippet below shows the PhotoTesterOption class.
PhotoTesterOption
import java.util.Optional; public class PhotoTesterOption { public static void main(String[] args) { ImageSize size = new ImageSize(750,1334); ImageFeatures features = new ImageFeatures("8.7", Optional.of(size)); Photo photo = new Photo(31591, "Google", "pixel", Optional.of(features)); PhotoService photoService = new PhotoService(); int width = photoService.getPhotoScreenWidth(Optional.of(photo)); System.out.println(" Width = " + width); } }
The command below executes the above code snippet:
Run command
javac PhotoTesterOption.java java PhotoTesterOption
The output of the executed command is shown below.
2.11 Best Practices
You should not assign null to an Optional object. Developer should assign a value to Optional Object before invoking get(). Use orElse method when optional default object has no value. You can use orElseGet to return a non existent optional object. ElseThrow method can be used when there is no value assigned to Optional Object. You can use orElse method when an Optional has a Null Reference.
You can consume an Optional if the value is not empty. Developer need not do anything if the value is empty. Chaining can be avoided if the goal is to get a value. You should avoid declaring a field of type Optional. Avoid using optional in arguments of the constructors and methods. You should not implement optional in collections. Values need to be transformed using map and flatmap methods. Filter method is used to reject the values based on a rule.
Developer should not use optionals in the operations which are sensitive on identity. For asserting equality, you need not unwrap optionals. You should not use Optional<T>. Developer can use OptionalInt, OptionalLong, or OptionalDouble classes which are not generic.
3. Download the Source Code
You can download the full source code of this example here: Java 8 Optional In Depth Example