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