Optional.stream()

от автора

На этой неделе я узнал об одной интересной «новой» возможности Optional, о которой хочу рассказать в этом посте. Она доступна с Java 9, так что новизна ее относительна.

Давайте начнем со следующей последовательности для вычисления общей цены заказа:

public BigDecimal getOrderPrice(Long orderId) {     List<OrderLine> lines = orderRepository.findByOrderId(orderId);     BigDecimal price = BigDecimal.ZERO;            for (OrderLine line : lines) {         price = price.add(line.getPrice());        }     return price; }
  • Предоставьте переменную-аккумулятор для цены

  • Добавьте цену каждой строки к общей цене

В настоящее время, вероятно, более целесообразно использовать стримы вместо итераций. Следующий фрагмент эквивалентен предыдущему:

public BigDecimal getOrderPrice(Long orderId) {     List<OrderLine> lines = orderRepository.findByOrderId(orderId);     return lines.stream()                 .map(OrderLine::getPrice)                 .reduce(BigDecimal.ZERO, BigDecimal::add); }

Давайте сосредоточимся на переменной orderId : она может содержать null.

Императивный способ обработки null заключается в том, чтобы проверить его в начале метода — и в конечном итоге сбросить:

public BigDecimal getOrderPrice(Long orderId) {     if (orderId == null) {         throw new IllegalArgumentException("Order ID cannot be null");     }     List<OrderLine> lines = orderRepository.findByOrderId(orderId);     return lines.stream()                 .map(OrderLine::getPrice)                 .reduce(BigDecimal.ZERO, BigDecimal::add); }

Функциональный способ заключается в том, чтобы обернуть orderId в Optional. Вот как выглядит код с использованием Optional:

public BigDecimal getOrderPrice(Long orderId) {     return Optional.ofNullable(orderId)                                         .map(orderRepository::findByOrderId)                                .flatMap(lines -> {                                                     BigDecimal sum = lines.stream()                         .map(OrderLine::getPrice)                         .reduce(BigDecimal.ZERO, BigDecimal::add);                 return Optional.of(sum);                                        }).orElse(BigDecimal.ZERO);                             }
  1. Оберните orderId в Optional

  2. Найдите соответствующие строки заказа

  3. Используйте flatMap(), чтобы получить Optional<BigDecimal>; map() получит Optional<Optional<BigDecimal>>

  4. Нам нужно обернуть результат в Optional, чтобы он соответствовал сигнатуре метода.

  5. Если Optional не содержит значения, сумма равна 0

Optional делает код менее читабельным! Я считаю, что понятность должна быть всегда важнее стиля кода.

К счастью, Optional предлагает метод stream() (начиная с Java 9). Он позволяет упростить функциональный конвейер:

public BigDecimal getOrderPrice(Long orderId) {     return Optional.ofNullable(orderId)             .stream()             .map(orderRepository::findByOrderId)             .flatMap(Collection::stream)             .map(OrderLine::getPrice)             .reduce(BigDecimal.ZERO, BigDecimal::add); }

Вот краткая информация о типе на каждой строке:

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


Перевод материала подготовлен в рамках курса «Java Developer. Basic». Приглашаем всех желающих на день открытых дверей онлайн, где можно подробнее узнать о формате и программе обучения, а также познакомиться с преподавателем.

ссылка на оригинал статьи https://habr.com/ru/company/otus/blog/561730/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *