Bir Tamsayıyı Listeden Düzgün Kaldırma <Integer>


201

İşte yeni karşılaştığım bir tuzak. Tamsayıların bir listesini düşünün:

List<Integer> list = new ArrayList<Integer>();
list.add(5);
list.add(6);
list.add(7);
list.add(1);

Yürüttüğünüzde ne olacağına dair eğitimli bir tahmin var list.remove(1)mı? Ne olmuş list.remove(new Integer(1))? Bu bazı kötü hatalara neden olabilir.

Tamsayı listeleriyle uğraşırken, bir öğeyi remove(int index)verilen dizinden remove(Object o)kaldıran ve bir öğeyi başvuru ile kaldıran arasında ayrım yapmanın doğru yolu nedir ?


Burada dikkate alınması gereken ana nokta, @Nikita'nın bahsettiği şeydir - tam parametre eşleşmesi otomatik bokstan önceliklidir.


11
C: Burada asıl mesele Sun birisi nasılsa ilkel etrafında (değişmez) sarıcı sınıflar sahip düşünce akıllı ve daha sonra birinin üzerinde otomatik (me) boks sahip daha akıllı olduğunu düşündüm ... olduğunu VE İNSANLAR LAME DEFAULT API'leri KULLANARAK TUTUN DA DAHA İYİ VARSA . Birçok amaç için yeni Arraylist <Integer> ' den daha iyi bir çözüm var . Örneğin Trove, şeylere bir TIntArrayList sağlar . Java'da ne kadar çok program (2001'den beri SCJP), sarmalayıcı sınıfları o kadar az kullanıyorum ve daha iyi tasarlanmış API'ler (Trove, Google vb.) Aklıma geliyor.
SyntaxT3rr0r

Yanıtlar:


231

Java her zaman argümanınıza en uygun yöntemi çağırır. Otomatik boks ve örtük yükseltme yalnızca döküm / otomatik boks olmadan çağrılabilecek bir yöntem yoksa gerçekleştirilir.

Liste arabirimi iki kaldırma yöntemi belirtir (lütfen bağımsız değişkenlerin adlarına dikkat edin):

  • remove(Object o)
  • remove(int index)

Bu, list.remove(1)1 konumundaki nesneyi remove(new Integer(1))kaldırdığı ve belirtilen öğenin ilk oluşumunu bu listeden kaldırdığı anlamına gelir .


110
Bir nit seçmek: Integer.valueOf(1)daha iyi bir uygulamadır new Integer(1). Statik yöntem önbellekleme yapabilir ve böylece daha iyi performans elde edersiniz.
decitrig

Peter Lawrey'in teklifi daha iyidir ve gereksiz nesne yaratımlarından kaçınır.
assylias

@assylias: Peter Lawrey'in teklifi, decitrig'in önerisiyle aynı şeyi yapar, ancak daha az şeffaftır.
Mark Peters

@MarkPeters Yorumum hakkındaydı new Integer(1), ama buna katılıyorum Integer.valueOf(1)ya (Integer) 1da eşdeğerim.
assylias

68

Döküm kullanabilirsiniz

list.remove((int) n);

ve

list.remove((Integer) n);

N'nin bir int veya Integer olması önemli değildir, yöntem her zaman beklediğinizi çağırır.

Kullanma (Integer) nveya Integer.valueOf(n)daha verimlidir new Integer(n), daha sonra, her zaman, bir nesne oluşturmak oysa ilk iki, tamsayı önbellek kullanımı gibi.


2
durumun neden böyle olduğunu açıklayabilirseniz iyi olur :) [otomatik boks koşulları ...]
Yuval Adam

Döküm kullanarak, derleyicinin beklediğiniz türü görmesini sağlarsınız. İlk durumda '(int) n' yalnızca int türünde , ikinci durumda '(Integer) n' yalnızca Integer türünde olabilir . 'n' gerektiği gibi dönüştürülecek / kutlanacak / kutudan çıkarılacak veya yapamadığında bir derleyici hatası alacaksınız.
Peter Lawrey

10

'Doğru' yol hakkında bilmiyorum, ama önerdiğiniz yol gayet iyi çalışıyor:

list.remove(int_parameter);

verilen konumda elemanı kaldırır ve

list.remove(Integer_parameter);

verilen nesneyi listeden kaldırır.

Çünkü VM ilk başta tam olarak aynı parametre tipiyle beyan edilen yöntemi bulmaya çalışır ve ancak o zaman otomatik boks yapmaya çalışır.


7

list.remove(4)ile tam olarak eşleştiği list.remove(int index)için çağrılır. Eğer çağrı istiyorsanız list.remove(Object)aşağıdakileri yapın: list.remove((Integer)4).


Teşekkürler Petar, (Integer)yukarıda yazdığınız gibi basit bir oyuncu benim için en kolay yaklaşım gibi görünüyor.
vikingsteve

