Java8 знаком с необязательным

Java

1. Использование необязательного введения

1.1, проблемы с кодом ведут

Обычно встречается при написании программNullPointerException, поэтому программа часто считается непустой:

User user = getUserById(id);
if (user != null) {
    String username = user.getUsername();
    System.out.println("Username is: " + username); // 使用 username
}

Чтобы решить эту неловкую ситуацию, JDK, наконец, присоединился к Java8.Optionalкласс, видOptionalJavadoc описывает:

A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value.

Это список, который может содержать или не содержатьnullконтейнер для ценностей. если значение существует, тоisPresent()метод вернетtrue,перечислитьget()Метод возвращает объект.

1.2. Расширенное решение

мы предполагаем, чтоgetUserByIdЭто уже объективно существующий метод, который нельзя изменить, тогда используйтеisPresentиgetДва метода, теперь мы можем написать следующий код:

Optional<User> user = Optional.ofNullable(getUserById(id));
if (user.isPresent()) {
    String username = user.get().getUsername();
    System.out.println("Username is: " + username); // 使用 username
}

Вроде бы код красивый, а по сути это то же самое, что и предыдущее суждениеnullПринципиальной разницы в коде значения нет, но используйтеOptionalинкапсулироватьvalue, увеличивая количество кода. Итак, давайте посмотримOptionalКакие еще методы предусмотрены, чтобы мы могли использовать их лучше (с правильной осанкой)Optional.

Два, опционально три статических метода построения

1 Обзор:

JDK предоставляет три статических метода для созданияOptional:

  1. Optional.of(T value)

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

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

  2. Optional.ofNullable(T value)

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

    этот метод иofОтличие методов в том, что входящие параметры могут бытьnull- Но предыдущий javadoc не говоритOptionalможет содержать только не-nullСтоит ли оно того? мы можем видетьofNullableИсходный код метода.

    Получается, что этот метод будет определять, является ли входящий параметрnull, еслиnull, возвратOptional.empty().

  3. Optional.empty()

        public static<T> Optional<T> empty() {
            @SuppressWarnings("unchecked")
            Optional<T> t = (Optional<T>) EMPTY;
            return t;
        }
    

    Этот метод используется для построения пустогоOptional, этоOptionalне содержит значения - на самом деле базовая реализация по-прежнемуЕсли значение в необязательном параметре равно нулю, то необязательный элемент находится в состоянии, которое не содержит значения., а затем на уровне APIOptionalисполнение не может содержатьnullзначение так, чтобыOptionalсуществует толькосодержит значениеине содержит значениядва состояния.

2) Анализ:

Ранее в javadoc также упоминалось,OptionalизisPresent()Метод используется для определения того, содержит ли он значение,get()получитьOptionalсодержит значения—Стоит отметить, что если значение не существует, то есть при вызове метода get() для Optional.empty будет выброшено исключение NoSuchElementException..

3) Резюме:

1) Необязательный.of(obj): требуется, чтобы входящий объект не мог иметь значение null, иначе перед входом в роль он попадет в NullPointerException. 2) Необязательный.ofNullable(obj): он конструирует необязательный экземпляр интеллектуальным и прощающим способом.Если он не отклонен, передайте null, чтобы получить Optional.empty(), если он не нулевой, вызовите Optional.of(obj) . Означает ли это, что нам нужно использовать Optional.ofNullable(obj) только один раз и навсегда, чтобы сконструировать экземпляр Optional таким образом, который не изменится и должен быть изменен? должны быть выставлены вот так, и это личное.

3. Подробное объяснение общих методов опционального

3.1. Обзор распространенных методов Факультативного

  1. Optional.of(T t)

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

  2. Optional.empty()

    Создает пустой необязательный экземпляр.

  3. Optional.ofNullable(T t)

    Возвращает указанное значение после его инкапсуляции с необязательным.Если значение равно null, возвращается пустой необязательный объект.

  4. isPresent

    Возвращает true, если значение существует, иначе возвращает false

  5. ifPresent

    Если необязательный экземпляр имеет значение, вызовите для него потребителя, в противном случае ничего не делайте. Чтобы понять метод ifPresent, вам сначала нужно понять класс Consumer. Короче говоря, класс Consumer содержит абстрактный метод. Этот абстрактный метод работает с входящим значением, но не возвращает значение. Java8 поддерживает передачу параметров напрямую через лямбда-выражения без использования интерфейсов. Если экземпляр Optional имеет значение, вызов ifPresent() может принять сегмент интерфейса или лямбда-выражение.

  6. Optional.get()

    Если значение существует, верните значение, завернутое в необязательный элемент, в противном случае создайте исключение NoSuchElementException.

  7. orElse(T t)

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

  8. orElseGet(Supplier s)

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

  9. orElseThrow()

    Он выдаст исключение, когда объект пуст.

  10. map(Function f)

    Если значение существует, выполните предоставленный вызов функции сопоставления для этого значения.

  11. flatMap(Function mapper)

    Выполняет предоставленный вызов функции сопоставления для значения, если оно существует, возвращая значение типа Optional , в противном случае возвращает пустой объект Optional.

3.2. Подробное объяснение общих методов опционального

3.2.1, если присутствует
    public void ifPresent(Consumer<? super T> consumer) {
        if (value != null)
            consumer.accept(value);
    }

еслиOptionalЕсли есть значение, вызовите это значениеconsumer.accept, иначе ничего не делать. Итак, для примера во введении мы можем изменить его на:

