validate not ejemplo check java java-8 null java-stream

not - optional java ejemplo



Es Java''s Collectors.toSet() garantizado para permitir nulos? (1)

La interfaz Set no promete si las implementaciones permiten elementos null . Se supone que cada implementación declara esto en su documentación.

Collectors.toSet() promete devolver una implementación de Set pero explícitamente hace que "no se devuelvan garantías sobre el tipo, mutabilidad, serializabilidad o seguridad de hilos del Set ". La seguridad nula no se menciona.

La implementación actual de Collectors.toSet() en OpenJDK siempre usa HashSet , que permite elementos nulos, pero esto podría cambiar en el futuro y otras implementaciones pueden hacerlo de manera diferente.

Si una implementación de Set prohíbe elementos null , arroja NullPointerException varias veces, en particular durante un intento de add(null) . Parecería que si Collectors.toSet() decidiera usar una implementación de Set nula, stream.collect(Collectors.toSet()) a stream.collect(Collectors.toSet()) en una Stream stream . La especificación de collect no enumera ninguna excepción, ni tampoco la especificación de ninguno de los métodos de Collector . Esto podría sugerir que la llamada por collect permite nulos dentro del stream , pero por otro lado no está claro si esto realmente significa mucho, ya que NullPointerException es una excepción no verificada y no tiene que estar en la lista estrictamente.

¿Se especifica esto más claramente en otro lugar? En particular, ¿se garantiza que el siguiente código no arrojará? ¿Se garantiza que es true ?

import java.util.stream.*; class Test { public static boolean setContainsNull() { return Stream.of("A", "list", "of", null, "strings") .collect(Collectors.toSet()) .contains(null); } }

De lo contrario, supongo que siempre debemos asegurarnos de que una secuencia no contenga nulos antes de utilizar Collectors.toSet() o estar preparados para manejar NullPointerException . (¿Esta excepción es suficiente por sí sola?) Alternativamente, cuando esto es inaceptable o difícil, podemos solicitar una implementación de conjunto específico usando código como Collectors.toCollection(HashSet::new) .

Editar: hay una pregunta existente que suena superficialmente similar, y esta pregunta se cerró como un supuesto duplicado de eso. Sin embargo, la pregunta vinculada no aborda Collectors.toSet() en absoluto. Además, las respuestas a esa pregunta forman los supuestos subyacentes de mi pregunta. Esa pregunta es: ¿se permiten nulos en las transmisiones? Sí. Pero, ¿qué sucede cuando una secuencia (perfectamente permitida) que contiene nulos se recopila a través de un recopilador estándar?


Existe una diferencia entre comportamientos deliberadamente no especificados, como "tipo, mutabilidad, serializabilidad o seguridad de subprocesos" y comportamiento no especificado, como el soporte null .

Siempre que un comportamiento no está especificado, el comportamiento real de la implementación de referencia tiende a convertirse en una cuestión de hecho que no puede modificarse más tarde, incluso si contrarresta la intención original, debido a restricciones de compatibilidad, o al menos no se puede cambiar sin una razón fuerte

Tenga en cuenta que aunque no se utilizó el derecho reservado para devolver un conjunto realmente inmutable o no serializable, simplemente porque no existía ese tipo en la versión Java 8, era posible imponer un comportamiento no null incluso sin la existencia de un tipo de mapa hash adecuado. , al igual que groupingBy prohíbe null claves null , aunque también está poco especificado.

Además, toMap cuenta que si bien groupingBy collector rechaza deliberadamente claves null en su código de implementación, toMap es un buen ejemplo de cómo el comportamiento real se convierte en parte del contrato. En Java 8, toMap permite claves null pero rechaza valores null , simplemente porque invoca Map.merge que tiene ese comportamiento. Parece que este no era un comportamiento intencionado en primer lugar. Ahora, en Java 9, el colector toMap sin una función de fusión ya no usa Map.merge ( JDK-8040892 , ver también esta respuesta ), pero deliberadamente rechaza valores null en el código de colector, para ser compatible con la versión anterior. . Simplemente porque nunca se dijo que el comportamiento null está intencionalmente no especificado.

Por lo tanto, Collectors.toSet() (y también Collectors.toList() ) permiten valores null para dos versiones principales de Java ahora y no hay ninguna especificación que diga que no debe dar esto por supuesto, por lo que puede estar tranquilo de que esto no cambio en el futuro