En el pasado, he dicho que copiar una colección de manera segura haga algo como:
public static void doThing(List<String> strs) {
List<String> newStrs = new ArrayList<>(strs);
o
public static void doThing(NavigableSet<String> strs) {
NavigableSet<String> newStrs = new TreeSet<>(strs);
Pero, ¿son estos constructores de "copia", métodos y flujos de creación estáticos similares, realmente seguros y dónde se especifican las reglas? Por seguro, quiero decir, son las garantías básicas de integridad semántica ofrecidas por el lenguaje Java y las colecciones aplicadas contra un llamador malicioso, suponiendo SecurityManagerque esté respaldado por un razonable y que no haya fallas.
Estoy contento con el lanzamiento método ConcurrentModificationException, NullPointerException, IllegalArgumentException, ClassCastException, etc, o tal vez incluso colgado.
He elegido Stringcomo ejemplo un argumento de tipo inmutable. Para esta pregunta, no me interesan las copias profundas para colecciones de tipos mutables que tienen sus propios trucos.
(Para ser claros, he mirado el código fuente de OpenJDK y tengo algún tipo de respuesta para ArrayListy TreeSet).
NavigableSety otras Comparablecolecciones basadas a veces pueden detectar si una clase no se implementa compareTo()correctamente y lanzar una excepción. No está claro qué quiere decir con argumentos no confiables. ¿Te refieres a un malhechor que crea una colección de cadenas malas y cuando las copias a tu colección, algo malo sucede? No, el marco de colecciones es bastante sólido, existe desde 1.2.
HashSet(y todas las demás colecciones de hash en general) se basa en la corrección / integridad de la hashCodeimplementación de los elementos, TreeSety PriorityQueuedepende de Comparator(y ni siquiera puede crea una copia equivalente sin aceptar el comparador personalizado si lo hay), EnumSetconfía en la integridad del enumtipo particular que nunca se verifica después de la compilación, por lo que un archivo de clase, no generado javaco hecho a mano, puede subvertirlo.
new TreeSet<>(strs)dónde strsestá a NavigableSet. Esta no es una copia masiva, ya que el resultado TreeSetutilizará el comparador de la fuente, que incluso es necesario para mantener la semántica. Si está bien con solo procesar los elementos contenidos, este toArray()es el camino a seguir; incluso mantendrá el orden de iteración. Cuando está bien con "tomar elemento, validar elemento, usar elemento", ni siquiera necesita hacer una copia. Los problemas comienzan cuando desea verificar todos los elementos, seguido de la utilización de todos los elementos. Entonces, no puede confiar en una TreeSetcopia con un comparador personalizado
checkcastpara cada elemento, es toArraycon un tipo específico. Siempre terminamos en eso. Las colecciones genéricas ni siquiera conocen su tipo de elemento real, por lo que sus constructores de copias no pueden proporcionar una funcionalidad similar. Por supuesto, puede diferir cualquier verificación al uso previo correcto, pero entonces, no sé a qué apuntan sus preguntas. No necesita "integridad semántica", cuando está de acuerdo con verificar y fallar inmediatamente antes de usar elementos.