webentwicklung-frage-antwort-db.com.de

Wie erhalte ich den ersten Nicht-Null-Wert in Java?

Gibt es ein Java-Äquivalent der COALESCE-Funktion von SQL? Gibt es eine Möglichkeit, den ersten Nicht-Null-Wert mehrerer Variablen zurückzugeben?

z.B.

Double a = null;
Double b = 4.4;
Double c = null;

Ich möchte eine Anweisung haben, die den ersten Nicht-Null-Wert von a, b und c zurückgibt. In diesem Fall würde b oder 4.4 zurückgegeben. (Etwas wie die SQL-Methode - geben Sie COALESCE(a,b,c) zurück). Ich weiß, dass ich das explizit machen kann mit:

return a != null ? a : (b != null ? b : c)

Aber ich fragte mich, ob es dafür eine eingebaute, akzeptierte Funktion gab.

124
froadie

Nein, das gibt es nicht.

Das nächste, was Sie bekommen können, ist:

public static <T> T coalesce(T ...items) {
    for(T i : items) if(i != null) return i;
    return null;
}

Aus Gründen der Effizienz können Sie die häufigsten Fälle wie folgt behandeln:

public static <T> T coalesce(T a, T b) {
    return a == null ? b : a;
}
public static <T> T coalesce(T a, T b, T c) {
    return a != null ? a : (b != null ? b : c);
}
public static <T> T coalesce(T a, T b, T c, T d) {
    return ...
}
96
les2
139
Andrzej Polis

Wenn nur zwei Variablen geprüft werden sollen und Sie Guave verwenden, können Sie MoreObjects.firstNonNull (T zuerst, T Sekunde) verwenden.

52
Dave

Wenn nur zwei Referenzen zum Testen vorhanden sind und Sie Java 8 verwenden, können Sie dies verwenden

Object o = null;
Object p = "p";
Object r = Optional.ofNullable( o ).orElse( p );
System.out.println( r );   // p

Wenn Sie statisch importieren, ist der Ausdruck nicht zu schlecht.

Leider ist Ihr Fall mit "mehreren Variablen" mit einer Optional-Methode nicht möglich. Stattdessen könnten Sie verwenden:

Object o = null;
Object p = null;
Object q = "p";

Optional<Object> r = Stream.of( o, p, q ).filter( Objects::nonNull ).findFirst();
System.out.println( r.orElse(null) );   // p
35

Nach der Antwort von LES2 können Sie einige Wiederholungen in der effizienten Version beseitigen, indem Sie die überladene Funktion aufrufen:

public static <T> T coalesce(T a, T b) {
    return a != null ? a : b;
}
public static <T> T coalesce(T a, T b, T c) {
    return a != null ? a : coalesce(b,c);
}
public static <T> T coalesce(T a, T b, T c, T d) {
    return a != null ? a : coalesce(b,c,d);
}
public static <T> T coalesce(T a, T b, T c, T d, T e) {
    return a != null ? a : coalesce(b,c,d,e);
}
24
Eric

Diese Situation erfordert einen Präprozessor. Wenn Sie eine Funktion schreiben (statische Methode), die den ersten Wert ungleich Null wählt, werden alle Elemente ausgewertet. Es ist ein Problem, wenn einige Elemente Methodenaufrufe sind (möglicherweise zeitaufwändige Methodenaufrufe). Diese Methoden werden auch dann aufgerufen, wenn ein Element vor ihnen nicht null ist.

Einige funktionieren so

public static <T> T coalesce(T ...items) …

sollte verwendet werden, aber vor der Kompilierung in Byte-Code sollte es einen Präprozessor geben, der die Verwendung dieser „Koaleszierungsfunktion“ findet und durch die Konstruktion ersetzt

a != null ? a : (b != null ? b : c)

Update 2014-09-02:

Dank Java 8 und Lambdas besteht die Möglichkeit, in Java eine echte Vereinigung zu haben! Einschließlich des entscheidenden Features: Bestimmte Ausdrücke werden nur bei Bedarf ausgewertet. Wenn der frühere Ausdruck nicht null ist, werden folgende Ausdrücke nicht ausgewertet (Methoden werden nicht aufgerufen, Berechnungen oder Festplatten-/Netzwerkoperationen werden nicht ausgeführt).

Ich habe einen Artikel darüber geschrieben Java 8: coalesce - hledáme neNULLové hodnoty - (auf Tschechisch geschrieben, aber ich hoffe, dass Codebeispiele für jeden verständlich sind).

7
Franta

Mit Guava können Sie:

Optional.fromNullable(a).or(b);

was keine NPE auslöst, wenn sowohl a als auch bnull sind.

