Introduction

An Optional in Java is a container object which may or may not contain a non-null value. Java also has separate Optional classes for primitive values - int, long and double. In this post, we will learn about the classes OptionalInt, OptionalLong, and OptionalDouble in Java.

OptionalInt, OptionalLong and OptionalDouble in Java

  • OptionalInt is a container object which may or may not contain a int value.
  • OptionalLong is a container object which may or may not contain a long value.
  • OptionalDouble is a container object which may or may not contain a double value.

We can use these classes in place of Optional<Integer>, Optional<Long> and Optional<Double> respectively.

In this post, I will explain in detail the OptionalInt class. The methods (and their behaviour) on OptionalDouble and OptionalLong classes are very similar and hence I will not explain them in detail. The explanation provided for OptionalInt applies to them as well (except that OptionalLong and OptionalDouble wrap a long and a double respectively).

OptionalInt in Java

Creating an OptionalInt

The empty method (static method) creates an empty OptionalInt instance i.e., a container object which has no int value.

OptionalInt optionalInt = OptionalInt.empty();

The static of method takes a primitive int value and returns an OptionalInt instance.

OptionalInt optionalInt = OptionalInt.of(5);
System.out.println(optionalInt); //OptionalInt[5]

Checking if an OptionalInt is empty

The method isPresent returns true if the OptionalInt is not empty. The method isEmpty (added in Java 11) checks if the OptionalInt is empty (i.e., not present).

OptionalInt optionalInt = OptionalInt.of(5);
System.out.println(optionalInt.isEmpty()); //false
System.out.println(optionalInt.isPresent()); //true

Getting the primitive int from the OptionalInt

To get the underlying primitive integer value from the OptionalInt, we can use the getAsInt method. If the OptionalInt is empty, then it throws a NoSuchElementException.

OptionalInt optionalInt = OptionalInt.of(5);  
System.out.println(optionalInt.getAsInt()); //5

OptionalInt - ifPresent actions

We can pass an IntConsumer (A Consumer that accepts a single int-valued argument) to the ifPresent method. If the OptionalInt is not empty, then it will call the passed consumer function.

Example: Let us print the int value of an OptionalInt using ifPresent as,

OptionalInt optionalInt = OptionalInt.of(5);  
optionalInt.ifPresent(i -> System.out.println(i)); //5

//Using method reference
optionalInt.ifPresent(System.out::println); //5

The last line replaced the lambda expression with its method reference equivalent.

ifPresentOrElse

Java 9 added the ifPresentOrElse method. It takes a IntConsumer as before, but also takes in a Runnable. It will call the IntConsumer if the OptionalInt is not empty. If it is empty, it will invoke the Runnable.

OptionalInt optionalInt = OptionalInt.of(5);    
optionalInt.ifPresentOrElse(System.out::println,
        () -> System.out.println("The OptionalInt is empty"));

The above code prints 5 since the OptionalInt is not empty. If the OptionalInt is empty, it will call the Runnable as shown below:

OptionalInt optionalInt = OptionalInt.empty();
optionalInt.ifPresentOrElse(System.out::println,
        () -> System.out.println("The OptionalInt is empty"));

Prints,

The OptionalInt is empty

OptionalInt - orElse actions

The orElse method takes an alternate int value and returns it if the OptionalInt is empty. If the OptionalInt is not empty, then it returns the int value of the OptionalInt itself.

OptionalInt optionalInt = OptionalInt.of(5);
System.out.println(optionalInt.orElse(10)); //5

OptionalInt optionalInt = OptionalInt.empty();
System.out.println(optionalInt.orElse(10)); //10

In the above example, since the second OptionalInt is empty, it returns the argument passed to the orElse method.

orElseGet

If the other value to be returned (if the OptionalInt is empty) is difficult to compute or if not available as a constant, we can pass a IntSupplier which will return the alternate value. Thus, calling orElseGet

  • Returns the value if the OptionalInt is not empty.
  • Else, invokes the passed IntSupplier and returns the value produced by it.
OptionalInt optionalInt = OptionalInt.of(5);
int value = optionalInt.orElseGet(() -> {
    System.out.println("Returning value since OptionalInt is empty");
    return 10;
});
System.out.println(value); //5

In the above code, since the OptionalInt is not empty, calling orElseGet returns the value wrapped by the OptionalInt instance. It does not invoke the supplier function at all.

On the other hand, the below code invokes orElseGet on an empty OptionalInt and hence it calls the IntSupplier we passed to get the value.

OptionalInt optionalInt = OptionalInt.empty();
int value = optionalInt.orElseGet(() -> {
    System.out.println("Returning value since OptionalInt is empty");
    return 10;
});
System.out.println(value);

Prints,

Returning value since OptionalInt is empty
10

orElseThrow

We used the orElse (and orElseGet) method to return an alternate value if the OptionalInt is empty. We use orElseThrow to throw an exception instead.

There are two overloaded orElseThrow methods. One takes a supplier that produces an exception. Its signature is:

public<X extends Throwable> int orElseThrow(Supplier<? extends X> exceptionSupplier) throws X 

If the value is present, then it is returned. Otherwise, it throws an exception that is returned by the supplying function.

OptionalInt optionalInt = OptionalInt.of(5);
int value = optionalInt.orElseThrow(() -> new RuntimeException("The OptionalInt is empty!!"));
System.out.println(value); //5

The above code prints 5 because the OptionalInt is not empty.

