Avete già visto questo molte volte da soli, di che sono sicuro:Esiste un modo elegante per ottenere il primo valore non nullo di più metodi restituiti in Java?
public SomeObject findSomeObject(Arguments args) {
SomeObject so = queryFirstSource(args); // the most likely source first, hopefully
if (so != null) return so;
so = querySecondSource(args); // a source less likely than the first, hopefully
if (so != null) return so;
so = queryThirdSource(args); // a source less likely than the previous, hopefully
if (so != null) return so;
// and so on
}
Abbiamo diverse fonti in cui un oggetto che cerchiamo potrebbe essere. Come esempio più vivido possiamo immaginare che prima controlliamo se un userid è in una lista di utenti privilegiati. In caso contrario, controlliamo se l'ID utente è nell'elenco degli utenti consentiti. Altrimenti restituiamo null. (Non è l'esempio migliore, ma spero che sia uno vivido-sufficiente.)
Guava ci offre alcuni aiutanti che potrebbero abbellire il codice sopra:
public SomeObject findSomeObject(Arguments args) {
// if there are only two objects
return com.google.common.base.Objects.firstNonNull(queryFirstSource(args), querySecondSource(args));
// or else
return com.google.common.collect.Iterables.find(
Arrays.asList(
queryFirstSource(args)
, querySecondSource(args)
, queryThirdSource(args)
// , ...
)
, com.google.common.base.Predicates.notNull()
);
}
Ma, come i più esperti tra noi avremo già visto, questo può funzionare male se le ricerche (es. queryXXXXSource(args)
) richiedono un certo periodo di tempo. Questo perché ora interrogiamo prima tutte le fonti e poi passiamo i risultati al metodo che trova il primo tra quei risultati che non è null
.
Contrariamente al primo esempio, in cui la sorgente successiva viene valutata solo quando la prima non restituisce qualcosa, questa seconda soluzione potrebbe sembrare migliore all'inizio, ma potrebbe comportare prestazioni molto peggiori.
Ecco dove arriviamo alla mia domanda reale e al punto in cui suggerisco qualcosa di quello spero che qualcuno abbia già implementato la base di esso o che qualcuno potrebbe proporre una soluzione addirittura intelligente.
In inglese semplice: Qualcuno ha già implementato tale defferedFirstNonNull
(vedere di seguito) o qualcosa di simile? Esiste una soluzione Java semplice per ottenere questo risultato con il nuovo framework Stream? Puoi proporre un'altra soluzione elegante che ottenga lo stesso risultato?
Regole: Java 8 è consentito, così come attiva tenute e ben note librerie di terze parti come Guava di Google o di Apache Commons Lang con licenza Apache o simile (No GPL!).
La soluzione proposta:
public SomeObject findSomeObject(Arguments args) {
return Helper.deferredFirstNonNull(
Arrays.asList(
args -> queryFirstSource(args)
, args -> querySourceSource(args)
, args -> queryThirdSource(args)
)
, x -> x != null
)
}
Quindi il metodo defferedFirstNonNull
sarebbe valutare ogni espressione lambda dopo l'altro e, non appena il predicato (x -> x != null
) è vero (cioè abbiamo trovato un match) il metodo sarebbe tornato il risultato immediatamente e non richiederebbe ulteriori fonti.
PS: so che le espressioni args -> queryXXXXSource(args)
potrebbero essere abbreviate in queryXXXXSource
. Ma ciò renderebbe più difficile leggere la soluzione proposta perché non è ovvio a prima vista cosa accadrà.
Ho scelto questa risposta come risposta designata in quanto combina tutte le altre risposte e sembra quindi 'completa'. Non conoscevo la classe 'Optional <>' e penso che fornisca il modo più elegante per il mio problema. – cimnine