
На этой неделе я узнал об одной интересной "новой" возможности 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". Приглашаем всех желающих на день открытых дверей онлайн, где можно подробнее узнать о формате и программе обучения, а также познакомиться с преподавателем.