2017-05-13 62 views
5

Przebudowuję kod do wersji Java 8 i chcę zastąpić sprawdzanie zerowe opcją Opcjonalnie.java 8 opcjonalnie, aby zastąpić return null

public Employee findEmployeeById(String id) { 
    List<Employee> empList = .. //some db query 
    return (empList.isEmpty() ? null : empList.get(0)); 
} 

Optional.ofNullable(empList.get(0)) nie będzie działać jak kiedy będzie rzucać IndexOutofBoundException

Albo mam idealnie zastąpić zerowy z Optional.empty()?

+0

Dlaczego zapytanie nie zwraca tylko jednego wyniku? – Marvin

+0

To jest złożona logika ... lewych złączeń i wszystkich .... Rozumiem, że punkt, ale nie mogę naprawdę zmienić tego – coder25

+6

'return empList.isEmpty()? Opcjonalne.empty(): Opcjonalne.of (empList.get (0)); ' – Jesper

Odpowiedz

9

Jako @Jesper już wspomniano w komentarzach, należy sprawdzić, czy lista jest pusta, a następnie zwrócić pusty Optional.

public Optional<Employee> findEmployeeById(String id) { 
    List<Employee> empList = .. //some db query 
    return empList.isEmpty() ? Optional.empty() : Optional.of(empList.get(0)); 
} 

Optional jest owinięcie wokół potencjalnie null wartości, która pozwala uniknąć jawnie sprawdzanie null kiedy go używać.

Zobacz, jaka funkcjonalność zapewnia.

Na przykład można uzyskać nazwisko pracownika lub „nieznane”, jeśli jest nieobecny, bez sprawdzania null:

Optional<Employee> emp = findEmployeeById(id); 
String name = emp.map(Employee::getName).orElse("unknown"); 

Możesz przeczytać this post about Uses for Optional aby sprawdzić, czy ma to sens, aby korzystać Optional.

3

Dlaczego nie można po prostu zastąpić metodę z:

public Optional<Employee> findEmployeeById(String id) { 
    List<Employee> empList = .. //some db query 
    return (empList.isEmpty() ? Optional.empty() : 
       Optional.ofNullable(empList.get(0))); 
} 

proponuję owinąć empList.get(0) w Optional.ofNullable w przypadku nadal może być null.

Jeśli chodzi o , dlaczego jest lepszy: pomyśl o wywołującej metodę. Ktokolwiek teraz nazywa twoją metodę musi myśleć co właściwie zrobić, gdy wynik jest empty.

Poza tym jesteś teraz przymusowej do pisania kodu, takich jak:

Optional<Employee> emp = findEmployeeById("12"); 

if (emp.isPresent()) { 

} else { 
    .... 
} 

Można również łańcuch to, by stać się bardziej płynnie jak:

emp.orElseThrow(RuntimeException::new) 

lub innymi metodami opcjonalne.

Po prostu nie jest tak po powrocie pracownika. Nawet nie myślisz (zazwyczaj), aby sprawdzić, czy odniesienie jest zerowe.

Dzięki temu Twój kod jest mniej podatny na błędy i łatwiejszy do zrozumienia.

2

Inną możliwością byłoby to zrobić w następujący sposób:

return Optional.of(empList).filter(list -> !list.isEmpty()).map(list -> list.get(0)); 

To automatycznie powróci pusty Optional w przypadku, gdy lista jest pusta lub empList.get(0) powraca null.

Jeśli empList może być null, należy rozważyć użycie Optional.ofNullable(empList) zamiast Optional(empList).

5

Dla mnie naturalnym rozwiązaniem byłoby zachowanie konstrukcji ? :, jak w Floern’s answer. Jeśli jednak chcesz się pozbyć, że istnieje również eleganckie rozwiązanie bez niego:

public Optional<Employee> findEmployeeById(String id) { 
    List<Employee> empList = .. //some db query 
    return empList.stream().findFirst(); 
} 

Daje Ci to, co chcesz, bo findFirst() zwraca Optional. Jeśli nie obchodzi cię, który element otrzymasz - lub wiesz, że nigdy nie ma więcej niż jeden - możesz alternatywnie użyć findAny(), to również zwraca Optional.

+0

Dobrze, nie myślałem o tym – Floern

+2

Nice! Nie potrzebujesz nawet 'empList' local, więc można to zredukować do' return someDbQuery(). Stream(). FindFirst() '. –