Статьи

Необязательно и объекты: Null Pointer Saviors!

Никто не любит исключения Null Pointer ! Есть ли способ, которым мы можем избавиться от них?
Может быть . , ,

Несколько методов были обсуждены в этом посте:

  • Необязательный тип (новый в Java 8)
  • Класс объектов (старый Java 7!)

Необязательный тип в Java 8

Что это такое?

  • Новый тип (класс), представленный в Java 8
  • Предназначен для использования в качестве « оболочки » для объекта определенного типа или для сценариев, в которых нет объекта (null)

Проще говоря, это лучшая замена для обработки нулей ( предупреждение : на первый взгляд это может быть не очень очевидно!)

Основное использование

Это тип (класс) — так, как мне создать его экземпляр?

Просто используйте три статических метода в классе Optional.

1
2
3
public static Optional<String> stringOptional(String input) {
    return Optional.of(input);
}

Просто и понятно — создайте опциональную оболочку, содержащую значение. Осторожно — бросит NPE, если само значение равно нулю!

1
2
3
4
5
6
7
public static Optional<String> stringNullableOptional(String input) {
    if (!new Random().nextBoolean()) {
        input = null;
    }
         
    return Optional.ofNullable(input);
}

Чуть лучше по моему личному мнению. Здесь нет риска NPE — в случае нулевого ввода будет возвращен пустой Optional.

1
2
3
public static Optional<String> emptyOptional() {
    return Optional.empty();
}

Если вы хотите целенаправленно вернуть «пустое» значение. «пустой» не означает ноль .

Хорошо — как насчет потребления / использования дополнительного?

1
2
3
4
5
6
7
8
9
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) . Не волнуйтесь, я тоже это объясню.

1
2
3
4
5
6
7
8
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 перед извлечением фактического значения.

01
02
03
04
05
06
07
08
09
10
11
12
13
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 — как упоминалось в приведенных выше примерах, использование Optional.ofNullable (во время создания Optional) и orElse и orElseGet (во время использования Optional) полностью защищает нас от NPE.

Еще один спаситель!

(если вы не можете использовать Java 8)

Посмотрите на этот фрагмент кода.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
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, мы никогда не можем быть уверены, что равно нулю ?

Войдите в класс объектов

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
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 . Это, наряду с вашим собственным сообщением об ошибке , поможет вам быстрее обнаруживать ошибки. , .Гораздо быстрее ИМО!

Вы также можете написать свои определенные пользователем проверки, например, реализовать простую проверку, которая обеспечивает не пустоту

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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;
        }
    }
}

Не позволяйте NPE быть болью в неправильном месте. В нашем распоряжении имеется более чем приличный набор инструментов для лучшей работы с NPE или их полного искоренения!

Ура!

Ссылка: Необязательно и объекты: Null Pointer Saviors! от нашего партнера JCG Абхишека Гупты в блоге Object Oriented ..