반복하는 동안 HashSet에서 요소 제거
이 질문에는 이미 답변이 있습니다.
따라서 반복하는 동안 Java HashSet 에서 요소를 제거하려고 하면 ConcurrentModificationException이 발생 합니다. 다음 예제와 같이 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();
}
}
As people have pointed out, using a for loop is preferred because it keeps the iterator variable (i in this case) confined to a smaller scope.
The reason you get a ConcurrentModificationException is because an entry is removed via Set.remove() as opposed to Iterator.remove(). If an entry is removed via Set.remove() while an iteration is being done, you will get a ConcurrentModificationException. On the other hand, removal of entries via Iterator.remove() while iteration is supported in this case.
The new for loop is nice, but unfortunately it does not work in this case, because you can't use the Iterator reference.
If you need to remove an entry while iteration, you need to use the long form that uses the Iterator directly.
for (Iterator<Integer> it = set.iterator(); it.hasNext();) {
Integer element = it.next();
if (element % 2 == 0) {
it.remove();
}
}
you can also refactor your solution removing the first loop:
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 has a nice method called removeIf that makes things easier and safer. From the API docs:
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.
Interesting note:
The default implementation traverses all elements of the collection using its iterator().
Each matching element is removed using Iterator.remove().
Like timber said - "Java 8 Collection has a nice method called removeIf that makes things easier and safer"
Here is the code that solve your problem:
set.removeIf((Integer element) -> {
return (element % 2 == 0);
});
Now your set contains only odd values.
Does it need to be whilst iterating? If all you're doing is filtering or selecting I would suggest using Apache Commons CollectionUtils. There are some powerful tools there and it makes your code "cooler."
Here's an implementation that should provide what you need:
Set<Integer> myIntegerSet = new HashSet<Integer>();
// Integers loaded here
CollectionUtils.filter( myIntegerSet, new Predicate() {
public boolean evaluate(Object input) {
return (((Integer) input) % 2 == 0);
}});
If you find yourself using the same kind of predicate frequently you can pull that out into a static variable for reuse... name it something like EVEN_NUMBER_PREDICATE. Some may see that code and declare it "hard to read" but it looks cleaner when you pull out the Predicate into a static. Then it's easy to see that we're doing a CollectionUtils.filter(...) and that seems more readable (to me) than a bunch of loops all over creation.
An other possible solution:
for(Object it : set.toArray()) { /* Create a copy */
Integer element = (Integer)it;
if(element % 2 == 0)
set.remove(element);
}
Or:
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' 카테고리의 다른 글
| android에서 adjustResize와 adjustPan의 차이점은 무엇입니까? (0) | 2020.07.27 |
|---|---|
| 자바; (0) | 2020.07.27 |
| 해시의 값을 기준으로 해시 배열을 어떻게 정렬합니까? (0) | 2020.07.27 |
| null + true는 어떻게 문자열입니까? (0) | 2020.07.27 |
| 전체 화면을 채우시겠습니까? (0) | 2020.07.27 |