Null může znamenat mnoho věcí. Aby bylo jasnější, co vlastně má null představovat, a také proto, aby uživatel ošetřil stavy, kdy může dojít k NullPointerException je tady třída Optional z knihovny Guava. Tato třída je vhodná právě pro případy, kdy null má představovat prázdnou hodnotu.
Pokud proměnná obsahuje prázdnou hodnotu (například záznam nenalezen) použije se Optional.absent(). Pokud neprázdnou hodnotu pak je to Optional, který obsahuje referenci na danou hodnotu. Pokud by v tomto případě proměnná obsahovala null, znamenalo by to, že proměnná nebyla inicializována a byla by to chyba.
Tímto způsobem je přesně řečeno, kdy proměnná něco obsahuje a kdy ne. Dalším důvodem pro tuto třídu je přimět uživatele ke kontrole, a předejít případné NullPointerException.
Hodnotu (referenci na objekt) získlám z Optional voláním metody get(). Když už voláme get(), mělo by nás trknout, že hodnota může být absent a proto bychom měli nejdříve zavolat isPresent(). Pokud tato metoda vrátí true můžeme zavolat get() a s objektem dále pracovat. Určitou nevýhodou je neustálé volání get() metody.
Třída Person.
import com.google.common.base.Optional; public class Person { private long id; private String name; private String surname; private Optional<String> nickname; public Person(long id, String name, String surname) { this.id = id; this.name = name; this.surname = surname; this.nickname = Optional.absent(); } public Person(long id, String name, String surname, String nickname) { this.id = id; this.name = name; this.surname = surname; this.nickname = Optional.of(nickname); } public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSurname() { return surname; } public void setSurname(String surname) { this.surname = surname; } public Optional<String> getNickname() { return nickname; } public void setNickname(Optional<String> nickname) { this.nickname = nickname; } }
Třída Service s metodou, která vrací Optional.absent v případě, že daný objekt Person není v seznamu nalezen. V případě, že nalezen je, vrací Optional s referencí na nalezený objekt.
import java.util.List; import com.google.common.base.Optional; public class Service { public Optional<Person> findLongInList(List<Person> list, Long id) { for (Person person : list) { if (person.getId() == id) { return Optional.of(person); } } return Optional.absent(); } }
Třída App, ve které je ukázána práce s Optional.
import java.util.Arrays; import java.util.List; import com.google.common.base.Optional; public class App { private static List<Person> persons = Arrays.asList( new Person(1L, "František", "Koudelka"), new Person(2L, "John", "Smith", "johny"), new Person(3L, "James", "Bond")); public static void main(String[] args) { Service service = new Service(); Optional<Person> personId2 = service.findLongInList(persons, 2L); Optional<Person> personId3 = service.findLongInList(persons, 3L); Optional<Person> personId4 = service.findLongInList(persons, 4L); // Pravujeme s objektem personId2 // Zde většinu programátorů napadně kontrola na null. if (personId2.isPresent()) { System.out.println("Jméno člověka s id 2: " + personId2.get().getName()); // Je ale jednoduché zapomenout na to, že getNickname může vrátit null. S Optional je to zřejmější. if (personId2.get().getNickname().isPresent()) { System.out.println("Jeho přezdívka je: " + personId2.get().getNickname().get()); } } // Pravujeme s objektem personId3 if (personId3.isPresent()) { System.out.println("Jméno člověka s id 3: " + personId3.get().getName()); if (personId3.get().getNickname().isPresent()) { System.out.println("Jeho přezdívka je: " + personId3.get().getNickname().get()); } } // Pravujeme s objektem personId4 if (personId4.isPresent()) { System.out.println("Jméno člověka s id 4: " + personId4.get().getName()); if (personId4.get().getNickname().isPresent()) { System.out.println("Jeho přezdívka je: " + personId4.get().getNickname().get()); } } } }
Po spuštění dostaneme následující výsledek:
Jméno člověka s id 2: John Jeho přezdívka je: johny Jméno člověka s id 3: James
Zdroje: