Операции над Java 8 Необязательные * значения.
В Java 8 имеется ряд необязательных классов, таких как OptionalDouble
, OptionalInt
, OptionalLong
.
Есть ли хороший способ работы с дополнительными значениями одного и того же типа? То есть, я хотел бы иметь возможность:
OptionalDouble d1 = OptionalDouble.of(1.);
OptionalDouble d2 = OptionalDouble.of(2.);
OptionalDouble d3 = OptionalDouble.of(3.);
OptionalDouble result = d1.add(d2).multiply(d3);
И, конечно, если любой из них "пуст", результат должен быть пустым. После нескольких попыток поиска я нашел несколько примеров кода, в которых люди используют эти функции (например, add
), но это не часть API (больше?).
Ответы
Ответ 1
Weird. Ссылка Optional
имеет метод map
, который вы можете использовать что-то похожее на то, что хотите, но оно, по-видимому, отсутствует в примитивных опциях. Я считаю, что ваш единственный ресурс в настоящее время заключается в использовании OptionalDouble::isPresent
или OptionalDouble::ifPresent
.
Или вы могли бы определить свои собственные вспомогательные методы add
или определить свой собственный класс OptionalDouble
, чтобы включить эти методы.
Ответ 2
Вы можете сделать свою собственную реализацию, которая инкапсулирует OptionalDouble
, здесь очень важно рассмотреть, что ваш инкапсулирующий класс должен быть неизменным, чтобы предотвратить путаницу, поскольку OptionalDouble
сам неизменен.
Собственная реализация предпочтительнее статического метода для удобочитаемости.
Я пошел вперед и создал свое собственное, с максимально возможным поведением:
public class OptionalDoubleImproved {
private static final OptionalDoubleImproved EMPTY = OptionalDoubleImproved.of(OptionalDouble.empty());
private final OptionalDouble optionalDouble;
private OptionalDoubleImproved(final OptionalDouble optionalDouble) {
this.optionalDouble = Objects.requireNonNull(optionalDouble);
}
public static OptionalDoubleImproved of(final OptionalDouble optionalDouble) {
return new OptionalDoubleImproved(optionalDouble);
}
public OptionalDoubleImproved applyFunction(final DoubleBinaryOperator operator, final OptionalDouble operand) {
Objects.requireNonNull(operator);
Objects.requireNonNull(operand);
if (!optionalDouble.isPresent() || !operand.isPresent()) {
return EMPTY;
}
return OptionalDoubleImproved.of(OptionalDouble.of(operator.applyAsDouble(optionalDouble.getAsDouble(), operand.getAsDouble())));
}
public OptionalDouble get() {
return optionalDouble;
}
@Override
public int hashCode() {
int hash = 7;
hash = 53 * hash + Objects.hashCode(this.optionalDouble);
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final OptionalDoubleImproved other = (OptionalDoubleImproved) obj;
if (!Objects.equals(this.optionalDouble, other.optionalDouble)) {
return false;
}
return true;
}
@Override
public String toString() {
return "OptionalDoubleImproved[" + optionalDouble + "]";
}
}
который затем можно использовать как:
OptionalDouble d1 = OptionalDouble.of(1.);
OptionalDouble d2 = OptionalDouble.of(2.);
OptionalDouble d3 = OptionalDouble.of(3.);
OptionalDouble result = OptionalDoubleImproved.of(d1)
.applyFunction((a, b) -> a + b, d2)
.applyFunction((a, b) -> a * b, d3)
.get();
Ответ 3
Основной целью Optional
является представление функции возвращаемого значения, которое может отсутствовать.
Точка примитивной специализации потоков состоит в том, чтобы избежать накладных расходов на бокс /unboxing. С OptionalInt
и друзьями там неизбежный уровень бокса (что было бы хуже, если бы они не существовали, поскольку альтернатива была бы Optional<Integer>
), но целью является то, кто обрабатывает возвращаемое значение, чтобы немедленно его удалить (или предоставить по умолчанию или выбросить исключение, если он отсутствует), а затем обработать фактические примитивы с этого момента.
Поддержка всех дополнительных API для выполнения арифметики, сравнений и т.д. на дополнительных примитивах добавит еще больше раздувания API. Использование этого приведет к загроможденному, медленному коду, весьма невыгодному по сравнению с прекрасно арифметическим синтаксисом выражений, который уже существует в Java. Короче говоря, добавление кучи операций над необязательными примитивами не считалось полезным.
Ответ 4
Я бы использовал простой double
double d1 = 1, d2 = 2, d3 = 3;
if (condition)
d1 = Double.NaN;
double result = (d1 + d2) * d3; // if any double is NaN, the result is NaN
Не только быстрее и короче, но и проще.