java.util.Optional – What it is and how to use it – What is java.util.Optional?



java.util.Optional – What it is and how to use it – What is java.util.Optional?

0 0


java-optional

What it is and how to use it

On Github tginsberg / java-optional

java.util.Optional

What it is and how to use it

Created by Todd Ginsberg for CJUG 2016-06-02

What is java.util.Optional?

  • Introduced in Java 8
  • Intended to reduce NullPointerExceptions
  • A signal to other developers that a value may not be present
  • Container with zero or one elements

What isn't java.util.Optional?

  • Not capable of storing null
  • Not serializable!
  • Not widely used in the JDK
"Our intention was to provide a limited mechanism for library method return types where there needed to be a clear way to represent "no result", and using null for such was overwhelmingly likely to cause errors." -- Brian Goetz

How did it get here?

Optional is mainly here to make stream terminal operations possible for empty streams.
new ArrayList<String>().stream().findFirst();
						

Why not also add it to Map?

public interface Map<K,V> {

    // ...

    default Optional<V> getOptionally(K k) {
        // ...
    }
}
						
Maps can contain null values!
Map<String, String> map = new HashMap<>();
map.put("A",null);

// Both look the same - no difference between not present and null.
map.getOptionally("A");
map.getOptionally("B");
						

States

value isEmpty() isPresent() .get() not null false true value null true false NoSuchElementException

Creation

Use one of the two built-in Factory methods
Optional<String> text = Optional.ofNullable("Hello, world!");
					

Or...

Optional<String> text = Optional.of(somethingThatIsntNull);
						
Optional<String> text = Optional.of(null);
// -> NullPointerException
						

When to use it

If you use it at all, only use it for return types where there is no natural way to represent "no result"
// Yes
public Optional<Customer> getCustomerById(long id);
					
// No
public Optional<List<Customer>> getCustomersForMonth(final YearMonth when);
						
// Prefer:
public List<Customer> getCustomersForMonth(final YearMonth when);
// -> Collections.emptyList();
						

Don't call .get()!

Optional<String> text = service.getText();
if(text.isPresent()) {
    System.out.println(text.get());
} else {
    System.out.println("Hello, world!");
}
						
Looks just like...
String text = service.getText();
if(text != null) {
    System.out.println(text);
} else {
    System.out.println("Hello, world!");
}
							
"In retrospect, we should have called get something like getOrElseThrowNoSuchElementException or something that made it far clearer that this was a highly dangerous method that undermined the whole purpose of Optional in the first place. Lesson learned." -- Brian Goetz

Use one of the safe methods instead!

Optional<String> text = service.getText();
System.out.println(text.orElse("Hello, world!"));
						
Optional<String> text = service.getText();
text.ifPresent(this::doSomethingWithText);
							
Optional<String> text = service.getText();
System.out.println(text.orElseThrow(NoSuchElementException::new));
							

When not to use it

  • Method parameters
  • Fields
  • In any DTO or Entity, because it is not serializable
  • If your customers are not using Java 8
  • Possibly, don't use it at all!

Rules to remember

  • When returning them, make absolutely sure they aren't null
  • Don't call .get()

Thanks!

 @ToddGinsberg

bit.ly/FeedbackOptional