을 피하기위한 몇 가지 대안으로 몇 가지 예를 드리겠습니다 ConcurrentModificationException
.
우리가 다음과 같은 책을 가지고 있다고 가정 해보십시오.
List<Book> books = new ArrayList<Book>();
books.add(new Book(new ISBN("0-201-63361-2")));
books.add(new Book(new ISBN("0-201-63361-3")));
books.add(new Book(new ISBN("0-201-63361-4")));
수집 및 제거
첫 번째 기술은 삭제하려는 모든 객체를 수집하는 것입니다 (예 : 향상된 for 루프 사용). 반복을 마치면 찾은 모든 객체를 제거합니다.
ISBN isbn = new ISBN("0-201-63361-2");
List<Book> found = new ArrayList<Book>();
for(Book book : books){
if(book.getIsbn().equals(isbn)){
found.add(book);
}
}
books.removeAll(found);
이것은 당신이하고 싶은 조작이 "삭제"라고 가정합니다.
이 방법을 "추가"하려는 경우에도 효과가 있지만 다른 컬렉션을 반복하여 두 번째 컬렉션에 추가 할 요소를 결정한 다음 addAll
마지막에 메소드 를 발행한다고 가정합니다 .
ListIterator 사용
리스트로 작업하는 경우 ListIterator
, 반복 기법 중에 항목을 제거하고 추가 할 수 있는 기능을 사용하는 다른 기술이 사용 됩니다.
ListIterator<Book> iter = books.listIterator();
while(iter.hasNext()){
if(iter.next().getIsbn().equals(isbn)){
iter.remove();
}
}
다시 한 번, 위 예제에서 "remove"메소드를 사용했는데, 이는 질문에 암시 된 것처럼 보이지만이 add
메소드를 사용하여 반복 중에 새 요소를 추가 할 수도 있습니다 .
JDK 사용> = 8
Java 8 이상 버전을 사용하는 사용자에게는이를 활용할 수있는 몇 가지 다른 기술이 있습니다.
기본 클래스 removeIf
에서 새 메소드를 사용할 수 있습니다 Collection
.
ISBN other = new ISBN("0-201-63361-2");
books.removeIf(b -> b.getIsbn().equals(other));
또는 새로운 스트림 API를 사용하십시오.
ISBN other = new ISBN("0-201-63361-2");
List<Book> filtered = books.stream()
.filter(b -> b.getIsbn().equals(other))
.collect(Collectors.toList());
이 마지막 경우, 콜렉션에서 요소를 필터링하려면 원래 참조를 필터링 된 콜렉션 ( books = filtered
)에 재 지정 하거나 필터링 된 콜렉션을 removeAll
원래 콜렉션 (즉 books.removeAll(filtered)
) 에서 찾은 요소에 사용하십시오 .
하위 목록 또는 하위 집합 사용
다른 대안도 있습니다. 목록이 정렬되어 있고 연속 요소를 제거하려는 경우 하위 목록을 작성하고 지울 수 있습니다.
books.subList(0,5).clear();
서브리스트는 원래리스트에 의해 지원되므로이 서브 요소 콜렉션을 제거하는 효율적인 방법입니다.
NavigableSet.subSet
방법을 사용하여 정렬 된 세트 또는 여기에 제공된 슬라이싱 방법을 사용하여 유사한 것을 얻을 수 있습니다 .
고려 사항 :
사용하려는 방법은 수행하려는 작업에 따라 다를 수 있습니다
- 수집 및
removeAl
기술은 모든 컬렉션 (컬렉션, 목록, 세트 등)과 함께 작동합니다.
ListIterator
기술은 분명히 그들의 주어진 것을 제공,리스트와 함께 작동 ListIterator
구현 이벤트 추가 및 제거 작업에 지원합니다.
- 이
Iterator
접근 방식은 모든 유형의 컬렉션에서 작동하지만 제거 작업 만 지원합니다.
ListIterator
/ Iterator
접근 방식을 사용하면 반복 할 때 제거하기 때문에 아무것도 복사 할 필요가 없습니다. 따라서 이것은 매우 효율적입니다.
- JDK 8 스트림 예제는 실제로 아무것도 제거하지 않았지만 원하는 요소를 찾은 다음 원래 컬렉션 참조를 새 것으로 교체하고 이전 컬렉션을 가비지 수집합니다. 따라서 컬렉션을 한 번만 반복하면 효율적입니다.
- 수집 및
removeAll
접근 방식의 단점은 두 번 반복해야한다는 것입니다. 먼저 제거 루프에서 제거 기준과 일치하는 객체를 찾기 위해 루프에서 반복하고, 일단 찾은 후에는 원래 컬렉션에서 객체를 제거하도록 요청합니다. 이는 다음 항목을 찾기 위해이 항목을 찾기위한 두 번째 반복 작업을 의미합니다. 제거하십시오.
Iterator
인터페이스 의 remove 메소드가 Javadocs에서 "선택적"으로 표시 된다는 것을 언급 할 가치가 있다고 생각합니다 . 이는 remove 메소드를 호출하면 Iterator
구현 이 발생할 수 있음을 의미합니다 UnsupportedOperationException
. 따라서 요소 제거를위한 반복자 지원을 보장 할 수없는 경우이 방법이 다른 방법보다 안전하지 않다고 말하고 싶습니다.