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));
}
반복하는 동안 컬렉션에서 안전하게 제거하려면 반복기를 사용해야 한다.
예를 들면 다음과 같다.
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 메서드에 의해 반환된 반복기는 오류 발생 속도가 빠름: 반복기가 생성된 후 언제라도 구조적으로 목록을 수정하는 경우, 반복자가 자체 제거 또는 추가 방법을 제외하고 어떤 방식으로든 반복기가 ConcurrentModify를 던진다.예외.따라서 동시 수정에 직면하여, 향후 결정되지 않은 시간에 임의적이고 비결정적인 행동을 위험하게 하기보다는, 반복자가 신속하고 깨끗하게 실패하게 된다.
아마도 많은 초보자들에게 불분명한 것은 목록을 반복해서 작성하면 반드시 접근할 수 없는 반복자가 암묵적으로 생성된다는 사실일 것이다.이 정보는 여기에서 찾을 수 있다.
당신은 그것을 하고 싶지 않을 것이다.수집에 따라 정의되지 않은 행동을 일으킬 수 있다.Iterator를 직접 사용하려는 경우.각 구성물에 대한 은 구문 당분이고 실제로 반복기를 사용하고 있지만, 암호로부터 그것을 숨겨서 당신은 전화를 걸 수 없다.
반복이 진행되는 동안 이 방법을 호출하는 것 외에 다른 방법으로 반복이 진행되는 동안 기본 수집을 수정하는 경우, 반복자의 동작은 지정되지 않는다.
대신 다음 코드를 입력하십시오.
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
.
for (String name : new ArrayList<String>(names)) {
// Do something
names.remove(nameToRemove);
}
목록을 복제하는 경우names
그리고 당신이 원본 목록에서 제거하는 동안 복제본을 통해 반복한다.정답보다 조금 더 깔끔하다.
"향상된 루프"의 자바 디자인은 반복기를 코드에 노출시키지 않는 것이었지만, 항목을 안전하게 제거하는 유일한 방법은 반복기에 접근하는 것이다.그러니 이 경우에는 구식대로 해야 한다.
for(Iterator<String> i = names.iterator(); i.hasNext();) {
String name = i.next();
//Do Something
i.remove();
}
실제 코드에서 강화된 루프가 정말로 가치가 있다면, 당신은 항목을 임시 수집에 추가하고 루프가 끝난 후 목록에서 removeAll을 호출할 수 있다.
편집(부록 다시 작성):아니, 반복하는 동안 reserator.remove() 방법 이외의 방법으로 목록을 변경하면 문제가 발생한다.이 문제를 해결하는 유일한 방법은 CopyOnWriteArrayList를 사용하는 것이지만, 이는 실제로 동시성 문제를 위한 것이다.
중복 항목을 제거하는 가장 저렴한 방법은 LinkedHashSet에 목록을 덤프한 다음 필요한 경우 다시 목록으로 덤프하는 것이다.이렇게 하면 중복 항목을 제거하는 동안 삽입 순서가 유지된다.
나는 반복기에 대해 몰랐지만, 오늘까지 루프 안의 목록에서 요소를 제거하기 위해 내가 하고 있는 일은 다음과 같다.
List<String> names = ....
for (i=names.size()-1;i>=0;i--) {
// Do something
names.remove(i);
}
이것은 항상 작동하며, 반복기를 지원하지 않는 다른 언어나 구조에서 사용될 수 있다.
예, 각 루프를 사용할 수 있습니다, 다음 작업관리에서는 항목을 삭제한 후 다음 이름을 사용하여 목록에서 해당 목록을 제거하십시오.removeAll()
방법
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
Iterator를 통해서만 수집에서 항목을 안전하게 제거할 수 없다는 것은 정확하지 않으며 ConcurrentHashMap과 같은 동시 수집 중 하나를 사용하여 안전하게 수행할 수 있다.
이게 코드냄새가 아닌지 확인해봐.논리를 뒤집고 '배타적'이 아닌 '포용적'이 될 수 있을까.
List<String> names = ....
List<String> reducedNames = ....
for (String name : names) {
// Do something
if (conditionToIncludeMet)
reducedNames.add(name);
}
return reducedNames;
나를 이 페이지로 이끈 상황은 목록으로부터 요소들을 제거하기 위해 우유부단함을 사용하여 목록을 반복하는 오래된 코드를 포함한다.나는 포어치 스타일을 사용하기 위해 리팩터링하고 싶었다.
사용자가 액세스할 수 있는 권한이 있는지 확인하기 위해 전체 요소 목록을 반복하고, 목록에서 권한이 없는 요소를 제거했다.
List<Service> services = ...
for (int i=0; i<services.size(); i++) {
if (!isServicePermitted(user, services.get(i)))
services.remove(i);
}
이 문제를 되돌리고 제거를 사용하지 않으려면:
List<Service> services = ...
List<Service> permittedServices = ...
for (Service service:services) {
if (isServicePermitted(user, service))
permittedServices.add(service);
}
return permittedServices;
언제 "제거"하는 것이 좋을까?한 가지 고려사항은 목록 크기에 비해 몇 개만 제거된 상태에서 큰 목록이나 값비싼 "추가"가 있는 경우다.많은 추가사항을 추가하는 것보다 몇 개만 제거하는 것이 더 효율적일 수 있다.그러나 나의 경우 그 상황은 그런 최적화를 받을 가치가 없었다.
- 이 2. 조건을 "WINTER"로 바꾸면 다음과 같은 의문이 들 것이다.
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");
}
}
목록에서 요소를 제거하려면 반복기를 사용하는 것이 좋다.
왜냐하면 제거의 소스 코드는
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null;
목록에서 요소를 제거하면 목록이 재구성되고, 다른 요소의 인덱스가 변경되며, 이로 인해 원하는 일이 발생할 수 있다.
사용하다
.remove() of Interator 또는
사용하다
CopyOnWriteArrayList
참조URL: https://stackoverflow.com/questions/1196586/calling-remove-in-foreach-loop-in-java
'Programing' 카테고리의 다른 글
VueJs - $ref에서 요소의 DOM 속성에 액세스하는 방법 (0) | 2022.04.25 |
---|---|
다중 문자 상수 경고 (0) | 2022.04.25 |
Mac에 Java 8을 설치하는 방법 (0) | 2022.04.25 |
MathicalException: "비단수 소수점 확장, 정확한 표현 가능한 소수점 결과 없음" (0) | 2022.04.25 |
어떤 구성 요소가 어떤 작업을 Vuex라고 부르는지 알 수 있는가? (0) | 2022.04.25 |