Java 8 – Optional class in detail

In this article, we will discuss Optional class in detail and understand why it is needed/introduced in Java 1.8 version and how to avoid/handle (or to get rid of) the infamous NullPointerException which comes under the umbrella of Runtime Exception

1. Optional class :

  • This is the new class introduced in Java 1.8 version to handle/avoid the infamous NullPointerException swiftly but altogether NullPointerException can’t be avoided
  • So, what is Optional class in Java 1.8 and why it is needed ?
  • It is a wrapper class for the actual object or in other words container for the actual object
  • This way actual object will be wrapped inside Optional class
  • With the help of predefined APIs (or methods) of Optional class, it is possible to get the actual object safely thereby avoiding the NullPointerException but then completely not ignoring any kind of Exception that may be arise/thrown
  • In addition to this, there can be many more operations can be performed on the Optional in case of null like,
    • Returning alternative value
    • Or throwing predefined or custom exception with proper error message
  • Let’s see different ways to create Optional in the following section

2. Different ways to create Optional :

There are 3 different ways (or static methods) available to create Optional as mentioned below –

  1. Optional.of();
  2. Optional.ofNullable();
  3. Optional.empty();

Note: all the above methods are static and can be accessed in a static way like <class-name>.<static-method>();

Let’s us understand each method in the mentioned order to understand their differences and usages in different scenarios

2.1 Optional.of(T) :

  • This static method returns an Optional with the specified present non-null value
    • If the value present is non-null then it returns Optional[non-null-value]
    • If the value present is null then it throws NoSuchElementException with the error message stating “No value present

OptionalDemo1.java

package in.bench.resources.optional.demo;

import java.util.Optional;

public class OptionalDemo1 {

	public static void main(String[] args) {

		// Optional of
		Optional<String> optionalOf = Optional.of("BenchResources");
		System.out.println("Optional.of() :- " + optionalOf);


		// try to get the value from Optional of
		String str = optionalOf.get();
		System.out.print("\nString value from Optional.of() using get() method :- " + str);
	}
}

Output :

Optional.of() :- Optional[BenchResources]

String value from Optional.of() using get() method :- BenchResources

OptionalDemo2.java

package in.bench.resources.optional.demo;

import java.util.Optional;

public class OptionalDemo2 {

	public static void main(String[] args) {

		// Optional of
		Optional<String> optionalOf = Optional.of(null);
		System.out.println("Optional.of() :- " + optionalOf);
	}
}

Output :

Exception in thread "main" java.lang.NullPointerException
	at java.util.Objects.requireNonNull(Objects.java:203)
	at java.util.Optional.<init>(Optional.java:96)
	at java.util.Optional.of(Optional.java:108)
	at in.bench.resources.optional.demo.OptionalDemo.main(OptionalDemo.java:10)

2.2 Optional.ofNullable(T) :

  • This static method returns an Optional describing the specified value, if non-null, otherwise returns an empty Optional
    • If the value present is non-null then it returns Optional[non-null-value]
    • If the value present is null then it returns Optional.empty without throwing any Exception like in the case of Optional.of(T)
    • But when Optional.get() method is invoked to retrieve the value from the empty Optional then it throws NoSuchElementException with the error message stating “No value present

OptionalDemo3.java

package in.bench.resources.optional.demo;

import java.util.Optional;

public class OptionalDemo3 {

	public static void main(String[] args) {

		// Optional ofNullable
		Optional<String> optionalOfNullable = Optional.ofNullable("BenchResources");
		System.out.println("Optional.ofNullable() :- " + optionalOfNullable);


		// try to get the value from Optional ofNullable
		String str = optionalOfNullable.get();
		System.out.print("\nString value from Optional.ofNullable() "
				+ "using get() method :- " + str);
	}
}

Output :

Optional.ofNullable() :- Optional[BenchResources]

String value from Optional.ofNullable() using get() method :- BenchResources

OptionalDemo4.java

package in.bench.resources.optional.demo;

import java.util.Optional;

public class OptionalDemo4 {

	public static void main(String[] args) {

		// Optional ofNullable
		Optional<String> optionalOfNullable = Optional.ofNullable(null);
		System.out.println("Optional.ofNullable() :- " + optionalOfNullable);


		// try to get the value from Optional ofNullable
		String str = optionalOfNullable.get();
		System.out.print("\nString value from Optional.ofNullable() "
				+ "using get() method :- " + str);
	}
}

Output :

Optional.ofNullable() :- Optional.empty

Exception in thread "main" java.util.NoSuchElementException: No value present
	at java.util.Optional.get(Optional.java:135)
	at in.bench.resources.optional.demo.OptionalDemo.main(OptionalDemo.java:15)

2.3 Optional.empty() :

  • This static method returns an empty Optional instance
  • No value is present for this Optional
  • It is just an empty container to represent Optional with no value
  • If we try to get the value from the empty Optional (or Optional.empty) then it throws NoSuchElementException with the error message stating “No value present

OptionalDemo5.java

package in.bench.resources.optional.demo;

import java.util.Optional;

public class OptionalDemo5 {

