java coalesce

¿Cómo obtener el primer valor no nulo en Java?



coalesce (12)

¿Hay un equivalente Java de la función COALESCE de SQL? Es decir, ¿hay alguna forma de devolver el primer valor no nulo de varias variables?

p.ej

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

De alguna manera, quiero tener una declaración que devuelva el primer valor no nulo de a , c - en este caso, devolvería b , o 4.4. (Algo así como el método sql - devuelve COALESCE(a,b,c) ). Sé que puedo hacerlo explícitamente con algo como:

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

Pero me preguntaba si había alguna función incorporada y aceptada para lograr esto.


¿Qué le parece usar proveedores cuando quiere evitar evaluar algún método costoso?

Me gusta esto:

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

Y luego usarlo así:

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

También puede usar métodos sobrecargados para las llamadas con dos, tres o cuatro argumentos.

Además, también puedes usar streams con algo como esto:

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



Con Guava puedes hacer:

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

que no arroja NPE si tanto a como b son null .

EDITAR: Estaba equivocado, arroja NPE. La forma correcta como lo comentó Michal Čizmazia es:

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


Esta situación requiere un preprocesador. Porque si escribe una función (método estático) que elige el primer valor no nulo, evalúa todos los elementos. Es un problema si algunos elementos son llamadas de método (pueden ser llamadas a métodos costosos en el tiempo). Y estos métodos se llaman incluso si algún elemento antes de ellos no es nulo.

Algunos funcionan de esta manera

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

debe usarse, pero antes de compilar en código de bytes debe haber un preprocesador que encuentre usos de esta "función de fusión" y lo reemplace con una construcción como

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

Actualización 2014-09-02:

¡Gracias a Java 8 y Lambdas existe la posibilidad de tener una verdadera fusión en Java! Incluyendo la característica crucial: las expresiones particulares se evalúan solo cuando es necesario; si las anteriores no son nulas, las siguientes no se evalúan (los métodos no se invocan, las operaciones de computación o de disco / red no se realizan).

Escribí un artículo sobre Java 8: coalesce - hledáme neNULLové hodnoty - (escrito en checo, pero espero que los ejemplos de código sean comprensibles para todos).


No, no hay.

Lo más cercano que puede obtener es:

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

Por razones eficientes, puede manejar los casos comunes de la siguiente manera:

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 ... }


Puedes intentar esto:

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

Basado en this respuesta


Qué tal si:

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

Java ArrayList permite convenientemente entradas nulas y esta expresión es consistente independientemente del número de objetos a considerar. (De esta forma, todos los objetos considerados deben ser del mismo tipo).


Si solo hay dos referencias para probar y está usando Java 8, podría usar

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

Si importa estática Opcional, la expresión no es tan mala.

Desafortunadamente, su caso con "varias variables" no es posible con un método opcional. En cambio, podrías usar:

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



Siguiendo con la respuesta de LES2, puede eliminar algunas repeticiones en la versión eficiente llamando a la función sobrecargada:

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); }


Solo por completitud, el caso de "varias variables" es de hecho posible, aunque no elegante en absoluto. Por ejemplo, para las variables o , p y q :

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

Tenga en cuenta el uso de orElseGet() atiende al caso que o , p y q no son variables sino expresiones caras o con efectos secundarios no deseados.

En el caso más general 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

Esto puede generar expresiones excesivamente largas. Sin embargo, si estamos intentando movernos a un mundo sin null , entonces v[i] probablemente ya sea de tipo Optional<String> , en lugar de simplemente String . En este caso,

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

o en el caso de expresiones:

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

Además, si también se está moviendo a un estilo funcional-declarativo, o , p , q deberían ser del tipo Supplier<String> como en:

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

Y luego todo el coalesce reduce simplemente a o.get() .

Para un ejemplo más concreto:

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() y ageFromInput() ya devolverían Optional<Integer> , naturalmente.

Y luego la coalesce convierte en effectiveAge.get() o simplemente effectiveAge si estamos contentos con un Supplier<Integer> .

En mi humilde opinión, con Java 8 veremos más y más códigos estructurados de esta manera, ya que son extremadamente autoexplicativos y eficientes al mismo tiempo, especialmente en casos más complejos.

Extraño una clase Lazy<T> que invoca un Supplier<T> solo una vez, pero de forma perezosa, así como la coherencia en la definición de Optional<T> (es decir, Optional<T> - Optional<T> operadores, o incluso Supplier<Optional<T>> ).


Object coalesce(Object... objects) { for(Object o : object) if(o != null) return o; return null; }