AIによる要約
Listにはremove(int index)とremove(Object value)があります。List<Integer>にremove(1)と書くと、引数1はintなのでremove(int index)が選ばれ、値1ではなくインデックス1の要素が削除されます。値1を消すならremove(Integer.valueOf(1))、条件で複数件を消すならremoveIfを使います。値と添字を混同しないよう、変数名とテストデータでも意図を明示します。


注文IDや選択済みコードを`List<Integer>`で扱うと、`remove(1)`が「値1の削除」に見えます。しかしJavaは引数の型から`remove(int index)`を選ぶため、2番目の要素を削除します。
結果がたまたま期待どおりになるデータもあり、レビューや単体テストをすり抜けやすい点が問題です。オーバーロードの仕組みと、値削除を明示する書き方を押さえます。
この記事のポイント
- remove(1)の1はintなので添字として扱われる
- 値を消すならInteger.valueOfでObject側を選ぶ
- remove(Object)は最初に一致した1件だけを削除する
- 条件一致を全件消すならremoveIfを使う
- ループ中の削除方法と変更不可Listにも注意する
XのJavaクイズで結果を確認する
List<Integer> ids =
new ArrayList<>(List.of(1, 2, 3));
ids.remove(1);
System.out.println(ids);出力は`[1, 3]`です。インデックス1にある値2が削除されます。
List.removeには2つのオーバーロードがある
E remove(int index);
boolean remove(Object value);`remove(int index)`は指定位置の要素を削除し、削除した要素を返します。`remove(Object value)`は最初に一致した値を削除し、削除できたかをbooleanで返します。
`ids.remove(1)`の1はintリテラルなので、引数型がそのまま一致する`remove(int index)`が選ばれます。Listの要素型がIntegerでも、「IntegerのListだから値削除になる」とは判断されません。
値1を削除する正しい書き方
List<Integer> ids =
new ArrayList<>(List.of(1, 2, 3));
boolean removed = ids.remove(Integer.valueOf(1));
System.out.println(ids); // [2, 3]
System.out.println(removed); // true`Integer.valueOf(1)`でObjectとして渡すと`remove(Object)`が選ばれます。値が存在しなければListは変わらず、戻り値はfalseです。
Integer targetId = 1;
boolean removed = ids.remove(targetId);Integer型の変数を渡しても値削除になります。ただし途中で`int targetId`へ変更されると意味が変わるため、値削除であることを明確にしたい箇所では`Integer.valueOf`が安全です。
remove(Object)は最初の1件だけを削除する
List<Integer> ids =
new ArrayList<>(List.of(1, 2, 1, 3));
ids.remove(Integer.valueOf(1));
System.out.println(ids); // [2, 1, 3]同じ値が複数あっても、remove(Object)が消すのは最初に一致した1件です。値1をすべて削除するなら`removeIf`を使います。
ids.removeIf(id -> id.equals(1));nullを含む可能性があるListでは`id.equals(1)`がNullPointerExceptionになるため、`Objects.equals(id, 1)`を使えます。
ids.removeIf(id -> Objects.equals(id, 1));添字削除では範囲外にも注意する
List<Integer> ids = new ArrayList<>(List.of(10));
ids.remove(1); // IndexOutOfBoundsException値1がなくてもremove(Object)ならfalseですが、インデックス1がなければ`IndexOutOfBoundsException`です。空の一覧や1件だけの一覧で落ちるため、件数が多い正常データだけでは見つかりません。
拡張for文の中で直接removeしない
for (Integer id : ids) {
if (id < 0) {
ids.remove(id);
}
}走査中のListを直接変更すると`ConcurrentModificationException`になる可能性があります。条件削除ならremoveIfが最も分かりやすい書き方です。
ids.removeIf(id -> id < 0);削除しながら別処理も行う必要がある場合はIteratorの`remove`を使いますが、まず処理を分けられないか検討します。1つのループに検証、削除、集計を詰め込むとレビューしづらくなります。
変更不可Listではどちらのremoveも失敗する
List<Integer> ids = List.of(1, 2, 3);
ids.remove(Integer.valueOf(1));`List.of`の戻り値は変更不可なので、値削除を正しく指定しても`UnsupportedOperationException`です。削除が必要なら可変Listへコピーします。
List<Integer> mutableIds =
new ArrayList<>(List.of(1, 2, 3));
mutableIds.remove(Integer.valueOf(1));現場ではIDと位置を変数名で分ける
int selectedIndex = 1;
selectedIds.remove(selectedIndex);
Integer selectedId = 1;
selectedIds.remove(selectedId);`index`と`id`を名前に含めるだけでも意図が伝わります。画面の行番号とDBのIDを同じintで持つ実装では、削除対象を取り違えやすいため、FormやDTOでも役割を分けます。
境界値を含むテストを書く
@Test
void 値1だけを削除する() {
List<Integer> ids =
new ArrayList<>(List.of(1, 2, 3));
boolean removed =
ids.remove(Integer.valueOf(1));
assertTrue(removed);
assertEquals(List.of(2, 3), ids);
}
@Test
void 存在しない値ならfalseを返す() {
List<Integer> ids =
new ArrayList<>(List.of(1, 2, 3));
assertFalse(ids.remove(Integer.valueOf(9)));
assertEquals(List.of(1, 2, 3), ids);
}
@Test
void 範囲外の添字は例外になる() {
List<Integer> ids =
new ArrayList<>(List.of(1));
assertThrows(
IndexOutOfBoundsException.class,
() -> ids.remove(1));
}`[1, 2, 3]`だけでなく、1件、空、重複、対象なしを確認します。値1とインデックス1が同時に存在するデータを使うと、取り違えを検出しやすくなります。
現場レビューでよくある指摘
// レビューコメント例
List<Integer>のremove(1)はインデックス削除になります。
値1を削除する意図ならInteger.valueOf(1)を渡してください。
// レビューコメント例
同じIDが複数ある場合、remove(Object)は最初の1件だけです。
全件削除が要件ならremoveIfを使ってください。
// レビューコメント例
拡張for中に元Listを変更しているため、
removeIfかIteratorを使う形へ変更してください。提出前のセルフチェック
- 削除対象は値か添字か明確か
- 引数のコンパイル時型を確認したか
- 値削除ならInteger.valueOfを使ったか
- 最初の1件だけでよいか
- 全件削除ならremoveIfを検討したか
- 走査中に元Listを変更していないか
- List自体が変更可能か確認したか
- 空・1件・重複・対象なしをテストしたか
Javaのオーバーロードを整理する参考書
コレクションAPIだけでなく、プリミティブ型、ラッパー型、オーバーロードの選択規則を基礎から確認すると、似た取り違えを防げます。
スッキリわかるJava入門 第5版
Java文法とオブジェクト指向を、最初から整理する一冊。
豊富な図とサンプルで、変数、条件分岐、クラス、例外処理まで順番に学べます。Javaの最初の教科書を探している人向けです。
- Javaを基礎から体系的に学びたい
- Java 25 LTS対応の入門書を選びたい
当サイトはAmazonアソシエイト・プログラムの参加者です。価格・在庫・配送条件はAmazonでご確認ください。
この記事とあわせて読みたい
まとめ
List<Integer>のremove(1)は、int引数に一致するremove(int index)が選ばれるため、値1ではなくインデックス1の要素を削除します。
値を削除するならInteger.valueOf、条件一致を全件削除するならremoveIfを使います。値と添字が紛らわしいコードでは変数名と境界値テストで意図を固定し、変更不可Listやループ中の削除にも注意しましょう。