	public static void main(String[] args) {

		// empty Optional
		Optional<String> emptyOptional = Optional.empty();
		System.out.println("Optional.empty() :- " + emptyOptional);
	}
}

Output :

Optional.empty() :- Optional.empty

OptionalDemo6.java

package in.bench.resources.optional.demo;

import java.util.Optional;

public class OptionalDemo6 {

	public static void main(String[] args) {

		// empty Optional
		Optional<String> emptyOptional = Optional.empty();
		System.out.println("Optional.empty() :- " + emptyOptional);


		// try to get the value from empty Optional
		String str = emptyOptional.get();
		System.out.print("\nString value from Optional.empty() "
				+ "using get() method :- " + str);
	}
}

Output :

Optional.empty() :- Optional.empty

Exception in thread "main" java.util.NoSuchElementException: No value present
	at java.util.Optional.get(Optional.java:135)
	at in.bench.resources.optional.demo.OptionalDemo.main(OptionalDemo.java:15)

3. Getting value from Optional :

  • To get the value from the Optional, instance method get() can be used which returns
    • value if present inside the Optional
    • otherwise throws NoSuchElementExcption for null or Optional.empty

OptionalDemo7.java

package in.bench.resources.optional.demo;

import java.util.Optional;

public class OptionalDemo7 {

	public static void main(String[] args) {

		// empty Optional
		Optional<String> optional = Optional.of("Java");
		System.out.println("Optional.of(\"Java\") :- " + optional);


		// try to get the value from Optional
		String str = optional.get();
		System.out.print("\nString value from Optional.of(\"Java\") "
				+ "using get() method :- " + str);
	}
}

Output :

Optional.of("Java") :- Optional[Java]

String value from Optional.of("Java") using get() method :- Java

OptionalDemo8.java

package in.bench.resources.optional.demo;

import java.util.Optional;

public class OptionalDemo8 {

	public static void main(String[] args) {

		// empty Optional
		Optional<String> optional = Optional.ofNullable(null);
		System.out.println("Optional.ofNullable(null) :- " + optional);


		// try to get the value from Optional
		String str = optional.get();
		System.out.print("\nString value from Optional.ofNullable(null) "
				+ "using get() method :- " + str);
	}
}

Output :

Optional.ofNullable(null) :- Optional.empty

Exception in thread "main" java.util.NoSuchElementException: No value present
	at java.util.Optional.get(Optional.java:135)
	at in.bench.resources.optional.demo.OptionalDemo.main(OptionalDemo.java:15)

4. isPresent() & ifPresent() methods :

There are 2 instance methods available in Optional which helps to check if there exists any value in the Optional, those are,

  • isPresent()
    • This method returns true if there is a value present, otherwise false
  • ifPresent()
    • If a value is present, invoke the specified consumer with the value, otherwise do nothing

OptionalIsPresentDemo.java

package in.bench.resources.optional.demo;

import java.util.Optional;

public class OptionalIsPresentDemo {

	public static void main(String[] args) {

		// Optional 1
		Optional<String> optional1 = Optional.of("BenchResources");
		checkForValue(optional1);


		// Optional 2
		Optional<String> optional2 = Optional.ofNullable(null);
		checkForValue(optional2);


		// Optional 3
		Optional<String> optional3 = Optional.empty();
		checkForValue(optional3);
	}


	/**
	 * This method tests whether there exists any value in Optional or not
	 * 
	 * @param optional
	 */
	private static void checkForValue(Optional<String> optional) {

		if(optional.isPresent()) {
			System.out.println("Value is present");
		}
		else {
			System.out.println("Either empty or null");
		}
	}
}

Output :

Value is present
Either empty or null
Either empty or null

OptionalIfPresentDemo.java

package in.bench.resources.optional.demo;

import java.util.Optional;

public class OptionalIfPresentDemo {

	public static void main(String[] args) {

		// Optional 1
		Optional<String> optional1 = Optional.of("BenchResources");
		optional1.ifPresent(opt -> System.out.println("Value is present for the " + opt));


		// Optional 2
		Optional<String> optional2 = Optional.ofNullable(null);
		optional2.ifPresent(opt -> System.out.println("Value is present for the " + opt));


		// Optional 3
		Optional<String> optional3 = Optional.empty();
		optional3.ifPresent(opt -> System.out.println("Value is present for the " + opt));
	}
}

Output :

Value is present for the BenchResources

5. Alternate way – return value or throw Exception :

There are 3 instance methods available in Optional which helps to return alternate value or throw custom exception in case value is not present in the Optional

  • orElse()
    • This method returns the value if present, otherwise return value provided in the orElse
  • orElseGet()
    • This method returns the value if present, otherwise invoke provided supplier and return the result of that invocation
  • orThrow()
    • This method returns the contained value, if present, otherwise throw an exception to be created by the provided supplier

OptionalOrElseDemo.java

package in.bench.resources.optional.demo;

import java.util.Optional;

public class OptionalOrElseDemo {

	public static void main(String[] args) {

		// test string 1
		String str = "BenchResources";

		// Optional 1
		String optional1 = Optional.of(str).orElse(dummy());
		System.out.println("When Optional is not null :- " + optional1 + "\n");


		// test string 12
		str = null;

		// Optional 2
		String optional2 = Optional.ofNullable(str).orElse(dummy());
		System.out.print("When Optional is null :- " + optional2);
	}


