Почему Optional не предоставляет метод просмотра? - PullRequest
0 голосов
/ 02 декабря 2018

Мне любопытно узнать, почему Java Необязательно не предоставляет peek метод, аналогичный Stream s .

peek method javadoc состояний интерфейса Stream:

  • @ apiNote Этот метод существует главным образом для поддержки отладки, когда вы хотите видеть элементы по мере их прохожденияопределенная точка в конвейере

Это почти точно описывает мой случай использования:

@Override
@Transactional
public User getUserById(long id) {
    return repository.findById(id)
        .peek(u -> logger.debug("Found user = {} by id = {}", u, id))
        .orElseThrow(() -> new UserNotFoundException("id = " + id));
}

(repository.findById возвращает Optional<User> (см. CrudRepository #findById ))

Но он не скомпилируется, поскольку для Optional нет метода peek. Поэтому без метода peek все вышеперечисленное преобразуется в:

@Override
@Transactional
public User getUserById(long id) {
  Optional<User> userOptional = repository.findById(id);
  if (userOptional.isPresent()) {
    logger.debug("Found user = {} with id = {}", userOptional.get(), id);
  }
  return userOptional.orElseThrow(() -> new UserNotFoundException("id = " + id));
}

Также возможно сделать что-то подобное (см. Этот ответ ):

@NoArgsConstructor(access = PRIVATE)
public abstract class OptionalUtils {
    public static <T> UnaryOperator<T> peek(Consumer<T> consumer) {
        return t -> {
            consumer.accept(t);
            return t;
        };
    }
}

И использовать его с методом map:

return repository.findById(id)
    .map(OptionalUtils.peek(u -> logger.debug("Found user = {} with id = {}", u, id)))
    .orElseThrow(() -> new UserNotFoundException("id = " + id));

Но я думаю, что это взлом, а не чистое использование Optional.

Начиная с Java 9 можно преобразовать Optional в Stream, но поток делаетне имеет метода orElseThrow (и, очевидно, не должно).

Также можно сделать то же самое, используя ifPresent, но он возвращает void.(И мне кажется, что ifPresent не должен возвращать ничего, кроме void)

Я неправильно использую Optional?

Является ли отсутствие метода peek преднамеренным?(Но в то же время Option Вавра обеспечивает метод peek.)

Или это только считалось не стоящим?

Ответы [ 3 ]

0 голосов
/ 02 декабря 2018

Уже существует метод Optional::ifPresent, который принимает Consumer.

В Java 8 единственным способом является использование Optional::map, чтобы отобразить сущность на себя и использовать ее как peek метод:

return repository.findById(id)
                 .map(u -> {
                     logger.debug("Found user = {} with id = {}", u, id)
                     return u;
                 })
                 .orElseThrow(() -> new UserNotFoundException("id = " + id));

... который должен быть упрощен при реализации собственного метода peek:

<T> UnaryOperator<T> peek(Consumer<T> consumer) {
    return t -> {
        consumer.accept(t);
        return t;
    };
}

... и удобно использовать с Optional:

return repository.findById(id)
                 .map(this.peek(logger.debug("Found user = {} with id = {}", u, id)))
                 .orElseThrow(() -> new UserNotFoundException("id = " + id));
0 голосов
/ 04 декабря 2018

Уже есть Optional::ifPresent и Optional::isPresent метод для регистрации результата.Но вы, вероятно, хотите что-то в очереди.Ответ на это, вероятно, недосмотр.

0 голосов
/ 02 декабря 2018

Что ж, только дизайнеры могли ответить вам на «точные» подробности о том, почему не было метода просмотра для Optionals.

Итак, на данный момент вы застряли с использованием isPresent(), что, на мой взгляд, на самом деле выглядит просто отлично:

if (userOptional.isPresent()) 
    logger.debug("Found user = {} with id = {}", userOptional.get(), id);

или вы можете рассмотреть предлагаемые ответы на связанной странице, есливы хотите, чтобы это было частью конвейера.

btw, учитывая новый метод stream, начиная с JDK9, вы можете сделать:

return repository.findById(id) // Optional<User>
                 .stream()  // Stream<User>
                 .peek(u -> logger.debug("Found user = {} by id = {}", u, id)) // Stream<User>
                 .findFirst() // Optional<User>
                 .orElseThrow(() -> new UserNotFoundException("id = " + id))

см. этот ответ для аналогичного примера.

...