
На этой неделе я узнал об одной интересной «новой» возможности 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); }
-
Оберните
orderIdвOptional -
Найдите соответствующие строки заказа
-
Используйте
flatMap(), чтобы получитьOptional<BigDecimal>;map()получитOptional<Optional<BigDecimal>> -
Нам нужно обернуть результат в
Optional, чтобы он соответствовал сигнатуре метода. -
Если
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/
Добавить комментарий