Optional<User> user = Optional.ofNullable(getUserById(id));
user.ifPresent(u -> System.out.println("Username is: " + u.getUsername()));
3.2.2 илиЕще
    public T orElse(T other) {
        return value != null ? value : other;
    }

еслиOptionalЕсли есть значение, верните его, иначе вернитеorElseПараметры, переданные в метод.

User user = Optional
        .ofNullable(getUserById(id))
        .orElse(new User(0, "Unknown"));
        
System.out.println("Username is: " + user.getUsername());
3.2.3 или ElseGet
    public T orElseGet(Supplier<? extends T> other) {
        return value != null ? value : other.get();
    }

orElseGetиorElseОтличие метода в том, чтоorElseGetВ метод передается параметрSupplierРеализация интерфейса - когдаOptionalКогда есть значение, вернуть значение; когдаOptionalКогда нет никакой ценности вSupplierполученное значение.

User user = Optional
        .ofNullable(getUserById(id))
        .orElseGet(() -> new User(0, "Unknown"));
        
System.out.println("Username is: " + user.getUsername());
3.2.4 или ElseThrow
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
        if (value != null) {
            return value;
        } else {
            throw exceptionSupplier.get();
        }
    }

orElseThrowиorElseОтличие метода в том, чтоorElseThrowметод, когдаOptionalКогда есть значение, возвращается значение; когда нет значения, будет выброшено исключение, и выброшенное исключение будет передано вexceptionSupplierпоставка.

Например:

В контроллере SpringMVC мы можем настроить единую обработку различных исключений. При запросе сущности, если есть соответствующая запись в БД, возвращается запись, иначе может быть выкинутEntityNotFoundException,иметь дело сEntityNotFoundExceptionВ методе мы возвращаем клиенту информацию, соответствующую Http-коду состояния 404 и исключению —orElseThrowИдеально подходит для этого сценария.

@RequestMapping("/{id}")
public User getUser(@PathVariable Integer id) {
    Optional<User> user = userService.getUserById(id);
    return user.orElseThrow(() -> new EntityNotFoundException("id 为 " + id + " 的用户不存在"));
}

@ExceptionHandler(EntityNotFoundException.class)
public ResponseEntity<String> handleException(EntityNotFoundException ex) {
    return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND);
}
3.2.5, карта
    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));
        }
    }

если текущийOptionalзаOptional.empty, все равно возвращаетсяOptional.empty; иначе вернуть новыйOptional,ДолженOptionalСодержит: функцииmapperвvalueВыходное значение при использовании в качестве входного.

String username = Optional.ofNullable(getUserById(id))
                        .map(user -> user.getUsername())
                        .orElse("Unknown")
                        .ifPresent(name -> System.out.println("Username is: " + name));

и мы можем использовать его несколько разmapработать:

Optional<String> username = Optional.ofNullable(getUserById(id))
                                .map(user -> user.getUsername())
                                .map(name -> name.toLowerCase())
                                .map(name -> name.replace('_', ' '))
                                .orElse("Unknown")
                                .ifPresent(name -> System.out.println("Username is: " + name));
3.2.6, плоская карта
    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));
        }
    }

flatMapметод сmapОтличие метода в том, чтоmapфункция в параметре методаmapperРезультатом является значение, затемmapметод будет использоватьOptional.ofNullableоберните это какOptionalflatMapфункция, которая требует аргументовmapperвыходOptional.

Optional<String> username = Optional.ofNullable(getUserById(id))
                                .flatMap(user -> Optional.of(user.getUsername()))
                                .flatMap(name -> Optional.of(name.toLowerCase()))
                                .orElse("Unknown")
                                .ifPresent(name -> System.out.println("Username is: " + name));
3.2.7, фильтр
    public Optional<T> filter(Predicate<? super T> predicate) {
        Objects.requireNonNull(predicate);
        if (!isPresent())
            return this;
        else
            return predicate.test(value) ? this : empty();
    }

filterметод принимаетPredicateиди прямоOptionalЗначение, содержащееся в фильтре, фильтруется, и если содержащееся значение удовлетворяет условию, оно все равно возвращается.Optional; иначе возвратOptional.empty.

Optional<String> username = Optional.ofNullable(getUserById(id))
                                .filter(user -> user.getId() < 10)
                                .map(user -> user.getUsername());
                                .orElse("Unknown")
                                .ifPresent(name -> System.out.println("Username is: " + name));

4. Пример использования Необязательно

4.1. Используйте дисплей 1

Когда user.isPresent() имеет значение true, он получает набор сопоставлений связанных с ним заказов, а если значение false, он возвращает пустой набор. map, мы можем сделать это одной строкой:

return user.map(u -> u.getOrders()).orElse(Collections.emptyList())
 
//上面避免了我们类似 Java 8 之前的做法
if(user.isPresent()) {
  return user.get().getOrders();
} else {
  return Collections.emptyList();
}

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

return user.map(u -> u.getUsername())
           .map(name -> name.toUpperCase())
           .orElse(null);

Предыдущая практика:

User user = .....
if(user != null) {
  String name = user.getUsername();
  if(name != null) {
    return name.toUpperCase();
  } else {
    return null;
  }
} else {
  return null;
}

filter() : если есть значение и условие выполнено, вернуть необязательный элемент, содержащий значение, в противном случае вернуть пустой необязательный элемент.

Optional<String> longName = name.filter((value) -> value.length() > 6);  
System.out.println(longName.orElse("The name is less than 6 characters"));