for 문과 while 문을 사용하여 Iterator를 앞으로 이동하는 것의 차이점
-
21-08-2019 - |
문제
객체의 반복자를 사용할 때 while 루프 (Java를 배우는 모든 책에 쓰여 있듯이, 자바로 생각하기 브루스 에켈의 글):
Iterator it=...
while(it.hasNext()){
//...
}
하지만 언젠가 누군가가 대신에 for 루프:
Iterator it=...
for (Iterator it=...; it.hasNext();){
//...
}
나는 이 선택을 이해하지 못합니다:
- 나는 for 루프 순서 순서(배열) 또는 단계에 대한 특수 규칙(일반적으로 단순 증분으로 선언됨)이 있는 컬렉션이 있는 경우
counter++
). - 나는 while 루프 루프가 끝나면 이 제약 조건은 없지만 종료를 위한 논리 조건만 있습니다.
다른 원인이 없는 스타일 코딩의 문제인가요, 아니면 제가 모르는 다른 로직(예: 성능)이 존재하는 건가요?
모든 피드백에 감사드립니다
해결책
for 루프의 올바른 구문은 다음과 같습니다.
for (Iterator it = ...; it.hasNext(); ){
//...
}
(코드의 이전 선언은 불필요하고 For Loop Heading의 추가 세미콜론입니다.)
이 구문을 사용하든 while
루프는 맛의 문제이며, 둘 다 정확히 동일하게 번역됩니다. For 루프의 일반적인 구문은 다음과 같습니다.
for (<init stmt>; <loop cond>; <iterate stmt>) { <body>; }
다음과 같습니다.
<init stmt>;
while (<loop cond>) { <body>; <iterate stmt>; }
편집하다: 실제로 위의 두 형태는 완전히 동등하지는 않습니다. 만약에 (질문에서와 같이) 변수는 init 문으로 선언됩니다. 이 경우 반복자 변수의 범위에 차이가 있습니다. FER 루프를 사용하면 스코프는 루프 자체로 제한되며, while 루프의 경우 스코프는 둘러싸는 블록의 끝까지 확장됩니다 (선언이 루프 외부에 있기 때문에 큰 놀라움은 없습니다).
또한 다른 사람들이 지적했듯이 새로운 버전의 Java에서는 For Loop에 대한 속기 표기법이 있습니다.
for (Iterator<Foo> it = myIterable.iterator(); it.hasNext(); ) {
Foo foo = it.next();
//...
}
다음과 같이 쓸 수 있습니다.
for (Foo foo : myIterable) {
//...
}
이 양식을 사용하면 물론 반복하는 동안 컬렉션에서 항목을 삭제하려는 경우 반복자에 대한 직접 참조를 잃어 버립니다.
다른 팁
그것은 단지 스타일 일이며 당신처럼 나는 색인으로 무언가를 사용할 때 for 루프를 선호합니다. Java 5를 사용하는 경우 물론 어쨌든 컬렉션을 통해 Foreach 루프를 사용해야합니다.
Collection<String> someCollection = someCollectionOfString();
for (String element : someCollection) {
....
}
선언하는 목적 Iterator
for 루프 내에서 변수의 범위를 최소화하십시오, 그것은 좋은 관행입니다.
당신이 선언 할 때 Iterator
루프 외에는 루프가 완료된 후에도 참조가 여전히 유효합니다. 시간의 99.99%, 당신은 계속 사용할 필요가 없습니다. Iterator
루프가 완료되면 이러한 스타일은 다음과 같은 버그로 이어질 수 있습니다.
//iterate over first collection
Iterator it1 = collection1.iterator();
while(it1.hasNext()) {
//blah blah
}
//iterate over second collection
Iterator it2 = collection2.iterator();
while(it1.hasNext()) {
//oops copy and paste error! it1 has no more elements at this point
}
첫 번째 방법 외에는이 두 가지 방법 사이에 큰 차이가 없습니다. it
루프 후. 두 번째 접근법은 루프 내부의 변수를 다시 고정하기 때문에 오류가 발생할 수 있습니다.
실제로 이것에는 세 번째 방법이 있습니다. 예를 들어 글을 쓰는 대신
for (Iterator<SomeObject> it = foo.iterator(); it.hasNext();) {
SomeObject so = foo.next();
}
당신은 가장 자주 쓸 수 있습니다
for (SomeObject so: foo) {...}
이 두 사람은 같은 것과 동일합니다 ...
사람들은 단순히 그것이 더 깔끔하다고 느끼기 때문에 명시적인('이전 스타일') for 루프를 사용할 수 있습니다. 아마도 아직 새로운 구문에 적응하지 않았을 수도 있습니다(개인적으로 훨씬 더 깔끔하다고 생각합니다).
더 긴 for 루프 구성의 실제적인 장점 중 하나는 반복자에 대한 참조가 있으므로 반복자에 대해 메서드를 호출할 수 있다는 것입니다. next()
.특히, hasNext()
종종 호출하는 것이 유용할 수 있습니다. 쉼표로 구분된 문자열 목록을 인쇄하고 싶다면 다음과 같이 상상해 보세요.
StringBuilder sb = new StringBuilder();
for (Iterator it=...; it.hasNext();){
sb.append(it.next());
if (it.hasNext())
sb.append(", ");
}
더 장황한 for 루프를 사용하는 경우 이와 같이 "이것이 마지막 것"인 경우를 구별하기 위한 것입니다.