Первый: Ты действительно уверен, что эта переменная никогда не будет null
Второй: конечно!
NullPointerException
Ведь так начинается Java код-ревью? NPE всегда является кошмаром для Java разработчиков. Рассмотрим не самый простой пример кода:
public interface Service {
public boolean switchOn(int timmer);
public boolean switchOff(int timmer);
//другие элементы
}
public class RefrigeratorService implements Service {
// ...
}
public class HomeServices {
private static final int NOW = 0;
private static HomeServices service;
public static HomeServices get() {
//проверка на Null #1
if(service == null) {
service = new HomeServices();
}
return service;
}
public Service getRefrigertorControl() {
return new RefrigeratorService();
}
public static void main(String[] args) {
/* получаем Home Services */
HomeServices homeServices = HomeServices.get();
//проверка на Null #2
if(homeServices != null) {
Service refrigertorControl = homeServices.getRefrigertorControl();
//проверка на Null #3
if (refrigertorControl != null) {
refrigertorControl.switchOn(NOW);
}
}
}
}
Как видно вышел, в коде несколько проверок на Null. Конечно все это сделано, чтобы код был более надежным во всех ситуация. Это необходимо, или ...Есть путь лучше?
В общем - да! В Java 8 представили java.util.Optional<T>. Это контейнер, который может содержить или не содержить null значения. Java 8 предоставляет нам более безопасный способ взаимодействовать с объектами, которые в некоторых случаях могут быть null. Данное решение вхоновлено идеями Haskell и Scala.
Если коротко - класс Optional включает методы, для корректной работы в двух случаях, когда значение существует и когда отсутствует. Преимущество, в сравнении с null проверкой, заключается в том, что класс Optional, заставляет обдумывать случаи, когда значение отсутствует. Т.о. получится избежать непредвиденных NPE.
В примере выше у нас есть фабрика HomeService, которая обрабатывает несколько устройств, доступных в доме. Но эти устройства функционально могут быть досутпны или не доступны. Т.е. может случиться NPE. Вместо того, чтобы добавлять проверку на null, обернем объект в Optional.
Мы часто используем тернарный оператор, чтобы проверить на null и значение по умолчанию, если null. Optional предоставляет то же самое без проверок. Optional.orElse(defaultObj) возвращает defaultObj, если в Optional значение null. Используем это в нашем коде:
В итоге вот наш код без NPE и null проверок:
PS: это мой перевод данной статьи
Если коротко - класс Optional включает методы, для корректной работы в двух случаях, когда значение существует и когда отсутствует. Преимущество, в сравнении с null проверкой, заключается в том, что класс Optional, заставляет обдумывать случаи, когда значение отсутствует. Т.о. получится избежать непредвиденных NPE.
В примере выше у нас есть фабрика HomeService, которая обрабатывает несколько устройств, доступных в доме. Но эти устройства функционально могут быть досутпны или не доступны. Т.е. может случиться NPE. Вместо того, чтобы добавлять проверку на null, обернем объект в Optional.
Оборачивание в Optional<T>
Рассмотрим получение объекта из фабрики. Вместо возвращение инстанса элемента, обернем его в Optional. Это позволит пользователю API, понимать, что возвращаемый сервис и может быть функционально доступным или нет. Используем безопасно:
public Optional<Service> getRefrigertorControl() {
Service s = new RefrigeratorService();
//...
return Optional.ofNullable(s);
}
Как вы видите, Optional.ofNullable предоставляет простой путь получить обернутый объект. Есть другие пути, чтобы получить оберный объект в Optional: Optiona.empty() или Optional.of(). Первый возвращает пустой объект, вместо null, а второй - оборачивает не null значения объектов.Как это помогает избежать null проверок?
Обернув объект в Optional единожды, получаем множество полезных методов для вызова функционала обернутого объекта, без NPE.
Optional ref = homeServices.getRefrigertorControl(); ref.ifPresent(HomeServices::switchItOn);Optiona.ifPresent вызывает потребителя (Consumer) по ссылке, если значение не null, иначе ничего не делает. Это очень красиво и легко для понимания. В примере выше, HomeService.switchOn(Service) вызывается, только если Optional содержить не null значение.
Мы часто используем тернарный оператор, чтобы проверить на null и значение по умолчанию, если null. Optional предоставляет то же самое без проверок. Optional.orElse(defaultObj) возвращает defaultObj, если в Optional значение null. Используем это в нашем коде:
public static Optional<HomeServices> get() {
service = Optional.of(service.orElse(new HomeServices()));
return service;
}
Сейчас HomeServices.get() делает то же самое, но лучшим способов. Он проверяет, проинициализирован ли сервис. Optional<T>.orElse(T) помогает вернуть значение по умолчанию.В итоге вот наш код без NPE и null проверок:
import java.util.Optional;
public class HomeServices {
private static final int NOW = 0;
private static Optional<HomeServices> service;
public static Optional<HomeServices> get() {
service = Optional.of(service.orElse(new HomeServices()));
return service;
}
public Optional<Service> getRefrigertorControl() {
if(ServiceDiscovery.isAvaiable("refrigetor")) {
Service s = RefrigeratorService.get();
return Optional.ofNullable(s);
}
return Optional.empty();
}
public static void main(String[] args) {
Optional<HomeServices> homeServices = HomeServices.get();
if(homeServices.isPresent()) {
Optional<Service> refrigertorControl = homeServices.get().getRefrigertorControl();
refrigertorControl.ifPresent(HomeServices::switchItOn);
}
}
public static void switchItOn(Service s){
//...
}
}
PS: это мой перевод данной статьи


