Статьи

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

Никто не любит исключения 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);
}
Чуть лучше по моему личному мнению. Здесь нет риска NPE — в случае нулевого ввода 
 будет возвращен пустой
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;
        }
    }
}
Не позволяйте NPE быть болью в неправильном месте. В нашем распоряжении имеется более чем достойный набор инструментов для лучшей обработки NPE или их полного искоренения!

Ура! 🙂