	/**
	 * dummy method to return value for orElse
	 * @return
	 */
	private static String dummy(){
		System.out.println("dummy method is called");
		return "dummy value";
	}
}

Output :

dummy method is called
When Optional is not null :- BenchResources

dummy method is called
When Optional is null :- dummy value

OptionalOrElseGetDemo.java

package in.bench.resources.optional.demo;

import java.util.Optional;

public class OptionalOrElseGetDemo {

	public static void main(String[] args) {

		// test string 1
		String str = "BenchResources";

		// Optional 1
		String optional1 = Optional.of(str).orElseGet(() -> dummy());
		System.out.println("When Optional is not null :- " + optional1 + "\n");


		// test string 12
		str = null;

		// Optional 2
		String optional2 = Optional.ofNullable(str).orElseGet(() -> dummy());
		System.out.print("When Optional is null :- " + optional2);
	}


	/**
	 * dummy method to return value for orElse
	 * @return
	 */
	private static String dummy(){
		System.out.println("dummy method is called");
		return "dummy value";
	}
}

Output :

When Optional is not null :- BenchResources

dummy method is called
When Optional is null :- dummy value

OptionalOrThrowDemo.java

package in.bench.resources.optional.demo;

import java.util.Optional;

public class OptionalOrThrowDemo {

	public static void main(String[] args) throws Exception {

		// test string 1
		String str = "BenchResources";

		// Optional 1
		String optional1 = Optional.of(str).orElseThrow(Exception::new);
		System.out.println("When Optional is not null :- " + optional1 + "\n");


		// test string 2
		str = null;

		// Optional 2
		String optional2 = Optional.ofNullable(str).orElseThrow(Exception::new);
		System.out.print("When Optional is null :- " + optional2);
	}
}

Output :

When Optional is not null :- BenchResources

Exception in thread "main" java.lang.Exception
	at java.util.Optional.orElseThrow(Optional.java:290)
	at in.bench.resources.optional.demo.OptionalOrThrowDemo.main(OptionalOrThrowDemo.java:21)

6. Difference between orElse() & orElseGet() :

  • The main difference between these 2 instance methods is how they deal with the invocation of the alternate method when the actual object wrapped around Optional is found to be null
  • In case of orElse() method, the supplied method is invoked even when the value of actual object is not null although it isn’t required; whereas for orElseGet() method, supplied method won’t get invoked if there is a value present
  • So, performance-wise orElseGet() method does a better job when comparing with orElse() method
  • Method-signature of both methods slightly differs
    • orElseGet() method accepts Supplier Functional interface
    • orElse() method accepts value/object of same-type of Optional
public T orElseGet(Supplier<? extends T> other);

public T orElse(T other);
  • Usage of both methods also differs like
    • orElseGet() can only be used when there is Supplier function available
    • whereas orElse() can be supplied with alternate value/object of same type of Optional

7. Mapping & Filtering Optional :

There are 2 instance methods available namely map() and filter() which helps to convert/transform and filter values from Optional

  • map() – If a value is present, apply the provided mapping function to it, and if the result is non-null, return an Optional describing the result. Otherwise return an empty Optional
public <U> Optional<U> map(Function<? super T,? extends U> mapper);
  • filter() – If a value is present, and the value matches the given predicate, return an Optional describing the value, otherwise return an empty Optional
public Optional<T> filter(Predicate<? super T> predicate);

OptionalMappingDemo.java

package in.bench.resources.optional.demo;

import java.util.Optional;

public class OptionalMappingDemo {

	public static void main(String[] args) {

		// Optional 1
		Optional<String> optional1 = Optional.of("BenchResources.Net");


		// map to upper case
		String url = optional1.map(String::toUpperCase).orElse("default url");
		System.out.println("Tranformed URL :- " + url);



		// Optional 2
		Optional<String> optional2 = Optional.ofNullable(null);


		// map to upper case
		url = optional2.map(String::toUpperCase).orElse("default url");
		System.out.print("\nTranformed URL :- " + url);
	}
}

Output :

Tranformed URL :- BENCHRESOURCES.NET

Tranformed URL :- default url

OptionalFilteringDemo.java

package in.bench.resources.optional.demo;

import java.util.Optional;

public class OptionalFilteringDemo {

	public static void main(String[] args) {

		// Optional 1
		Optional<String> optional1 = Optional.of("BenchResources.Net");


		// map to upper case
		String url = optional1.filter(str -> str.startsWith("Bench")).orElse("default url");
		System.out.println("URL :- " + url);



		// Optional 2
		Optional<String> optional2 = Optional.ofNullable(null);


		// map to upper case
		url = optional2.filter(str -> str.startsWith("Bench")).orElse("default url");
		System.out.print("\nURL :- " + url);
	}
}

Output :

URL :- BenchResources.Net

URL :- default url

Related Articles :

References:

Happy Coding !!
Happy Learning !!

Java 8 - How to Reverse a String in place ?