Все еще используете != null для определения нуля? Научу вас новым позам

# Введение

В начале статьи давайте поговорим о проблеме NPE. Проблема NPE — это исключение NullPointerException, с которым мы часто сталкиваемся при разработке. Предположим, что у нас есть два класса, и их диаграммы классов UML показаны ниже.

В этом случае есть следующий код

user.getAddress().getProvince();

Этот способ записи может вызвать исключение NullPointerException, когда значение пользователя равно нулю. Для решения этой проблемы принят следующий метод записи.

if(user!=null){
   
       Address address = user.getAddress();    if(address!=null){
   
           String province = address.getProvince();    }}

Этот вид письма относительно некрасив. Чтобы избежать вышеупомянутого некрасивого письма, сделайте некрасивый дизайн элегантным. JAVA8 предоставляет дополнительный класс для оптимизации этого метода записи, который будет подробно описан в следующем тексте.

# Введение в API

Давайте сначала представим API. В отличие от других статей, эта статья использует аналогию и объединяет ее с исходным кодом. В отличие от других статей, API перечислены один за другим, поэтому люди не могут найти ключевые моменты.

1、Необязательно(значение T),empty(),of(значение T),ofNullable(значение T)

Между этими четырьмя функциями существует корреляция, поэтому для запоминания они объединены.

Прежде всего позвольте мне объяснить, что параметр «Optional(T value»), то есть конструктор, имеет частные разрешения и не может быть вызван извне. Оставшиеся три функции являются общедоступными и позволяют нам вызывать их. Тогда суть необязательного заключается в том, что он хранит внутри себя реальное значение и при его создании напрямую определяет, является ли его значение пустым. Ладно, это немного абстрактно. Перейдите непосредственно к исходному коду конструктораOptional(Tvalue), как показано на рисунке ниже.

Тогда исходный код of(T value) выглядит следующим образом:

public static <T> Optional<T> of(T value) {
   
       return new Optional<>(value);}

Другими словами, функция of(T value) вызывает конструктор внутри себя. На основании исходного кода конструктора можно сделать два вывода:

  • Необязательный объект, созданный с помощью функции of(T value), по-прежнему будет сообщать об исключении NullPointerException, если значение Value пусто.

  • Необязательный объект, созданный с помощью функции of(T value), может обычно создавать дополнительный объект, если значение Value не пустое.

Кроме того, класс Необязательный также поддерживает объект со значением null, который, вероятно, выглядит следующим образом.

​​​​​​

public final class Optional<T> {
    //省略....
    private static final Optional<?> EMPTY = new Optional<>();
    private Optional() {
        this.value = null;
    }
    //省略...
    public static<T> Optional<T> empty() {
        @SuppressWarnings("unchecked")
        Optional<T> t = (Optional<T>) EMPTY;
        return t;
    }
}

Затем роль пустой() — вернуть ПУСТОЙ объект.

Хорошо, теперь, когда мы заложили основу, мы можем поговорить о роли ofNullable(значение T). Давайте перейдем к исходному коду​​​​​​​

 public static <T> Optional<T> ofNullable(T value) {
    return value == null ? empty() : of(value);
}

Хорошо, каждый должен понимать, что это значит. Разница по сравнению с of(T value) заключается в том, что, когда значение равно null, of(T value) сообщит об исключении NullPointerException; ofNullable(T value) не выдаст исключение, а ofNullable(T value) напрямую возвращает пустой объект.

Означает ли это, что в проекте мы используем только функцию ofNullable вместо функции?

Нет, пока что-то существует, оно, естественно, имеет ценность. Когда мы работаем, мы не хотим скрывать исключение NullPointerException. Вместо этого об этом необходимо сообщить немедленно, и в этом случае используется функция Of. Но надо признать, что такие сцены действительно редки. Блогер использовал эту функцию только при написании тестов junit.

2、orElse(Tother),orElseGet(Supplier<? расширяет T>other)和orElseThrow(Supplier<? расширяет X>ExceptionSupplier)

Эти три функции объединены для памяти и все вызываются, когда значение, переданное в конструктор, равно нулю. Использование orElse и orElseGet происходит следующим образом, что эквивалентно заданию значения по умолчанию, когда значение равно нулю:​​​​​​​

@Test
public void test() {
    User user = null;
    user = Optional.ofNullable(user).orElse(createUser());
    user = Optional.ofNullable(user).orElseGet(() -> createUser());
}
public User createUser(){
    User user = new User();
    user.setName("zhangsan");
    return user;
}

Разница между этими двумя функциями: если значение пользователя не равно нулю, функция orElse все равно выполнит метод createUser(), но функция orElseGet не выполнит метод createUser(). Вы можете проверить это самостоятельно.

Что касается orElseThrow, когда значение равно нулю, исключение генерируется напрямую.

User user = null;
Optional.ofNullable(user).orElseThrow(()->new Exception("用户不存在"));


3、map(Function<? super T, ? extends U> mapper)和flatMap(Function<? super T, Optional<U>> mapper)