Son yaklaşımınızı kullanırken, bir boole döndürüyor gibi görünüyor. Birden fazla kaldırmayı yığınlamaya çalışırken, bir boolean üzerinde remove diyemediğim hatayı alıyorum.
Bram Vanroy

4

List.remove (1) komutunu çalıştırdığınızda ne olacağına dair eğitimli bir tahmin var mı? List.remove (yeni Tamsayı (1)) ne olacak?

Tahmin etmeye gerek yok. İlk durum List.remove(int)çağrılır ve konumdaki eleman 1kaldırılır. İkinci durum List.remove(Integer)çağrılır ve değeri eşit olan eleman Integer(1)kaldırılır. Her iki durumda da, Java derleyicisi en yakın eşleşen aşırı yükü seçer.

Evet, burada karışıklık (ve böcek) potansiyeli var, ancak oldukça nadir bir kullanım durumudur.

List.removeJava 1.2'de iki yöntem tanımlandığında, aşırı yüklemeler belirsiz değildi. Sorun yalnızca Java 1.5'te jeneriklerin ve otomatik boksun getirilmesiyle ortaya çıktı. Arka görüşte, kaldırma yöntemlerinden birine farklı bir isim verilmesi daha iyi olurdu. Ama şimdi çok geç.


2

VM, yaptığı doğru şeyi yapmasa bile remove(java.lang.Object), keyfi nesneler üzerinde çalışan gerçeği kullanarak doğru davranışı sağlayabileceğinizi unutmayın :

myList.remove(new Object() {
  @Override
  public boolean equals(Object other) {
    int k = ((Integer) other).intValue();
    return k == 1;
  }
}

Bu "çözüm" equalsyöntemin sözleşmesini , özellikle (Javadoc'tan) bozar "Simetriktir: boş olmayan tüm referans değerleri için x ve y, x.equals (y) yalnızca y.equals ( x) true değerini döndürür. " Bu nedenle, tüm uygulamalarda çalışacağı garanti edilmez List, çünkü List'in herhangi bir uygulamasının x ve x.equals(y)y'yi irade ile değiştirmesine izin verilir , çünkü Javadocu Object.equalsbunun geçerli olması gerektiğini söyler.
Erwin Bolwidt

1

Sadece #decitrig tarafından kabul edilen cevap ilk yorumunda önerildiği gibi takip ettim.

list.remove(Integer.valueOf(intereger_parameter));

Bu bana yardımcı oldu. Yorumunuz için tekrar teşekkür ederim. Bazılarına yardımcı olabilir.


0

İşte işte püf noktası.

Burada iki örnek verelim:

public class ArrayListExample {

public static void main(String[] args) {
    Collection<Integer> collection = new ArrayList<>();
    List<Integer> arrayList = new ArrayList<>();

    collection.add(1);
    collection.add(2);
    collection.add(3);
    collection.add(null);
    collection.add(4);
    collection.add(null);
    System.out.println("Collection" + collection);

    arrayList.add(1);
    arrayList.add(2);
    arrayList.add(3);
    arrayList.add(null);
    arrayList.add(4);
    arrayList.add(null);
    System.out.println("ArrayList" + arrayList);

    collection.remove(3);
    arrayList.remove(3);
    System.out.println("");
    System.out.println("After Removal of '3' :");
    System.out.println("Collection" + collection);
    System.out.println("ArrayList" + arrayList);

    collection.remove(null);
    arrayList.remove(null);
    System.out.println("");
    System.out.println("After Removal of 'null': ");
    System.out.println("Collection" + collection);
    System.out.println("ArrayList" + arrayList);

  }

}

Şimdi çıktıya bir göz atalım:

Collection[1, 2, 3, null, 4, null]
ArrayList[1, 2, 3, null, 4, null]

After Removal of '3' :
Collection[1, 2, null, 4, null]
ArrayList[1, 2, 3, 4, null]

After Removal of 'null': 
Collection[1, 2, 4, null]
ArrayList[1, 2, 3, 4]

Şimdi çıktıyı analiz edelim:

  1. Koleksiyondan 3 kaldırıldığında, parametre olarak remove()alan koleksiyon yöntemini çağırır Object o. Böylece nesneyi kaldırır 3. Ancak arrayList nesnesinde, dizin 3 tarafından geçersiz kılınır ve bu nedenle 4. öğe kaldırılır.

  2. Aynı nesne kaldırma mantığı ile ikinci çıktıda her iki durumda da null kaldırılır.

Bu nedenle 3, bir nesne olan sayıyı kaldırmak için açıkça 3'ü bir object.

Ve bu, sarıcı sınıfı kullanılarak döküm veya sarma ile yapılabilir Integer.

Örneğin:

Integer removeIndex = Integer.valueOf("3");
collection.remove(removeIndex);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.