2015-12-29 7 views
9

Come posso fare qualcosa come il seguente codice JavaScript, in Java?Come posso valutare la prossima dichiarazione quando è stato restituito un valore nullo in Java?

var result = getA() || getB() || getC() || 'all of them were undefined!'; 

Quello che voglio fare è quello di continuare a valutare le dichiarazioni o metodi, fino a quando si ottiene qualcosa invece di null.

Desidero che il codice del chiamante sia semplice ed efficace.

+2

Cosa vuoi in 'risultato' se tutti i metodi restituiscono cose diverse? –

+0

@TAsk - Finora, voglio la stessa classe o super classe. –

risposta

8

È possibile creare un metodo per questo.

public static <T> T coalesce(Supplier<T>... ts) { 
    return asList(ts) 
     .stream() 
     .map(t -> t.get()) 
     .filter(t -> t != null) 
     .findFirst() 
     .orElse(null); 
} 

codice tratto da: http://benjiweber.co.uk/blog/2013/12/08/null-coalescing-in-java-8/

modificare Come accennato nei commenti. Trova sotto un piccolo frammento come usarlo. L'utilizzo dell'API Stream presenta un vantaggio rispetto all'utilizzo di vargs come parametro del metodo. Se i valori restituiti dai metodi sono costosi e non restituiti da semplici getter la soluzione vargs valuterà prima tutti i metodi.

import static java.util.Arrays.asList; 
import java.util.function.Supplier; 
... 
static class Person { 
    String name; 
    Person(String name) { 
     this.name = name; 
    } 
    public String name() { 
     System.out.println("name() called for = " + name); 
     return name; 
    } 
} 

public static <T> T coalesce(Supplier<T>... ts) { 
    System.out.println("called coalesce(Supplier<T>... ts)"); 
    return asList(ts) 
      .stream() 
      .map(t -> t.get()) 
      .filter(t -> t != null) 
      .findFirst() 
      .orElse(null); 
} 

public static <T> T coalesce(T... ts) { 
    System.out.println("called coalesce(T... ts)"); 
    for (T t : ts) { 
     if (t != null) { 
      return t; 
     } 
    } 
    return null; 
} 

public static void main(String[] args) { 
    Person nobody = new Person(null); 
    Person john = new Person("John"); 
    Person jane = new Person("Jane"); 
    Person eve = new Person("Eve"); 
    System.out.println("result Stream API: " 
      + coalesce(nobody::name, john::name, jane::name, eve::name)); 
    System.out.println(); 
    System.out.println("result vargas : " 
      + coalesce(nobody.name(), john.name(), jane.name(), eve.name())); 
} 

uscita

called coalesce(Supplier<T>... ts) 
name() called for = null 
name() called for = John 
result Stream API: John 

name() called for = null 
name() called for = John 
name() called for = Jane 
name() called for = Eve 
called coalesce(T... ts) 
result vargas : John 

Come mostrato nell'output. Nella soluzione Stream i metodi che restituiscono i valori saranno valutati all'interno del metodo coalesce. Vengono eseguiti solo due, poiché la seconda chiamata restituisce il valore non-null previsto. Nella soluzione vargs tutti i metodi che restituiscono i valori vengono valutati prima che venga invocato il metodo coalesce.

+0

Non è sicuro che l'utilizzo dell'API java stream per questo caso d'uso sia pertinente (né efficiente) anche se l'OP richiede una soluzione Java8. – fluminis

+2

Questa è una buona risposta, ma sarebbe meglio con un esempio di come lo chiami (analogo all'esempio dell'OP). – ruakh

+0

@SubOptimal - Grazie, ho dovuto sostituire 'return asList (ts) ...' per restituire Arrays.asList (ts) ... ', ma comunque, è buono. –

4

Se si desidera utilizzare l'API di flusso java8, consultare la soluzione di SubOptimal.

In Java puro, non è possibile scrivere la stessa riga di javascript: java sarà più dettagliato.

non Se il getter è il tempo/consumo di risorse e non si cura di chiamare due volte, si può fare:

String result = getA() != null ? getA() : 
    (getB() != null ? getB() : 
     (getC() != null ? getC() : 
      "default value")); 

altro si può fare con semplice se:

String result = getA(); 
if (result == null) { 
    result = getB(); 
    if (result == null) { 
     result = getC(); 
     if (result == null) { 
      result = "default value"; 
     } 
    } 
} 
+0

Quest'ultima sembra la più chiara per me, descrive esattamente cosa sta facendo –

+0

Grazie, ma la creazione di codici annidati in questo tipo di situazione non è esattamente il mio preferito –

+1

Lo so, lo so, ma tieni a mente che l'API del flusso non è la pallottola d'oro per tutti. Dovresti leggere alcuni articoli davvero interessanti sull'argomento: https://jaxenter.com/java-performance-tutorial-how-fast-are-the-java-8-streams-118830.html https://dzone.com/ articoli/3-motivi-perché-non-dovresti-sostituire-i-tuoi-per-loop Inoltre, chiamando 'MyHelper.coalesce (getA(), getB(), getC()," valore predefinito ")' chiamerà ogni getters anche se il primo non è nullo! – fluminis

0

È inoltre possibile utilizzare Java 8 opzionale. Per esempio

public static void main(String[] args) { 
    getA().orElse(getB().orElse(getC().orElse("Unknown"))); 
} 

public static Optional<String> getA() { 
    return Optional.empty(); 
} 

public static Optional<String> getB() { 
    return Optional.empty(); 
} 

public static Optional<String> getC() { 
    return Optional.empty(); 
} 
Problemi correlati