Geçmişte, bir koleksiyonu güvenli bir şekilde kopyalamayı şöyle söyledim:
public static void doThing(List<String> strs) {
List<String> newStrs = new ArrayList<>(strs);
veya
public static void doThing(NavigableSet<String> strs) {
NavigableSet<String> newStrs = new TreeSet<>(strs);
Ancak bu "kopya" kurucuları, benzer statik oluşturma yöntemleri ve akışları gerçekten güvenli midir ve kurallar nerede belirtilmiştir? Güvenli bir şekilde , Java dili tarafından sunulan temel anlamsal bütünlük garantileri ve makul bir kişi tarafından desteklenen SecurityManager
ve kusurların olmadığı varsayılarak kötü amaçlı bir arayan için uygulanan koleksiyonlar vardır.
Ben metod atma mutluyum ConcurrentModificationException
, NullPointerException
, IllegalArgumentException
, ClassCastException
, vb hatta belki asılı.
String
Değişmez tipte bir argüman örneği olarak seçtim . Bu soru için, kendi gotcha'ları olan değişebilir tiplerin koleksiyonları için derin kopyalarla ilgilenmiyorum.
(Açık olmak gerekirse, ben OpenJDK kaynak koduna bakıp için cevap çeşit var ArrayList
ve TreeSet
.)
NavigableSet
ve diğer Comparable
tabanlı koleksiyonlar bazen bir sınıfın compareTo()
doğru bir şekilde uygulanıp uygulanmadığını tespit eder ve bir istisna atar. Güvenilmeyen argümanlarla ne demek istediğiniz biraz net değil. Yani bir kötü adam kötü Dizeleri bir koleksiyon yapar ve bunları koleksiyonunuza kopyaladığınızda kötü bir şey olur mu? Hayır, koleksiyon çerçevesi oldukça sağlam, 1.2'den beri var.
HashSet
(ve genel olarak tüm diğer karma koleksiyonları) doğruluğu / bütünlüğü dayanıyor hashCode
elemanlarının uygulanması, TreeSet
ve PriorityQueue
bağlı Comparator
(ve hatta olamaz özel karşılaştırıcıyı kabul etmeden eşdeğer bir kopya oluştur) (varsa), derlemeden sonra hiçbir zaman doğrulanmayan EnumSet
belirli enum
türün bütünlüğüne güvenir , böylece üretilmeyen javac
veya el işi olmayan bir sınıf dosyası onu bozabilir.
new TreeSet<>(strs)
nerede strs
bir olduğunu NavigableSet
. Bu toplu bir kopya değildir, çünkü sonuç TreeSet
, semantiği korumak için bile gerekli olan kaynağın karşılaştırıcısını kullanacaktır. Sadece içerilen elemanları işlemede iyi iseniz, toArray()
gitmek için yoldur; yineleme sırasını bile koruyacaktır. “Elemanı al, elemanı doğrula, elemanı kullan” konusunda sorun yaşıyorsanız, bir kopya bile yapmanız gerekmez. Sorunlar, tüm öğeleri doğrulamak ve ardından tüm öğeleri kullanmak istediğinizde başlar. O zaman, TreeSet
özel karşılaştırıcı w kopyalamaya güvenemezsiniz
checkcast
Her öğe için a efektine sahip tek toplu kopyalama işlemi toArray
belirli bir türdedir. Biz her zaman bununla bitiyoruz. Genel koleksiyonlar, gerçek öğe türlerini bile bilmezler, bu nedenle kopya oluşturucuları benzer bir işlev sağlayamaz. Tabii ki, herhangi bir kontrolü doğru kullanımdan önce erteleyebilirsiniz, ancak sonra sorularınızın neyi amaçladığını bilmiyorum. Elemanları kullanmadan hemen önce kontrol etme ve hata verme konusunda iyi olduğunuzda "anlamsal bütünlük" e ihtiyacınız yoktur.