반복하는 동안 HashSet에서 요소 제거
따라서 반복 중에 Java HashSet에서 요소를 제거하려고 하면 Concurrent Modification이 나타납니다.예외입니다.다음 예시와 같이 HashSet에서 요소의 서브셋을 삭제하는 가장 좋은 방법은 무엇입니까?
Set<Integer> set = new HashSet<Integer>();
for(int i = 0; i < 10; i++)
set.add(i);
// Throws ConcurrentModificationException
for(Integer element : set)
if(element % 2 == 0)
set.remove(element);
여기 해결책이 있습니다만, 그다지 우아하다고는 생각하지 않습니다.
Set<Integer> set = new HashSet<Integer>();
Collection<Integer> removeCandidates = new LinkedList<Integer>();
for(int i = 0; i < 10; i++)
set.add(i);
for(Integer element : set)
if(element % 2 == 0)
removeCandidates.add(element);
set.removeAll(removeCandidates);
감사합니다!
세트의 요소에 대해 수동으로 반복할 수 있습니다.
Iterator<Integer> iterator = set.iterator();
while (iterator.hasNext()) {
Integer element = iterator.next();
if (element % 2 == 0) {
iterator.remove();
}
}
이 패턴은 자주 볼 수 있습니다.for
가 아닌 루프while
루프:
for (Iterator<Integer> i = set.iterator(); i.hasNext();) {
Integer element = i.next();
if (element % 2 == 0) {
i.remove();
}
}
사람들이 지적한 바와 같이,for
루프가 권장되는 이유는 반복 변수(i
이 경우)는 더 작은 범위로 제한됩니다.
취득하는 이유ConcurrentModificationException
엔트리가 Iterator.remove()가 아닌 Set.remove()를 통해 삭제되기 때문입니다.반복 중에 Set.remove()를 통해 엔트리가 삭제되면 Concurrent Modification이 나타납니다.예외.한편, 이 경우 반복 중에 Iterator.remove()를 통한 엔트리 삭제가 지원됩니다.
새로운 for 루프는 좋지만 안타깝게도 이 경우 반복 참조를 사용할 수 없기 때문에 작동하지 않습니다.
반복 중에 항목을 제거해야 하는 경우 반복기를 직접 사용하는 긴 형식을 사용해야 합니다.
for (Iterator<Integer> it = set.iterator(); it.hasNext();) {
Integer element = it.next();
if (element % 2 == 0) {
it.remove();
}
}
Java 8 Collection에는 removeIf라고 불리는 좋은 방법이 있어 더 쉽고 안전하게 만들 수 있습니다.API 문서에서:
default boolean removeIf(Predicate<? super E> filter)
Removes all of the elements of this collection that satisfy the given predicate.
Errors or runtime exceptions thrown during iteration or by the predicate
are relayed to the caller.
흥미로운 주의:
The default implementation traverses all elements of the collection using its iterator().
Each matching element is removed using Iterator.remove().
송신원: https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html#removeIf-java.util.function.Predicate-
첫 번째 루프를 제거하여 솔루션을 리팩터링할 수도 있습니다.
Set<Integer> set = new HashSet<Integer>();
Collection<Integer> removeCandidates = new LinkedList<Integer>(set);
for(Integer element : set)
if(element % 2 == 0)
removeCandidates.add(element);
set.removeAll(removeCandidates);
목재처럼 - "Java 8 Collection에는 remove If라는 멋진 방법이 있어 작업을 더 쉽고 안전하게 할 수 있습니다.
문제를 해결하는 코드는 다음과 같습니다.
set.removeIf((Integer element) -> {
return (element % 2 == 0);
});
이제 세트에 홀수 값만 포함됩니다.
다음은 보다 현대적인 스트림 접근법입니다.
myIntegerSet.stream().filter((it) -> it % 2 != 0).collect(Collectors.toSet())
다만, 이것은 새로운 세트가 되기 때문에, 매우 큰 세트라면 메모리 제약이 문제가 될 수 있습니다.
편집: 이 답변의 이전 버전은 Apache Collection Utils를 제안했지만, 이는 스팀 발생 전이었습니다.
다른 가능한 해결책:
for(Object it : set.toArray()) { /* Create a copy */
Integer element = (Integer)it;
if(element % 2 == 0)
set.remove(element);
}
또는 다음 중 하나를 선택합니다.
Integer[] copy = new Integer[set.size()];
set.toArray(copy);
for(Integer element : copy) {
if(element % 2 == 0)
set.remove(element);
}
언급URL : https://stackoverflow.com/questions/1110404/remove-elements-from-a-hashset-while-iterating
'programing' 카테고리의 다른 글
사용자 'root@localhost'에 대한 액세스가 거부되었습니다(암호 사용:아니요) (0) | 2022.09.25 |
---|---|
Python의 클래스 메서드 차이: bound, unbound 및 static (0) | 2022.09.25 |
Spring Java 설정에서 @Bean 주석이 달린 메서드를 호출합니다. (0) | 2022.09.25 |
마리아에서 보기에 색인을 추가할 수 있습니까?DB (0) | 2022.09.25 |
PHP에서 static 메서드와 nonstatic 메서드를 선언할 수 있습니까? (0) | 2022.09.25 |