Эти две функции помещаются в набор ячеек памяти и преобразуют значения.

Непосредственно загрузите исходный код​​​​​​​

 public final class Optional<T> {
    //省略....
     public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
        Objects.requireNonNull(mapper);
        if (!isPresent())
            return empty();
        else {
            return Optional.ofNullable(mapper.apply(value));
        }
    }
    //省略...
     public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
        Objects.requireNonNull(mapper);
        if (!isPresent())
            return empty();
        else {
            return Objects.requireNonNull(mapper.apply(value));
        }
    }
}

В теле функции нет разницы между этими двумя функциями. Единственная разница заключается во входных параметрах.Типы входных параметров, принимаемые функцией карты, — это Function<? super T, ?extensions U>, а типы входных параметров, принимаемыеflapMap, — это Function<?super T,Optional<U>>.

С точки зрения конкретного использования, для карты:

Если структура пользователя следующая​​​​​​​

public class User {
    private String name;
    public String getName() {
        return name;
    }
}

В настоящее время способ написания имени следующий:

String city = Optional.ofNullable(user).map(u-> u.getName()).get();

Для плоской карты:

Если структура пользователя следующая​​​​​​​

public class User {
    private String name;
    public Optional<String> getName() {
        return Optional.ofNullable(name);
    }
}

В настоящее время способ написания имени следующий:

String city = Optional.ofNullable(user).flatMap(u-> u.getName()).get();

4、isPresent() и ifPresent(Consumer<? super T> потребитель)

Эти две функции запоминаются вместе: isPresent определяет, является ли значение пустым, а ifPresent выполняет некоторые операции, когда значение не пустое. Исходный код этих двух функций выглядит следующим образом:

public final class Optional<T> {
    //省略....
    public boolean isPresent() {
        return value != null;
    }
    //省略...
    public void ifPresent(Consumer<? super T> consumer) {
        if (value != null)
            consumer.accept(value);
    }
}

Что требует дополнительного объяснения, так это то, что каждый не должен ставить

if (user != null){
   // TODO: do something
}

написано как

User user = Optional.ofNullable(user);
if (Optional.isPresent()){
   // TODO: do something
}

Поскольку написано таким образом, структура кода по-прежнему уродлива. Блогер подскажет вам, как правильно написать это позже.

Что касается ifPresent(Consumer<? super T> Consumer), то его использование также очень просто, как показано ниже​​​​​​​

Optional.ofNullable(user).ifPresent(u->{
    // TODO: do something
});

5、фильтр(предикат Predicate<? super T>)

Говорить особо нечего, просто зайдите в исходный код​​​​​​​

public final class Optional<T> {
    //省略....
   Objects.requireNonNull(predicate);
        if (!isPresent())
            return this;
        else
            return predicate.test(value) ? this : empty();
}

Метод фильтра принимает Предикат для фильтрации значений, содержащихся в Необязательном. Если содержащиеся значения соответствуют условиям, то Необязательный все равно возвращается; в противном случае возвращается Необязательный.пустой.

Использование следующее

Optional<User> user1 = Optional.ofNullable(user).filter(u -> u.getName().length()<6);

Как показано выше, если длина имени пользователя меньше 6, оно возвращается. Если оно больше 6, возвращается ПУСТОЙ объект.

# Практическое использование

Пример 1

в функциональном методе

Предыдущий метод письма​​​​​​​

public String getCity(User user)  throws Exception{
        if(user!=null){
            if(user.getAddress()!=null){
                Address address = user.getAddress();
                if(address.getCity()!=null){
                    return address.getCity();
                }
            }
        }
        throw new Excpetion("取值错误"); 
    }

Метод написания JAVA8​​​​​​

public String getCity(User user) throws Exception{
    return Optional.ofNullable(user)
                   .map(u-> u.getAddress())
                   .map(a->a.getCity())
                   .orElseThrow(()->new Exception("取指错误"));
}

Пример 2

Например, в основной программе

Предыдущий метод письма​​​​​​​

if(user!=null){
    dosomething(user);
}

Метод написания JAVA8​​​​​​

 Optional.ofNullable(user)
    .ifPresent(u->{
        dosomething(u);
});

Пример 3

Предыдущий метод письма​​​​​​​

public User getUser(User user) throws Exception{
    if(user!=null){
        String name = user.getName();
        if("zhangsan".equals(name)){
            return user;
        }
    }else{
        user = new User();
        user.setName("zhangsan");
        return user;
    }
}

метод записи java8​​​​​​​

public User getUser(User user) {
    return Optional.ofNullable(user)
                   .filter(u->"zhangsan".equals(u.getName()))
                   .orElseGet(()-> {
                        User user1 = new User();
                        user1.setName("zhangsan");
                        return user1;
                   });
}

Другие примеры не перечислены один за другим. Тем не менее, используя эту цепочку программирования, код становится более элегантным. Однако логика не столь очевидна и читабельность снижается, вы можете использовать ее в своем проекте по ситуации.

рекомендация

отblog.csdn.net/yzs2022/article/details/130045282