Dans le passé, j'ai dit que pour copier une collection en toute sécurité, faites quelque chose comme:
public static void doThing(List<String> strs) {
List<String> newStrs = new ArrayList<>(strs);
ou
public static void doThing(NavigableSet<String> strs) {
NavigableSet<String> newStrs = new TreeSet<>(strs);
Mais ces constructeurs de «copie», des méthodes de création statique similaires et des flux, sont-ils vraiment sûrs et où sont les règles spécifiées? Par sûr, j'entends les garanties d' intégrité sémantique de base offertes par le langage Java et les collections appliquées contre un appelant malveillant, en supposant SecurityManager
qu'elles soient sauvegardées par un raisonnable et qu'il n'y a pas de défauts.
Je suis heureux avec le lancement de la méthode ConcurrentModificationException
, NullPointerException
, IllegalArgumentException
, ClassCastException
, etc., ou peut - être même accroché.
J'ai choisi String
comme exemple d'argument de type immuable. Pour cette question, je ne suis pas intéressé par les copies complètes pour les collections de types mutables qui ont leurs propres pièges.
(Pour être clair, j'ai regardé le code source d'OpenJDK et j'ai une sorte de réponse pour ArrayList
et TreeSet
.)
NavigableSet
et d'autres Comparable
collections basées peuvent parfois détecter si une classe ne s'implémente pas compareTo()
correctement et lever une exception. On ne sait pas trop ce que vous entendez par arguments non fiables. Vous voulez dire qu'un malfaiteur crée une collection de mauvaises cordes et lorsque vous les copiez dans votre collection, quelque chose de mauvais se produit? Non, le cadre des collections est assez solide, il existe depuis la 1.2.
HashSet
(et toutes les autres collections de hachage en général) repose sur l'exactitude / l'intégrité de la hashCode
mise en œuvre des éléments, TreeSet
et PriorityQueue
dépend de la Comparator
(et vous ne pouvez même pas créer une copie équivalente sans accepter le comparateur personnalisé s'il en existe un), EnumSet
fait confiance à l'intégrité du enum
type particulier qui n'est jamais vérifié après la compilation, de sorte qu'un fichier de classe, non généré javac
ou fabriqué à la main, peut le subvertir.
new TreeSet<>(strs)
où strs
est un NavigableSet
. Ce n'est pas une copie en bloc, car le résultat TreeSet
utilisera le comparateur de la source, ce qui est même nécessaire pour conserver la sémantique. Si vous êtes prêt à simplement traiter les éléments contenus, toArray()
c'est la voie à suivre; il conservera même l'ordre d'itération. Lorsque vous êtes d'accord avec "prendre élément, valider élément, utiliser élément", vous n'avez même pas besoin d'en faire une copie. Les problèmes commencent lorsque vous souhaitez vérifier tous les éléments, puis en utilisant tous les éléments. Ensuite, vous ne pouvez pas faire confiance à une TreeSet
copie avec un comparateur personnalisé
checkcast
pour chaque élément, concerne toArray
un type spécifique. Nous y terminons toujours. Les collections génériques ne connaissent même pas leur type d'élément réel, de sorte que leurs constructeurs de copie ne peuvent pas fournir une fonctionnalité similaire. Bien sûr, vous pouvez reporter tout contrôle à une bonne utilisation antérieure, mais je ne sais pas à quoi vos questions visent. Vous n'avez pas besoin d '«intégrité sémantique», lorsque vous êtes prêt à vérifier et à échouer immédiatement avant d'utiliser des éléments.