Подтвердить что ты не робот

Операции над 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 (больше?).

4b9b3361

Ответ 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

Не только быстрее и короче, но и проще.