Java에서 for-each 루프는 컬렉션이나 배열의 순회 프로세스를 단순화하지만 모든 Java 프로그래머가 이 기사에서 설명할 for-each 루프의 일부 세부 사항을 아는 것은 아닙니다. Java 5에서 발표된 다른 용어(별명 릴리스 제네릭, 자동 캡슐화 및 가변 매개변수)와는 달리 Java 개발자는 다른 기능보다 for-each 루프를 더 자주 사용하지만 고급 for-each 루프가 어떻게 작동하는지 묻는 질문에 대해서는 for-each 루프에서 컬렉션을 사용할 때 요구 사항에 대해 모든 사람이 대답할 수 있는 것은 아닙니다.
이 튜토리얼과 예제는 for-each 루프에서 몇 가지 흥미로운 퍼즐을 탐구하여 그 격차를 메우는 것을 목표로 합니다. 좋습니다. 자세한 내용은 다루지 말고 Java5 for-each 루프의 첫 번째 문제를 살펴보겠습니다.
고급 루프 질문 1
사용자 정의 수집기 또는 컬렉션 클래스를 순회하는 다음 코드를 고려하세요. 이 코드는 예외를 발생시키든 컴파일러 오류를 발생시키든 무엇을 인쇄합니까?
다음과 같이 코드 코드를 복사합니다.
패키지 테스트;
/**
* Java에서 for-each 루프가 작동하는 방식을 보여주는 Java 클래스
*/
공개 클래스 ForEachTest {
공개 정적 무효 메인(문자열 인수[]){
CustomCollection<String> myCollection = new CustomCollection<String>();
myCollection.add("자바");
myCollection.add("스칼라");
myCollection.add("그루비");
//이 코드는 언어 인쇄, 예외 발생 또는 컴파일 타임 오류 등의 작업을 수행합니다.
for(문자열 언어: myCollection){
System.out.println(언어);
}
}
}
다음은 다른 Collection 클래스와 마찬가지로 ArrayList를 사용하고 Collection에서 항목을 추가 및 제거하는 메서드를 제공하는 일반 클래스인 CustomCollection 클래스입니다.
다음과 같이 코드 코드를 복사합니다.
패키지 테스트;
공개 클래스 CustomCollection<T>{
개인 ArrayList<T> 버킷;
공개 CustomCollection(){
버킷 = 새로운 ArrayList();
}
공개 정수 크기() {
bucket.size()를 반환합니다.
}
공개 부울 isEmpty() {
bucket.isEmpty()를 반환합니다.
}
공개 부울 포함(T o) {
return bucket.contains(o);
}
공개 부울 추가(T e) {
return bucket.add(e);
}
공개 부울 제거(T o) {
return bucket.remove(o);
}
}
답변:
CustomCollection 클래스가 java.lang.Iterable 인터페이스를 구현하지 않기 때문에 위 코드는 컴파일되지 않습니다. 컴파일 시간 오류는 다음과 같습니다.
다음과 같이 코드 코드를 복사합니다.
스레드 "main" java.lang.RuntimeException의 예외: 컴파일할 수 없는 소스 코드 - for-each는 표현식 유형에 적용할 수 없음
필수: 배열 또는 java.lang.Iterable
발견됨: test.CustomCollection
test.ForEachTest.main(ForEachTest.java:24)에서
여기서 배울 수 있는 흥미로운 사실은 for-each 루프가 Iterable 인터페이스를 구현하는 Java 배열 및 Collection 클래스에만 적용되며 모든 내장 Collection 클래스는 java.util.Collection 인터페이스를 구현하고 Iterable을 상속했기 때문에 이 루프는 종종 간과되는 세부 사항은 Collection 인터페이스 "공용 인터페이스 Collection은 Iterable을 확장합니다"의 유형 선언에서 볼 수 있습니다. 따라서 위의 문제를 해결하려면 단순히 CustomCollection이 Collection 인터페이스를 구현하도록 하거나 기본 범용 구현인 AbstractCollection을 상속하도록 선택할 수 있으며 이는 더 나은 유연성을 위해 추상 클래스와 인터페이스를 동시에 사용하는 방법을 보여줍니다. 이제 for-each 루프의 두 번째 퍼즐을 살펴보겠습니다.
Java for-each 루프의 두 번째 어려움:
다음 코드 예제에서는 ConcurrentModificationException을 발생시킵니다. 여기서는 표준 반복자와 for-each 루프를 사용하여 ArrayList를 반복한 다음 요소를 삭제합니다. ConcurrentModificationException을 발생시키는 코드 부분과 그 이유를 찾아야 합니다. 대답은 둘 다일 수도 있고 둘 다일 수도 있고 둘 중 하나일 수도 있습니다.
다음과 같이 코드 코드를 복사합니다.
패키지 테스트;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
* Java에서 for-each 루프의 내부 작업을 보여주는 Java 클래스
* @저자 Javin Paul
**/
공개 클래스 ForEachTest2 {
공개 정적 무효 메인(문자열 인수[]){
Collection<String> 목록 = new ArrayList<String>();
list.add("안드로이드");
list.add("아이폰");
list.add("윈도우 모바일");
// ConcurrentModificationException을 발생시키는 코드는 둘 다입니다.
// 없음 또는 둘 중 하나
// 예시 1
Iterator<String> itr = list.iterator();
동안(itr.hasNext()){
문자열 lang = itr.next();
list.remove(lang);
}
//예제 2
for(문자열 언어: 목록){
list.remove(언어);
}
}
}
Java 개발자의 약 70%는 요소를 삭제하기 위해 반복자의 제거 메소드를 사용하지 않고 ArrayList의 제거() 메소드를 사용하기 때문에 첫 번째 코드 블록에서 ConcurrentModificationException 예외가 발생한다고 말합니다. 그러나 여기에서는 반복자를 사용하지 않기 때문에 for-each 루프에서 동일한 문제가 발생한다고 말하는 Java 개발자는 많지 않습니다. 실제로 두 번째 코드 조각에서도 ConcurrentModificationException이 발생하는데, 이는 첫 번째 혼란을 해결한 후에 분명해집니다. for-each 루프는 내부적으로 Iterator를 사용하여 Collection을 순회하므로 (요소의) 변경 사항을 확인하고 ConcurrentModificationException을 발생시키는 Iterator.next()도 호출합니다. 첫 번째 스니펫을 주석 처리한 후 두 번째 스니펫을 실행하면 얻을 수 있는 아래 출력에서 이를 확인할 수 있습니다.
다음과 같이 코드 코드를 복사합니다.
스레드 "main"의 예외 java.util.ConcurrentModificationException
java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)에서
java.util.AbstractList$Itr.next(AbstractList.java:343)에서
test.ForEachTest2.main(ForEachTest2.java:34)에서
이것이 Java5 for-each 루프에 관한 전부입니다. 우리는 Java 프로그래머가 Collection 클래스를 반복하는 코드를 작성할 때, 특히 요소를 삭제하는 동시에 컬렉션을 반복할 때 겪는 많은 문제를 보아왔습니다. 컬렉션(예: 맵, 세트 또는 목록)에서 개체를 제거할 때 항상 Iterator의 제거 메서드를 사용하는 것을 기억하십시오. 표준 반복자 코드)만 해당됩니다.
번역자 주: 설탕 코팅 문법이라고도 번역되는 구문 설탕은 영국의 컴퓨터 과학자 Peter J. Landin이 발명한 용어로, 컴퓨터 언어에 추가된 특정 종류의 문법을 지칭합니다. 구문은 기능에 영향을 미치지 않습니다. 하지만 프로그래머가 사용하기 더 쉽게 만듭니다. 일반적으로, 구문 설탕을 사용하면 프로그램의 가독성이 높아져 프로그램 코드 오류 가능성이 줄어듭니다.