EDIT: Ich habe mich geirrt, es wirft NPE. Der richtige Weg, kommentiert von Michal Čizmazia ist:

Optional.fromNullable(a).or(Optional.fromNullable(b)).orNull();
5
Jamol

Der Vollständigkeit halber ist der Fall "mehrere Variablen" zwar möglich, jedoch nicht elegant. Beispielsweise für die Variablen o, p und q:

Optional.ofNullable( o ).orElseGet(()-> Optional.ofNullable( p ).orElseGet(()-> q ) )

Bitte beachten Sie die Verwendung von orElseGet() im Zusammenhang mit dem Fall, dass o, p und q keine Variablen sind, sondern Ausdrücke, die entweder teuer sind oder unerwünschte Nebenwirkungen haben.

Im allgemeinsten Fall coalesce(e[1],e[2],e[3],...,e[N])

coalesce-expression(i) ==  e[i]  when i = N
coalesce-expression(i) ==  Optional.ofNullable( e[i] ).orElseGet(()-> coalesce-expression(i+1) )  when i < N

Dies kann zu lange Ausdrücke erzeugen. Wenn wir jedoch versuchen, in eine Welt ohne null zu wechseln, sind v[i] höchstwahrscheinlich bereits vom Typ Optional<String> und nicht String. In diesem Fall, 

result= o.orElse(p.orElse(q.get())) ;

oder bei Ausdrücken:

result= o.orElseGet(()-> p.orElseGet(()-> q.get() ) ) ;

Wenn Sie außerdem zu einem funktional deklarativen Stil wechseln, sollten o, p und q vom Typ Supplier<String> sein, wie in:

Supplier<String> q= ()-> q-expr ;
Supplier<String> p= ()-> Optional.ofNullable(p-expr).orElseGet( q ) ;
Supplier<String> o= ()-> Optional.ofNullable(o-expr).orElseGet( p ) ;

Und dann reduziert sich das ganze coalesce einfach auf o.get().

Für ein konkreteres Beispiel:

Supplier<Integer> hardcodedDefaultAge= ()-> 99 ;
Supplier<Integer> defaultAge= ()-> defaultAgeFromDatabase().orElseGet( hardcodedDefaultAge ) ;
Supplier<Integer> ageInStore= ()-> ageFromDatabase(memberId).orElseGet( defaultAge ) ;
Supplier<Integer> effectiveAge= ()-> ageFromInput().orElseGet( ageInStore ) ;

defaultAgeFromDatabase(), ageFromDatabase() und ageFromInput() würden natürlich Optional<Integer> zurückgeben.

Und dann wird coalesceeffectiveAge.get() oder einfach effectiveAge, wenn wir mit einem Supplier<Integer> zufrieden sind.

IMHO, mit Java 8 werden wir immer mehr Code sehen, der so strukturiert ist, da er äußerst selbsterklärend und gleichzeitig effizient ist, insbesondere in komplexeren Fällen.

Ich vermisse eine Klasse Lazy<T>, die einen Supplier<T> nur einmal, aber träge, sowie Konsistenz in der Definition von Optional<T> (d. H. Optional<T>__Optional<T>-Operatoren oder sogar Supplier<Optional<T>>) aufruft.

4
Mario Rossi

Sie können dies versuchen:

public static <T> T coalesce(T... t) {
    return Stream.of(t).filter(Objects::nonNull).findFirst().orElse(null);
}

Basierend auf dieser Antwort

3
Lucas León

Wie wäre es mit Lieferanten, wenn Sie es vermeiden möchten, teure Methoden zu bewerten? 

So was:

public static <T> T coalesce(Supplier<T>... items) {
for (Supplier<T> item : items) {
    T value = item.get();
    if (value != null) {
        return value;
    }
    return null;
}

Und dann so verwenden:

Double amount = coalesce(order::firstAmount, order::secondAmount, order::thirdAmount)

Sie können auch überladene Methoden für die Aufrufe mit zwei, drei oder vier Argumenten verwenden.

Außerdem könnten Sie Streams mit etwas wie dem folgenden verwenden:

public static <T> T coalesce2(Supplier<T>... s) {
    return Arrays.stream(s).map(Supplier::get).filter(Objects::nonNull).findFirst().orElse(null);
}
1
Triqui

Wie wäre es mit:

firstNonNull = FluentIterable.from(
    Lists.newArrayList( a, b, c, ... ) )
        .firstMatch( Predicates.notNull() )
            .or( someKnownNonNullDefault );

Java ArrayList erlaubt bequem Null-Einträge und dieser Ausdruck ist unabhängig von der Anzahl der zu berücksichtigenden Objekte konsistent. (In diesem Formular müssen alle betrachteten Objekte vom selben Typ sein.)

0
Lonnie