Необязательный - хорошая вещь, вы действительно его используете?

задняя часть
Необязательный - хорошая вещь, вы действительно его используете?

введение

В начале статьи давайте сначала поговорим о проблеме 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)

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

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

Тогда суть Optional заключается в том, что он хранит внутри реальное значение, а при построении напрямую определяет, пусто ли его значение. Ну, это все еще немного абстрактно. Перейдите непосредственно к исходному коду конструктора Optional(T value), как показано на следующем рисунке.在这里插入图片描述

Тогда исходный код 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 не является пустым.

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

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;
    }
}

Затем роль empty() состоит в том, чтобы вернуть ПУСТОЙ объект.

Что ж, после стольких предзнаменований можно сказать, что роль ofNullable(значение T) в исходном коде

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

Что ж, все должны понимать, что это значит. Разница по сравнению со значением of(T) заключается в том, что когда значение равно null, of(значение T) сообщит об исключении NullPointerException; ofNullable(значение T) не вызовет исключение, а ofNullable(значение T) напрямую вернет ПУСТОЙ объект.

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

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

2. orElse(T другое), orElseGet(Поставщик расширяет T> другое) и orElseThrow(Поставщик расширяет X> исключениеПоставщик)

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

@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;
}

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

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

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

3. map(Function super T, ? extends U> mapper) и flatMap(Function super T, Optional> 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, а тип входного параметра лоскутаMap — Function.

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

Если структура пользователя выглядит следующим образом

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/zjhred/article/details/84976734