Aikido

Koleksiyonlardan öğeleri çıkarırken neden güvenli desenler kullanmalısınız?

Okunabilirlik

Kural
Kullanım güvenli yöntemleri kullan çıkarırken koleksiyonlardan koleksiyonlardan
Değiştirme bir koleksiyonu döngü bir sırasındaki üzerinde genellikle hatalara hatalara yol açar.

Desteklenen diller: PY, Java, C/C++, C#, 
Swift/Objective-C, Ruby, PHP, Kotlin, Go,
Scala, Rust, Groovy, Dart, Julia, Elixit, 
Erlang, Clojure, OCaml, Lua

Giriş

Bir koleksiyondan yineleme sırasında öğelerin kaldırılması, Java'da eşzamanlı değiştirme istisnalarına ve C#'da öngörülemeyen davranışlara neden olur. Yineleyici, altta yatan koleksiyon değiştiğinde geçersiz hale gelen dahili bir işaretçiye sahiptir. Bu durum, koleksiyon türüne ve kullanılan kaldırma yöntemine bağlı olarak öğelerin atlanmasına, programın çökmesine veya sonsuz döngülere yol açar.

Neden önemli?

Sistem kararlılığı: Eşzamanlı değişiklik istisnaları, uygulamanın anında çökmesine neden olur. Üretim ortamında bu durum, isteklerin kaybolması ve hizmetin kullanılamaması anlamına gelir. Bu istisna genellikle belirli verilerle ilgili sınır durumlarında ortaya çıktığı için, test aşamasında tespit edilmesi zordur.

Veri bütünlüğü: İterasyonun ortasında silme işlemi başarısız olduğunda, koleksiyon kısmen değiştirilmiş bir durumda kalır. Bazı öğeler silinirken, silinmesi gereken diğer öğeler ise kalır. Bu durum, sonraki aşamalardaki işlemleri etkileyen tutarsız verilere yol açar.

Hata ayıklama karmaşıklığı: Eşzamanlı değiştirme hataları zamanlamaya bağlıdır ve yalnızca belirli veri kombinasyonlarında ortaya çıkabilir. Bu hataları tutarlı bir şekilde yeniden oluşturmak zordur; bu da hata ayıklama ve güvenilir bir şekilde düzeltme işlemlerini zorlaştırır.

Kod örnekleri

❌ Uygun değil:

List<User> users = getUserList();
for (User user : users) {
    if (!user.isActive()) {
        users.remove(user); // ConcurrentModificationException
    }
}

Neden yanlış: Şuradan kaldırma kullanıcılar Geliştirilmiş for döngüsüyle yineleme yaparken ortaya çıkan sorunlar ConcurrentModificationException. İteratör, koleksiyonun iteratörün dışında değiştirildiğini algılar ve derhal hata atar. İlk etkin olmayan kullanıcıdan sonraki tüm aktif kullanıcılar hiçbir zaman işleme alınmaz.

✅ Uygunluk:

List<User> users = getUserList();
Iterator<User> iterator = users.iterator();
while (iterator.hasNext()) {
    User user = iterator.next();
    if (!user.isActive()) {
        iterator.remove(); // Safe removal through iterator
    }
}

Bunun önemi: Kullanım iterator.remove() Yineleme sırasında öğeleri güvenli bir şekilde kaldırır. Yineleyici, tutarlı bir durum sağlar ve kalan öğeleri işlemeye devam eder. Etkin olmayan tüm kullanıcılar, istisna oluşmadan doğru bir şekilde kaldırılır.

Sonuç

İteratörleri kullanın remove() iterasyon sırasında güvenli bir şekilde kaldırma yöntemi. Alternatif olarak, şu özelliklere sahip akışları kullanın: filter() yeni koleksiyonlar oluşturmak veya removeIf() büyük hacimli atıkların toplanması için. Asla çöp toplama hizmetini aramayın remove() döngü sırasında doğrudan.

Sık Sorulan Sorular

Sorularınız mı var?

Peki ya indeksli normal for döngüleri kullanmak nasıl olur?

İndeks kullanarak geriye doğru yineleme işe yarar: for (int i = list.size() - 1; i >= 0; i--). Öğeleri kaldırmak sonraki öğeleri kaydırır, ancak geriye doğru yineleme atlamaları önler. Bununla birlikte, iterator.remove() veya removeIf() daha anlaşılır ve hata yapma olasılığı daha düşüktür.

Bunun yerine Java 8 ve üzeri sürümlerdeki `removeIf` yöntemini kullanabilir miyim?

Evet, `users.removeIf(user -> !user.isActive())` tercih edilen modern yaklaşımdır. Bu yöntem daha özlüdür ve yineleme işlemini dahili olarak güvenli bir şekilde gerçekleştirir. Bir predikata göre eleme yaparken `removeIf()` yöntemini, dönüşümler için akışları ve eleme mantığı karmaşık olduğunda yineleyici yöntemlerini kullanın.

Bu, tüm tahsilat türleri için geçerli mi?

Evet, ArrayList, HashSet, HashMap ve çoğu koleksiyon, yineleme sırasında değiştirildiğinde ConcurrentModificationException istisnası atar. ConcurrentHashMap gibi iş parçacığı güvenli koleksiyonlar, değiştirmeye izin verir ancak farklı çalışma kurallarına sahiptir. Değiştirme kuralları için her zaman koleksiyonun belgelerine bakın.

Peki ya C# koleksiyonları?

C#'da, yineleme sırasında koleksiyonlar üzerinde değişiklik yapıldığında InvalidOperationException hatası verilir. Yinelemeye başlamadan önce ToList() yöntemini kullanarak bir kopya oluşturun: foreach (var user in users.ToList()) ve ardından orijinal koleksiyondan silin. Ya da LINQ kullanın: users = users.Where(u => u.IsActive).ToList().

Birden fazla öğeyi verimli bir şekilde nasıl silebilirim?

Tek bir koleksiyon için removeIf() işlevini, karmaşık filtreleme işlemleri için ise akışları kullanın: users = users.stream().filter(User::isActive).collect(Collectors.toList()). Bu yaklaşımlar toplu işlemler için optimize edilmiştir ve bir döngü içinde öğeleri tek tek kaldırmaya kıyasla daha verimlidir.

Şimdi güvenliğinizi sağlayın

Kodunuzu, bulutunuzu ve çalışma zamanınızı tek bir merkezi sistemde güvenceye alın.
Güvenlik açıklarını otomatik olarak hızla bulun ve düzeltin.

Kredi kartı gerekmez | Tarama sonuçları 32 saniyede.