2014-05-01 35 views
12

Java 8 ma kilka klas opcjonalnych, takich jak OptionalDouble, OptionalInt, OptionalLong.Operacje na Java 8 Opcjonalne * wartości.

Czy istnieje przyjemny sposób działania z Opcjonalnymi wartościami tego samego rodzaju? To znaczy, chciałbym móc:

OptionalDouble d1 = OptionalDouble.of(1.); 
OptionalDouble d2 = OptionalDouble.of(2.); 
OptionalDouble d3 = OptionalDouble.of(3.); 

OptionalDouble result = d1.add(d2).multiply(d3); 

I oczywiście, jeśli którykolwiek z nich jest "pusty", wynik powinien być pusty. Po przejściu przez trochę google znalazłem kilka próbek kodu, w których ludzie używają tych funkcji (np. add), ale to nie jest część API (już?).

Odpowiedz

3

Dziwne. Numer Optional ma metodę, której możesz użyć, aby zrobić coś podobnego do tego, czego chcesz, ale wydaje się być nieobecna w pierwotnych opcjach. Uważam, że obecnie jedynym rozwiązaniem jest użycie OptionalDouble::isPresent lub OptionalDouble::ifPresent.

Można również zdefiniować własne metody pomocnicze add lub zdefiniować własną klasę OptionalDouble, aby uwzględnić te metody.

+2

'Opcjonalne # mapa' wydaje się wymagać' funkcji', a nie 'BinaryOperator', więc działałoby tylko z funkcjami działającymi na jednej wartości, a nie takimi jak' add' czy 'multiply'. – ajb

+0

Używam metody pomocnika, ale tak naprawdę nie rozumiem powodu, dla którego pominięto te metody lub przynajmniej możliwość ich dodania.Zwróć uwagę, że klasy "Opcjonalne" dla prymitywów takich jak 'OpcjonalneDouble' są' końcowe', więc nie można ich nawet rozszerzyć. – siki

+1

@siki Są one ostateczne, ponieważ opcje są niezmiennymi klasami i dlatego nigdy nie powinny być przedłużane, ponieważ nie można zagwarantować niezmienności, a następnie, jeśli metoda przyjmuje parametr "OptionalDouble" jako. – skiwi

3

Możesz stworzyć własną implementację, która zawiera OptionalDouble, bardzo ważną rzeczą, o której tutaj należy pamiętać jest to, że twoja klasa enkapsulacji powinna być niezmienna, aby zapobiec pomyłkom, ponieważ sama jest niezmienna.

Własna implementacja jest preferowana w stosunku do metody statycznej dla czytelności.

poszedł do przodu i stworzył własną rękę, z najbardziej podstawowych zachowań jak to możliwe:

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 + "]"; 
    } 
} 

które następnie mogą być używane jako:

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(); 
2

użyłbym zwykły 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 

Nie tylko jest szybszy i krótszy, ale także prostszy.

3

Głównym celem Optional jest przedstawienie funkcji return value that might be absent.

Celem posiadania prymitywnych specjalizacji strumieni jest unikanie narzutów boksu/rozpakowywania. Z OptionalInt i przyjaciółmi istnieje nieunikniony poziom boksowania (co byłoby gorsze, gdyby nie istniały, jako alternatywa byłaby Optional<Integer>), ale intencją jest, aby każdy, kto przetworzy wartość zwrotu, rozpakował je natychmiast (lub zapewnił domyślne lub wyrzuć wyjątek, jeśli jest nieobecny), a następnie zajmij się rzeczywistymi prymitywami od tego momentu.

Obsługa wszystkich dodatkowych interfejsów API do wykonywania operacji arytmetycznych, porównań itp. Na opcjonalnych elementach pierwotnych spowodowałaby jeszcze więcej nadęcia interfejsu API. Używanie go doprowadziłoby do bałaganu, powolnego kodu, co stanowiło wadę w porównaniu z doskonale złożoną składnią wyrażeń arytmetycznych, która już istnieje w Javie. Krótko mówiąc, dodanie kilku operacji na opcjonalnych elementach pierwotnych nie było przydatne.

Powiązane problemy