Никто не любит исключения Null Pointer ! Есть ли способ, которым мы можем избавиться от них? Может быть . , ,
Несколько методов были обсуждены в этом посте
- Необязательный тип (новый в Java 8)
- Класс объектов (старый Java 7 материал ;-))
Необязательный тип в Java 8
Что это?
- Новый тип (класс), представленный в Java 8
- Предназначен для использования в качестве « оболочки » для объекта определенного типа или для сценариев, в которых нет объекта (null)
Проще говоря, это лучшая замена для обработки нулей ( предупреждение : на первый взгляд это может быть не очень очевидно!)
Основное использование
Это тип (класс) — так, как мне создать его экземпляр?
Просто используйте три статических метода в классе Optional
public static Optional<String> stringOptional(String input) { return Optional.of(input); }
Просто и понятно — создайте опциональную оболочку, содержащую значение. Осторожно — бросит NPE, если само значение равно нулю!
public static Optional<String> stringNullableOptional(String input) { if (!new Random().nextBoolean()) { input = null; } return Optional.ofNullable(input); }
будет возвращен пустой
Optional
public static Optional<String> emptyOptional() { return Optional.empty(); }
«пустой» не означает ноль
Хорошо — как насчет потребления / использования дополнительного?
public static void consumingOptional() { Optional<String> wrapped = Optional.of("aString"); if (wrapped.isPresent()) { System.out.println("Got string - " + wrapped.get()); } else { System.out.println("Gotcha !"); } }
метод isPresent
) — это заставит вас задуматься, а не лучше
ли
использовать if (myObj! = Null) ? Не волнуйтесь, я объясню как хорошо
public static void consumingNullableOptional() { String input = null; if (new Random().nextBoolean()) { input = "iCanBeNull"; } Optional<String> wrapped = Optional.ofNullable(input); System.out.println(wrapped.orElse("default")); }
orElse,
который можно использовать для возврата
значения по умолчанию
в случае, если обернутое значение равно нулю — преимущество очевидно. Мы
избегаем
очевидного многословия вызова
ifPresent
перед извлечением фактического значения
public static void consumingEmptyOptional() { String input = null; if (new Random().nextBoolean()) { input = "iCanBeNull"; } Optional<String> wrapped = Optional.ofNullable(input); System.out.println(wrapped.orElseGet( () -> { return "defaultBySupplier"; } )); }
orElse
и
orElseGet
вполне могли быть
перегружены
(то же имя, другой параметр)
В любом случае, единственным очевидным отличием здесь является сам параметр — у вас есть возможность предоставить лямбда-выражение, представляющее экземпляр поставщика <T> (функциональный интерфейс)
Как использование Optional лучше, чем обычные проверки нуля ????
- В общем и целом, главное преимущество использования Optional заключается в том, чтобы иметь возможность четко выразить свое намерение — простой возврат нулевого значения из метода оставляет потребителя в море сомнений (когда происходит фактический NPE) относительно того, было ли оно преднамеренным или нет. и требует дальнейшего самоанализа в Javadocs (если таковые имеются). С Факультативным, его кристально чистый !
- Есть способы , в которых вы можете полностью избежать NPE с Опционно — как указаны в приведенном выше примерах, использование Optional.ofNullable (при Факультативным создании) и OrElse и orElseGet (при Факультативным потреблении) оградить нас от неработающих вообще
Еще один спаситель! ( если вы не можете использовать Java 8 )
Посмотрите на этот фрагмент кода
package com.abhirockzz.wordpress.npesaviors; import java.util.Map; import java.util.Objects; public class UsingObjects { String getVal(Map<String, String> aMap, String key) { return aMap.containsKey(key) ? aMap.get(key) : null; } public static void main(String[] args) { UsingObjects obj = new UsingObjects(); obj.getVal(null, "dummy"); } }
- Объект карты
- Ключ, по которому выполняется поиск
- Экземпляр, в котором вызывается метод
Когда в этом случае выбрасывается NPE, мы никогда не можем быть уверены, что равно нулю ?
Войдите в класс объектов
package com.abhirockzz.wordpress.npesaviors; import java.util.Map; import java.util.Objects; public class UsingObjects { String getValSafe(Map<String, String> aMap, String key) { Map<String, String> safeMap = Objects.requireNonNull(aMap, "Map is null"); String safeKey = Objects.requireNonNull(key, "Key is null"); return safeMap.containsKey(safeKey) ? safeMap.get(safeKey) : null; } public static void main(String[] args) { UsingObjects obj = new UsingObjects(); obj.getValSafe(null, "dummy"); } }
RequireNonNull
метод
- Просто возвращает значение в случае, если оно не равно нулю
- Бросает NPE будет указанное сообщение в случае, если значение в ноль
Почему это лучше, чем если (myObj! = Null)
Трассировки стека , который вы увидите , будет ясно иметь Objects.requireNonNull вызов метода. Это, наряду с вашим собственным сообщением об ошибке , поможет вам быстрее обнаруживать ошибки. , намного быстрее ИМО!
Вы также можете написать свои определенные пользователем проверки, например, реализовать простую проверку, которая обеспечивает не пустоту
import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.function.Predicate; public class RandomGist { public static <T> T requireNonEmpty(T object, Predicate<T> predicate, String msgToCaller){ Objects.requireNonNull(object); Objects.requireNonNull(predicate); if (predicate.test(object)){ throw new IllegalArgumentException(msgToCaller); } return object; } public static void main(String[] args) { //Usage 1: an empty string (intentional) String s = ""; System.out.println(requireNonEmpty(Objects.requireNonNull(s), (s1) -> s1.isEmpty() , "My String is Empty!")); //Usage 2: an empty List (intentional) List list = Collections.emptyList(); System.out.println(requireNonEmpty(Objects.requireNonNull(list), (l) -> l.isEmpty(), "List is Empty!").size()); //Usage 3: an empty User (intentional) User user = new User(""); System.out.println(requireNonEmpty(Objects.requireNonNull(user), (u) -> u.getName().isEmpty(), "User is Empty!")); } private static class User { private String name; public User(String name){ this.name = name; } public String getName(){ return name; } } }
Ура! ?