OptionalInt optionalInt = OptionalInt.empty();
optionalInt.orElseThrow(() -> new RuntimeException("The OptionalInt is empty!!"));

This would throw a RuntimeException with the passed message.

There is an overloaded orElseThrow method (added in Java 10) - this doesn’t take any arguments. If the value is present, it will return it. Otherwise, it throws a NoSuchElementException.

Note: This method is equivalent to calling getAsInt().

OptionalInt optionalInt = OptionalInt.of(5);
int value = optionalInt.orElseThrow();
System.out.println(value); //5

OptionalInt optionalInt = OptionalInt.empty();
//Throws java.util.NoSuchElementException: No value present
optionalInt.orElseThrow();

Creating a single element stream from an OptionalInt

Java 9 added a new method called stream(). If the OptionalInt is not empty, it returns a sequential IntStream that has only that value, otherwise returns an empty IntStream.

OptionalInt optionalInt = OptionalInt.of(5);
optionalInt.stream()
        .map(i -> i * 3)
        .forEach(System.out::println); //15

OptionalInt optionalInt = OptionalInt.empty();
optionalInt.stream() //returns empty IntStream
        .map(i -> i * 3)
        .forEach(System.out::println);

In the first code snippet, calling the stream() method returned an IntStream with value 5. Then we can use any method available on an IntStream. Here, we multiplied the value with 3 and printed it. The second code would return an empty IntStream since the OptionalInt is empty and hence nothing was printed.

OptionalLong in Java

The methods supported by OptionalLong are very similar to that of supported on an OptionalInt. One difference is that to get the underlying long value, use the getAsLong() .

OptionalLong - Creation

We use the of method to create an OptionalLong. The empty method returns an empty OptionalLong. We use the isEmpty() and isPresent() methods to check if the OptionalLong is empty or not. Finally, the getAsLong() method returns the long value (if present) and throws NoSuchElementException if no value is present.

OptionalLong optionalLong = OptionalLong.empty();

optionalLong = optionalLong.of(100L); 
System.out.println(optionalLong); //OptionalLong[100]

System.out.println(optionalLong.isEmpty()); //false
System.out.println(optionalLong.isPresent()); //true

System.out.println(optionalLong.getAsLong()); //100

IfPresent and IfPresentOrElse

The ifPresent takes a LongConsumer and calls it if the OptionalLong is not empty.

The ifPresentOrElse a LongConsumer and a Runnable. It calls the consumer if the OptionalLong is not empty, otherwise it calls the passed Runnable.

OptionalLong optionLong = OptionalLong.of(100L);
optionalLong.ifPresent(System.out::println); //100

System.out.println();
//100
optionalLong.ifPresentOrElse(System.out::println,
        () -> System.out.println("The OptionalLong is empty"));

optionalLong = OptionalLong.empty();
//The OptionalLong is empty
optionalLong.ifPresentOrElse(System.out::println,
        () -> System.out.println("The OptionalLong is empty"));

orElse and orElseGet

The orElseGet method takes a long value and returns it if the OptionalLong is empty (else returns the value the OptionalLong has).

OptionalLong optionalLong = OptionalLong.of(100L);
System.out.println(optionalLong.orElse(200L)); //100

optionalLong = OptionalLong.empty();
System.out.println(optionalLong.orElse(200L)); //200

The orElseGet takes a LongSupplier and it invokes it if the OptionalLong is empty.

OptionalLong optionalLong = OptionalLong.of(100L);
long value = optionalLong.orElseGet(() -> {
    System.out.println("Returning value since OptionalLong is empty");
    return 200L;
});
System.out.println(value); //100

optionalLong = OptionalLong.empty();
value = optionalLong.orElseGet(() -> {
    System.out.println("Returning value since OptionalLong is empty");
    return 200L;
});
/*
Returning value since OptionalLong is empty
200
*/
System.out.println(value);

orElseThrow

The two overloaded orElseThrow methods are shown below.

OptionalLong optionalLong = OptionalLong.of(100L);
value = optionalLong.orElseThrow(() -> new RuntimeException("The OptionalLong is empty!!"));
System.out.println(value); //100

optionalLong = OptionalLong.empty();
//Throws java.lang.RuntimeException: The OptionalLong is empty!!
optionalLong.orElseThrow(() -> new RuntimeException("The OptionalInt is empty!!"));

optionalLong = OptionalLong.of(100L);
value = optionalLong.orElseThrow();
System.out.println(value); //100

optionalLong = OptionalLong.empty();
//Throws java.util.NoSuchElementException: No value present
optionalLong.orElseThrow();
System.out.println();

Creating a stream from OptionalLong

Calling the stream() method on an OptionalLong returns a sequential LongStream with that only value from the OptionalLong (if not empty). If the OptionalLong is empty, it returns an empty LongStream.

OptionalLong optionalLong = OptionalLong.of(100L);
optionalLong.stream()
        .map(i -> i * 3)
        .forEach(System.out::println); //300

optionalLong = OptionalLong.empty();
//Prints nothing
optionalLong.stream()
        .map(i -> i * 3)
        .forEach(System.out::println);

OptionalDouble in Java

To get the underlying double value call, getAsDouble(). Calling the stream() returns a DoubleStream. The functionalities of the other methods are similar to what we have already seen and will avoid repeating them.

If you have any questions, I would be happy to hear them.

Conclusion

In this post, we learnt about the OptionalInt, OptionalLong and OptionalDouble classes in Java. To learn more about the latest method additions to the Optional class in Java, refer to the Optional new methods post.