web-dev-qa-db-ja.com

List <Integer>から整数を適切に削除する

これは私が今遭遇した素敵な落とし穴です。整数のリストを考えます:

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

list.remove(1)を実行すると何が起こるかについての経験に基づいた推測はありますか? list.remove(new Integer(1))はどうですか?これはいくつかの厄介なバグを引き起こす可能性があります。

特定のインデックスから要素を削除する remove(int index)remove(Object o) 、整数のリストを処理するときに、参照によって要素を削除しますか?


ここで考慮すべき主なポイントは、1つ @ Nikitaが言及した です。正確なパラメーターのマッチングは、オートボクシングより優先されます。

193
Yuval Adam

Javaは常に、引数に最適なメソッドを呼び出します。自動ボックス化と暗黙的なアップキャストは、キャスト/自動ボックス化なしで呼び出すことができるメソッドがない場合にのみ実行されます。

Listインターフェースは2つのremoveメソッドを指定します(引数の命名に注意してください):

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

つまり、list.remove(1)は位置1のオブジェクトを削除し、remove(new Integer(1))はこのリストから指定された要素の最初の出現を削除します。

217
aka

キャストを使用できます

list.remove((int) n);

そして

list.remove((Integer) n);

NがintまたはIntegerの場合は問題ではありません。メソッドは常に期待するものを呼び出します。

(Integer) nまたはInteger.valueOf(n)を使用すると、最初の2つは整数キャッシュを使用できるため、new Integer(n)よりも効率的ですが、後者は常にオブジェクトを作成します。

68
Peter Lawrey

「適切な」方法については知りませんが、あなたが提案した方法はうまくいきます:

list.remove(int_parameter);

指定された位置の要素を削除し、

list.remove(Integer_parameter);

リストから指定されたオブジェクトを削除します。

これは、VMが最初にexactlyで宣言されたメソッドを同じパラメータータイプで見つけようとした後、オートボクシングを試みるためです。

10
Nikita Rybak

list.remove(4)list.remove(int index)と完全に一致するため、呼び出されます。 list.remove(Object)を呼び出す場合は、list.remove((Integer)4)を実行します。

7
Petar Minchev

List.remove(1)を実行すると何が起こるかについて、経験に基づいた推測はありますか? list.remove(new Integer(1))はどうですか?

推測する必要はありません。最初のケースでは、List.remove(int)が呼び出され、1の位置にある要素が削除されます。 2番目のケースでは、List.remove(Integer)が呼び出され、Integer(1)に等しい値を持つ要素が削除されます。どちらの場合も、Javaコンパイラーは、最も近い一致するオーバーロードを選択します。

はい、ここでは混乱(およびバグ)の可能性がありますが、それはかなり一般的なユースケースです。

2つのList.removeメソッドがJava 1.2で定義されたとき、オーバーロードはあいまいではありませんでした。この問題は、ジェネリックの導入とJava 1.5のオートボクシングでのみ発生しました。後から見ると、removeメソッドの1つに別の名前が付けられていた方がよかったでしょう。しかし、今では遅すぎます。

4
Stephen C

VMが正しいことをしなかった場合でも、remove(Java.lang.Object)が任意のオブジェクトで動作するという事実を使用することで、適切な動作を保証できることに注意してください。

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

単純に、受け入れられた回答の最初のコメントで#decitrigによって提案されているとおりにフォローしたかったのです。

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

これは私を助けました。コメントしてくれてありがとう#decitrig。いくつかの助けになるかもしれません。

1
Shylendra Madda

さて、ここにトリックがあります。

ここで2つの例を見てみましょう。

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);

  }

}

次に、出力を見てみましょう。

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]

次に、出力を分析しましょう。

  1. 3がコレクションから削除されると、Object oをパラメーターとして取るコレクションのremove()メソッドを呼び出します。したがって、オブジェクト3を削除します。ただし、arrayListオブジェクトでは、インデックス3によってオーバーライドされるため、4番目の要素は削除されます。

  2. オブジェクトの削除と同じロジックにより、2番目の出力の両方のケースでnullが削除されます。

したがって、オブジェクトである番号3を削除するには、objectとして3を明示的に渡す必要があります。

そして、それは、ラッパークラスIntegerを使用してキャストまたはラップすることで実行できます。

例えば:

Integer removeIndex = Integer.valueOf("3");
collection.remove(removeIndex);
0
Pritam Banerjee