List <Integer>에서 정수를 올바르게 제거


201

내가 방금 만난 좋은 함정이 있습니다. 정수 목록을 고려하십시오.

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)에서 요소를 제거하는 요소와 참조로 요소를 제거하는 을 구별하는 올바른 방법은 무엇입니까 ?


여기서 고려해야 할 요점은 @Nikita가 언급 한 것입니다 . 정확한 매개 변수 일치는 자동 복싱보다 우선합니다.


11
A : 여기 진짜 문제는 일에 그 사람이 어떻게 든 프리미티브의 주위에 (불변) 래퍼 클래스를 가지고 생각 똑똑하고 나중에 누군가가 자동 (유엔) 권투를 갖는 심지어 똑똑하다고 생각입니다 ... 사람들이 LAME의 DEFAULT API를 사용하여 유지하는 것이 더 나은 경우 . 많은 목적을 위해 new Arraylist <Integer> 보다 더 나은 솔루션이 있습니다. 예를 들어 Trove는 TIntArrayList를 제공합니다 . Java (2001 년 이후 SCJP)에서 프로그램을 많이할수록 래퍼 클래스를 적게 사용하고 잘 디자인 된 API (Trove, Google 등)를 더 많이 사용합니다.
SyntaxT3rr0r

답변:


230

Java는 항상 귀하의 주장에 가장 적합한 방법을 호출합니다. 자동 복싱 및 암시 적 업 캐스팅은 캐스팅 / 자동 복싱없이 호출 할 수있는 방법이없는 경우에만 수행됩니다.

List 인터페이스는 두 가지 remove 메소드를 지정합니다 (인수 이름 지정에 유의하십시오).

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

list.remove(1), 위치 1에서 오브젝트를 remove(new Integer(1))제거하고이 목록에서 지정된 요소가 처음 나타나는 것을 제거합니다.


110
nit 선택 : Integer.valueOf(1)보다 낫습니다 new Integer(1). 정적 메소드는 캐싱 등을 수행 할 수 있으므로 성능이 향상됩니다.
decitrig

Peter Lawrey의 제안은 더 좋으며 불필요한 객체 생성을 피합니다.
assylias

@assylias : Peter Lawrey의 제안은 decitrig의 제안과 정확히 같은 일을합니다.
Mark Peters

@MarkPeters 내 의견은 약이었다 new Integer(1),하지만 난 동의 Integer.valueOf(1)또는 (Integer) 1동일합니다.
assylias 2014 년

68

캐스팅을 사용할 수 있습니다

list.remove((int) n);

list.remove((Integer) n);

n이 int 또는 Integer인지 여부는 중요하지 않습니다. 메소드는 항상 예상 한 것을 호출합니다.

사용 (Integer) n또는 것이 Integer.valueOf(n)보다 효율적입니다 new Integer(n)나중에 항상 객체를 생성하는 반면 처음 두가, 정수 캐시를 사용할 수있다.


2
당신이 왜 그런지 설명 할 수 있다면 좋을 것입니다 :) [오토
유발 아담

캐스팅을 사용하면 컴파일러가 예상 한 유형을 볼 수 있습니다. 첫 번째 경우 '(int) n'은 int 유형일 수 있고 두 번째 경우 '(Integer) n'은 Integer 유형 만 될 수 있습니다 . 'n'은 필요에 따라 변환 / 박스 / 박스 해제되거나 컴파일러 오류가 발생하면 컴파일러 오류가 발생합니다.
Peter Lawrey

10

나는 '적절한'방법에 대해 모르지만 제안한 방식은 잘 작동합니다.

list.remove(int_parameter);

주어진 위치에서 요소를 제거하고

list.remove(Integer_parameter);

주어진 객체를 목록에서 제거합니다.

VM은 처음에 정확히 동일한 매개 변수 유형으로 선언 된 메서드를 찾은 다음 오토 박스를 시도하기 때문입니다.


7

list.remove(4)와 정확히 일치 list.remove(int index)하므로 호출됩니다. 전화를 걸 list.remove(Object)려면 다음을 수행하십시오 list.remove((Integer)4)..


감사합니다 Petar, (Integer)위에서 쓴 것처럼 간단한 캐스트가 가장 쉬운 방법 인 것 같습니다.
vikingsteve

마지막 접근 방식을 사용하면 부울을 반환하는 것 같습니다. 여러 제거를 스택하려고 할 때 부울에서 remove를 호출 할 수 없다는 오류가 발생합니다.
Bram Vanroy 2016

4

list.remove (1)을 실행할 때 어떤 일이 발생하는지에 대한 교육 된 추측이 있습니까? list.remove (new Integer (1))는 어떻습니까?

추측 할 필요가 없습니다. 첫 번째 경우가 List.remove(int)호출되고 위치의 요소 1가 제거됩니다. 두 번째 경우는 List.remove(Integer)호출되고 값이 같은 요소는 Integer(1)제거됩니다. 두 경우 모두 Java 컴파일러는 가장 일치하는 과부하를 선택합니다.

예, 여기에는 혼동 (및 버그)이있을 수 있지만 매우 드문 경우입니다.

List.remove메소드가 Java 1.2에서 정의 되었을 때, 과부하는 모호하지 않았습니다. 이 문제는 자바 1.5에서 제네릭과 오토 박싱 (autoboxing)을 도입했을 때만 발생했다. 후시로, 제거 방법 중 하나에 다른 이름을 부여하면 더 좋을 것입니다. 그러나 지금 너무 늦었습니다.


2

VM이 올바른 작업을 수행하지 않더라도 remove(java.lang.Object)임의의 개체에서 작동 하는 사실을 사용하여 올바른 동작을 보장 할 수 있습니다 .

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

이 "솔루션"은 equals특히 Javadoc에서 메소드 의 계약을 위반합니다. "null이 아닌 참조 값 x 및 y에 대해 x.equals (y)는 y.equals ( x)는 true를 반환합니다. ". 따라서 Javadoc 이 이것이 유효해야한다고 말했기 때문에 ListList의 구현은 x와 y를 자유롭게 교환 할 수 있기 때문에 모든 구현에서 작동하지 않을 수 있습니다. x.equals(y)Object.equals
Erwin Bolwidt

1

#decitrig에서 제안한대로 첫 번째로 허용되는 답변은 다음과 같습니다.

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

이것은 나를 도왔다. 귀하의 의견에 다시 #decitrig 감사합니다. 어떤 사람에게는 도움이 될 수 있습니다.


0

여기 트릭이 있습니다.

여기 두 가지 예를 들어 보자.

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을 제거하면 매개 변수로 사용 remove()되는 컬렉션 의 메서드를 호출합니다 Object o. 따라서 객체를 제거합니다 3. 그러나 arrayList 객체에서는 인덱스 3으로 재정의되므로 4 번째 요소가 제거됩니다.

  2. 동일한 객체 제거 논리에 의해 두 번째 출력에서 ​​두 경우 모두 널이 제거됩니다.

따라서 3객체 인 숫자를 제거하려면 명시 적으로 3을로 전달해야합니다 object.

래퍼 클래스를 사용하여 캐스팅하거나 래핑하여 수행 할 수 있습니다 Integer.

예 :

Integer removeIndex = Integer.valueOf("3");
collection.remove(removeIndex);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.