Hola, compañeros desarrolladores de Java:
Sé que el tema puede ser un poco in advance
ya que el JDK8 aún no se ha lanzado (y no por ahora de todos modos ...) pero estaba leyendo algunos artículos sobre las expresiones Lambda y particularmente la parte relacionada con la nueva API de colección conocida como Stream.
Aquí está el ejemplo dado en el artículo de la Revista Java (es un algoritmo de población de nutrias ...):
Set<Otter> otters = getOtters();
System.out.println(otters.stream()
.filter(o -> !o.isWild())
.map(o -> o.getKeeper())
.filter(k -> k.isFemale())
.into(new ArrayList<>())
.size());
Mi pregunta es ¿qué sucede si en medio de la iteración interna de Set, una de las nutrias es nula?
Esperaría que se lanzara una NullPointerException, pero tal vez todavía estoy atrapado en el paradigma de desarrollo anterior (no funcional), ¿alguien puede aclararme cómo se debe manejar esto?
Si esto realmente arroja una NullPointerException, encuentro la función bastante peligrosa y tendré que usarla solo como se muestra a continuación:
- Desarrollador para asegurarse de que no haya un valor nulo (tal vez usando un .filter anterior (o -> o! = Null))
- Desarrollador para garantizar que la aplicación nunca genere una nutria nula o un objeto NullOtter especial con el que lidiar.
¿Cuál es la mejor opción o cualquier otra opción?
¡Gracias!
fuente
filter(Objects::nonNull)
conObjects
desdejava.utils
Respuestas:
El pensamiento actual parece ser "tolerar" nulos, es decir, permitirlos en general, aunque algunas operaciones son menos tolerantes y pueden terminar arrojando NPE. Consulte la discusión sobre nulos en la lista de correo del grupo de expertos de Bibliotecas Lambda, específicamente este mensaje . Posteriormente surgió un consenso en torno a la opción 3 (con una notable objeción de Doug Lea). Así que sí, la preocupación del OP sobre la explosión de oleoductos con NPE es válida.
No en vano Tony Hoare se refirió a los nulos como el "error de mil millones de dólares". Tratar con nulos es un verdadero dolor de cabeza. Incluso con colecciones clásicas (sin considerar lambdas o streams), los nulos son problemáticos. Como mencionó fge en un comentario, algunas colecciones permiten valores nulos y otras no. Con colecciones que permiten valores nulos, esto introduce ambigüedades en la API. Por ejemplo, con Map.get () , un retorno nulo indica que la clave está presente y su valor es nulo o que la clave está ausente. Hay que trabajar más para eliminar la ambigüedad de estos casos.
El uso habitual de nulo es para denotar la ausencia de un valor. El enfoque para lidiar con esto propuesto para Java SE 8 es introducir un nuevo
java.util.Optional
tipo, que encapsula la presencia / ausencia de un valor, junto con comportamientos de proporcionar un valor predeterminado, o lanzar una excepción, o llamar a una función, etc. si el valor está ausente.Optional
es utilizado solo por nuevas API, sin embargo, todo lo demás en el sistema aún tiene que soportar la posibilidad de nulos.Mi consejo es evitar las referencias nulas reales en la mayor medida posible. Es difícil ver en el ejemplo dado cómo podría haber una Nutria "nula". Pero si fuera necesario, las sugerencias del OP de filtrar valores nulos o mapearlos a un objeto centinela (el Patrón de objeto nulo ) son buenos enfoques.
fuente
null
apesta, por eso. Acc. para una encuesta que vi (no puedo encontrarla), NPE es la excepción número 1 en Java. SQL no es un lenguaje de programación de alto nivel, ciertamente no es funcional, que desprecia el nulo, así que no le importa.Aunque las respuestas son 100% correctas, una pequeña sugerencia para mejorar el
null
manejo de casos de la propia lista con Opcional :La parte
Optional.ofNullable(listOfStuff).orElseGet(Collections::emptyList)
le permitirá manejar bien el caso cuandolistOfStuff
sea nulo y devolver una lista vacía en lugar de fallar con NullPointerException.fuente
La respuesta de Stuart proporciona una gran explicación, pero me gustaría dar otro ejemplo.
Me encontré con este problema al intentar realizar una transmisión
reduce
en un flujo que contiene valores nulos (en realidad lo fueLongStream.average()
, que es un tipo de reducción). Dado que average () devuelveOptionalDouble
, asumí que Stream podría contener nulos, pero en su lugar se lanzó una NullPointerException. Esto se debe a la explicación de Stuart de nulo versus vacío.Entonces, como sugiere el OP, agregué un filtro así:
list.stream() .filter(o -> o != null) .reduce(..);
O, como se señala a continuación, use el predicado proporcionado por la API de Java:
De la discusión de la lista de correo, Stuart vinculó: Brian Goetz sobre nulos en Streams
fuente
Si solo desea filtrar los valores nulos de una secuencia, simplemente puede usar una referencia de método a java.util.Objects.nonNull (Object) . De su documentación:
Por ejemplo:
List<String> list = Arrays.asList( null, "Foo", null, "Bar", null, null); list.stream() .filter( Objects::nonNull ) // <-- Filter out null values .forEach( System.out::println );
Esto imprimirá:
fuente
Un ejemplo de cómo evitar nulos, por ejemplo, use el filtro antes de agrupar
Filtre las instancias nulas antes de groupingBy.
Aquí hay un ejemploMyObjectlist.stream() .filter(p -> p.getSomeInstance() != null) .collect(Collectors.groupingBy(MyObject::getSomeInstance));
fuente