Java의 foreach 루프에서 제거 호출 [중복]
이 질문에 이미 답변이 있습니다.
Java에서 foreach 루프를 사용하여 컬렉션을 반복 할 때 컬렉션에 대해 remove를 호출하는 것이 합법적입니까? 예를 들면 :
List<String> names = ....
for (String name : names) {
// Do something
names.remove(name).
}
부록으로 아직 반복되지 않은 항목을 제거하는 것이 합법적입니까? 예를 들어
//Assume that the names list as duplicate entries
List<String> names = ....
for (String name : names) {
// Do something
while (names.remove(name));
}
반복하는 동안 컬렉션에서 안전하게 제거하려면 Iterator를 사용해야합니다.
예를 들면 :
List<String> names = ....
Iterator<String> i = names.iterator();
while (i.hasNext()) {
String s = i.next(); // must be called before you can call i.remove()
// Do something
i.remove();
}
로부터 자바 문서 :
이 클래스의 반복자 및 listIterator 메서드에 의해 반환되는 반복기는 실패하지 않습니다. 반복자가 생성 된 후 언제든지 목록이 구조적으로 수정되면 반복기의 자체 제거 또는 추가 메서드를 통하지 않는 한 반복자가 ConcurrentModificationException을 throw합니다. 따라서 동시 수정에 직면하여 반복자는 미래에 결정되지 않은 시간에 임의의 비 결정적 동작을 위험에 빠뜨리지 않고 빠르고 깔끔하게 실패합니다.
아마도 많은 초보자들에게 분명하지 않은 것은 for / foreach 구문을 사용하여 목록을 반복하면 필연적으로 액세스 할 수없는 반복자를 암시 적으로 생성한다는 사실입니다. 이 정보는 여기 에서 찾을 수 있습니다 .
당신은 그렇게하고 싶지 않습니다. 컬렉션에 따라 정의되지 않은 동작이 발생할 수 있습니다. 반복기를 직접 사용하려고합니다 . for each 구문은 구문 적 설탕이고 실제로 반복자를 사용하고 있지만 코드에서 숨겨서을 호출하기 위해 액세스 할 수 없습니다 Iterator.remove
.
이 메서드를 호출하는 것 이외의 방법으로 반복이 진행되는 동안 기본 컬렉션이 수정되면 반복기의 동작이 지정되지 않습니다.
대신 코드를 작성하십시오.
List<String> names = ....
Iterator<String> it = names.iterator();
while (it.hasNext()) {
String name = it.next();
// Do something
it.remove();
}
코드를 호출합니다 Iterator.remove
, 없습니다 List.remove
.
추가:
아직 반복되지 않은 요소를 제거하더라도 컬렉션을 수정 한 다음 Iterator
. 놀라운 방식으로 컬렉션을 수정할 수 있으며 Iterator
.
The java design of the "enhanced for loop" was to not expose the iterator to code, but the only way to safely remove an item is to access the iterator. So in this case you have to do it old school:
for(Iterator<String> i = names.iterator(); i.hasNext();) {
String name = i.next();
//Do Something
i.remove();
}
If in the real code the enhanced for loop is really worth it, then you could add the items to a temporary collection and call removeAll on the list after the loop.
EDIT (re addendum): No, changing the list in any way outside the iterator.remove() method while iterating will cause problems. The only way around this is to use a CopyOnWriteArrayList, but that is really intended for concurrency issues.
The cheapest (in terms of lines of code) way to remove duplicates is to dump the list into a LinkedHashSet (and then back into a List if you need). This preserves insertion order while removing duplicates.
for (String name : new ArrayList<String>(names)) {
// Do something
names.remove(nameToRemove);
}
You clone the list names
and iterate through the clone while you remove from the original list. A bit cleaner than the top answer.
I didn't know about iterators, however here's what I was doing until today to remove elements from a list inside a loop:
List<String> names = ....
for (i=names.size()-1;i>=0;i--) {
// Do something
names.remove(i);
}
This is always working, and could be used in other languages or structs not supporting iterators.
Yes you can use the for-each loop, To do that you have to maintain a separate list to hold removing items and then remove that list from names list using removeAll()
method,
List<String> names = ....
// introduce a separate list to hold removing items
List<String> toRemove= new ArrayList<String>();
for (String name : names) {
// Do something: perform conditional checks
toRemove.add(name);
}
names.removeAll(toRemove);
// now names list holds expected values
Those saying that you can't safely remove an item from a collection except through the Iterator aren't quite correct, you can do it safely using one of the concurrent collections such as ConcurrentHashMap.
Make sure this is not code smell. Is it possible to reverse the logic and be 'inclusive' rather than 'exclusive'?
List<String> names = ....
List<String> reducedNames = ....
for (String name : names) {
// Do something
if (conditionToIncludeMet)
reducedNames.add(name);
}
return reducedNames;
The situation that led me to this page involved old code that looped through a List using indecies to remove elements from the List. I wanted to refactor it to use the foreach style.
It looped through an entire list of elements to verify which ones the user had permission to access, and removed the ones that didn't have permission from the list.
List<Service> services = ...
for (int i=0; i<services.size(); i++) {
if (!isServicePermitted(user, services.get(i)))
services.remove(i);
}
To reverse this and not use the remove:
List<Service> services = ...
List<Service> permittedServices = ...
for (Service service:services) {
if (isServicePermitted(user, service))
permittedServices.add(service);
}
return permittedServices;
When would "remove" be preferred? One consideration is if gien a large list or expensive "add", combined with only a few removed compared to the list size. It might be more efficient to only do a few removes rather than a great many adds. But in my case the situation did not merit such an optimization.
- Try this 2. and change the condition to "WINTER" and you will wonder:
public static void main(String[] args) {
Season.add("Frühling");
Season.add("Sommer");
Season.add("Herbst");
Season.add("WINTER");
for (String s : Season) {
if(!s.equals("Sommer")) {
System.out.println(s);
continue;
}
Season.remove("Frühling");
}
}
It's better to use an Iterator when you want to remove element from a list
because the source code of remove is
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null;
so ,if you remove an element from the list, the list will be restructure ,the other element's index will be changed, this can result something that you want to happened.
Use
.remove() of Interator or
Use
CopyOnWriteArrayList
참고URL : https://stackoverflow.com/questions/1196586/calling-remove-in-foreach-loop-in-java
'Program Tip' 카테고리의 다른 글
Python에서 현재 사용자 이름을 가져 오는 이식 가능한 방법이 있습니까? (0) | 2020.10.03 |
---|---|
Bash의 'if'문에서 두 문자열 변수를 어떻게 비교합니까? (0) | 2020.10.03 |
주어진 인덱스에서 요소별로 목록 / 튜플을 정렬 (목록 / 튜플)하는 방법은 무엇입니까? (0) | 2020.10.03 |
왜 this ()와 super ()가 생성자의 첫 번째 문장이어야합니까? (0) | 2020.10.03 |
Java에서 getPath (), getAbsolutePath () 및 getCanonicalPath ()의 차이점은 무엇입니까? (0) | 2020.10.03 |