Proč používat Java Optional?

Není příliš velký rozdíl mezi:

Optional<T> op = ...;
op.get().someMethod();

vs

T val = ...;
val.someMethod();

Pokud se chceme vyhnout výjimce:

if (op.isPresent()) {
    T val = op.get();
    val.someMethod();
}

vs

if (val != null) {
    val.someMethod();
}

Pokud programátor Optional nepoužívá, ušetří dokonce pár znaků při psaní (nemusí volat get()). Proč tedy používat Optional?

Předchozí příspěvek na téma Optional se týkal třídy Optional z knihovny Guava. Tento příspěvek se věnuje třídě java.util.Optional, která je dostupná od Javy 8. Důvody pro jejich použití jsou ale obdobné. Guava Optional se používá v případě, že máte starší verzi Javy. V případě, že používáte Javu 8, knihovnu Guava nepotřebujete. 

Důvodem pro používání Optional je to, že null může mít více významů. Null může být prázdná hodnota, může představovat chybu, může to být též neinicializovaná proměnná. Pokud ale máme Optional<T> (Optional vlastně zabaluje hodnotu T), tak buď máme referenci na objekt typu T (Optional.isPresent() == true) a nebo referenci nemáme (Optional.isPresent() == false). V případě, že referenci nemáme, odpovídalo by to případu, kdy null vyjadřuje prázdnou hodnotu.

Další výhodou Optional je to, že bychom si při použití Optional měli uvědomit, že se jedná o hodnotu, která nepovinná (proto název optional) a podle toho se k ní chovat. U běžné proměnné nás nemusí napadnout, že je třeba provést kontrolu na to, zda třeba není null. To je důvod, proč některé metody vrací Optional. Dávají tím najevo, že nemusí vrátit žádnou hodnotu. Je to bezpečnější způsob práce než s null. Optional například vrací některé metody pracující s Stream (java.util.stream.Stream).

Stream<Integer> is1 = Stream.of(5, 7, 1, 8, 2);
Optional<Integer> max = is1.max(Integer::compareTo);

Stream<Integer> is2 = Stream.empty();
Optional<Integer> min = is2.min(Integer::compareTo);

Stream<String> ss1 = Stream.of("lokomotiva", "auto", "letadlo", "raketa", "vzducholoď");
Optional<String> firstWithL = ss1.filter((word) -> word.startsWith("l")).findFirst();

Stream<String> ss2 = Stream.of("lokomotiva", "auto", "letadlo", "raketa", "vzducholoď");
Optional<String> anyWithQ = ss2.filter((word) -> word.startsWith("q")).findAny();

Stream<String> ss3 = Stream.of("lokomotiva", "auto", "letadlo", "raketa", "vzducholoď");
Optional<String> shortest = ss3.min((word1, word2) -> word1.length() - word2.length());

Metody min(), max(), findAny(), findFirst() vrací Optional, protože Stream, který dostanou může být prázdný a tím pádem žádnou hodnotu nemusí najít (viz is2), nebo žádná taková hodnota nevyhovuje podmínkám (viz ss2.filter() na slova začínající na q -> žádné takové tam není).

Napsat komentář