왜 Java의 Iterator는 반복가능하지 않은가?
?는 왜?Iterator
extend " " " 。Iterable
iterator()
는 단순히 할 수 .this
.
자바 디자이너를 고의로 관리한 것인가, 아니면 그냥 간과한 것인가?
다음과 같이 반복기와 함께 각 루프를 사용할 수 있으면 편리합니다.
for(Object o : someContainer.listSomeObjects()) {
....
}
서 ''는listSomeObjects()
반복기를 반환합니다.
이치노 이 전화하면Iterable.iterator()
2배는 독립된 반복기를 얻을 수 있습니다.-어쨌든 대부분의 반복기는 마찬가지입니다.당신 시나리오에서는 분명히 그렇지 않을 거예요.
예를 들어, 보통 다음과 같이 쓸 수 있습니다.
public void iterateOver(Iterable<String> strings)
{
for (String x : strings)
{
System.out.println(x);
}
for (String x : strings)
{
System.out.println(x);
}
}
그러면 컬렉션이 두 번 인쇄됩니다.그러나 스킴에서는 두 번째 루프가 항상 즉시 종료됩니다.
반복기는 일반적으로 컬렉션의 단일 인스턴스를 가리키기 때문입니다.반복할 수 있는 것은 객체에서 반복자를 얻어 요소를 통과할 수 있다는 것을 의미합니다.또한 반복자가 나타내는1개의 인스턴스(instance)를 반복할 필요는 없습니다.
$0.02에 대해서는 Iterator가 Itable을 구현하지 않는 것에 전적으로 동의하지만 확장 for loop은 둘 다 수용해야 한다고 생각합니다.나는 "반복자를 반복 가능하게 한다"는 주장 전체가 언어의 결함에 대한 회피책으로 떠오른다고 생각한다.
향상된 for 루프가 도입된 이유는 "수집 및 어레이를 반복할 때 반복자 및 인덱스 변수의 번거로움과 오류 명료성을 없애기 때문"이었습니다 [1].
Collection<Item> items...
for (Iterator<Item> iter = items.iterator(); iter.hasNext(); ) {
Item item = iter.next();
...
}
for (Item item : items) {
...
}
그렇다면 왜 이 같은 주장이 반복자들에게 맞지 않는가?
Iterator<Iter> iter...
..
while (iter.hasNext()) {
Item item = iter.next();
...
}
for (Item item : iter) {
...
}
어느 경우든 hasNext()와 next()에 대한 콜은 삭제되어 내부 루프에 있는 반복기에 대한 참조는 없습니다.네, Iterables를 사용하여 여러 개의 반복기를 만들 수 있지만 모두 for loop 밖에서 발생합니다.루프 내부에는 반복기에서 반환된 항목보다 한 번에 한 항목씩 앞으로 진행됩니다.
또한 이를 허용하면 열거에 대한 for 루프를 쉽게 사용할 수 있습니다.이것은 다른 곳에서 지적된 바와 같이 반복자가 아닌 반복자와 유사합니다.
따라서 Iterator가 Iterable을 구현하도록 하지 말고 for 루프를 업데이트하여 둘 중 하나를 허용하십시오.
건배.
다른 사람들이 지적한 바와 같이 두 가지 다른 점이 있다.
ㅇㅇㅇㅇ.Iterator
구현은 루프에 대한 확장보다 앞서 있습니다.
스태틱 방식의 Import와 함께 사용하면 다음과 같은 간단한 어댑터 방식으로 이 제한을 극복하는 것도 간단합니다.
for (String line : in(lines)) {
System.out.println(line);
}
구현 예시:
/**
* Adapts an {@link Iterator} to an {@link Iterable} for use in enhanced for
* loops. If {@link Iterable#iterator()} is invoked more than once, an
* {@link IllegalStateException} is thrown.
*/
public static <T> Iterable<T> in(final Iterator<T> iterator) {
assert iterator != null;
class SingleUseIterable implements Iterable<T> {
private boolean used = false;
@Override
public Iterator<T> iterator() {
if (used) {
throw new IllegalStateException("SingleUseIterable already invoked");
}
used = true;
return iterator;
}
}
return new SingleUseIterable();
}
8을 하고 있습니다.Iterator
Iterable
★★★★★★★★★★★★★★★★★★:
for (String s : (Iterable<String>) () -> iterator) {
놀랍게도 아직 아무도 이 답을 주지 않았다. 반복할 수 .Iterator
새로운 Java 8 메서드를 사용하여 다음을 수행합니다.
Iterator<String> it = ...
it.forEachRemaining(System.out::println);
하여 포어치 루프를 Iterator
an Iterable
:::
for (String s : (Iterable<String>) () -> it)
System.out.println(s);
다른 사용자가 말했듯이, 반복 가능은 여러 번 호출할 수 있으며, 호출할 때마다 새로운 반복기를 반환할 수 있습니다. 반복기는 한 번만 사용됩니다.그래서 그들은 관련이 있지만 다른 목적을 가지고 있다.그러나 "compact for" 메서드는 반복 가능한 경우에만 작동합니다.
이하에 설명하겠습니다.양쪽의 장점을 최대한 활용할 수 있는 한 가지 방법입니다.기본적인 데이터 시퀀스가 일회성일 경우에도 반복 가능한 (더 나은 구문을 위해) 반환됩니다.
요령은 실제로 작업을 촉발하는 Itable의 익명 구현을 반환하는 것입니다.따라서 일회성 시퀀스를 생성하는 작업을 수행하고 그 위에 반복기를 반환하는 대신 반복기를 반환해야 합니다. 반복기는 액세스할 때마다 작업을 다시 수행합니다.낭비처럼 보일 수도 있지만, 어쨌든 Itable은 한 번만 호출하고 여러 번 호출해도 합리적인 의미론(Iterator를 Iterable처럼 보이게 하는 단순한 래퍼와는 달리 두 번 사용해도 실패하지 않습니다).
예를 들어 데이터베이스에서 일련의 개체를 제공하는 DAO가 있고 반복기를 통해 DAO에 액세스하려고 합니다(예: 필요하지 않은 경우 메모리에 모든 개체를 만들지 않기 위해).이제 반복기를 반환할 수 있지만 반환된 값을 루프에서 사용하는 것은 더 보기 흉합니다.대신 모든 걸 '이터블'로 싸서
class MetricDao {
...
/**
* @return All known metrics.
*/
public final Iterable<Metric> loadAll() {
return new Iterable<Metric>() {
@Override
public Iterator<Metric> iterator() {
return sessionFactory.getCurrentSession()
.createQuery("from Metric as metric")
.iterate();
}
};
}
}
이것은, 다음과 같은 코드로 사용할 수 있습니다.
class DaoUser {
private MetricDao dao;
for (Metric existing : dao.loadAll()) {
// do stuff here...
}
}
따라서 증분 메모리 사용을 유지하면서 콤팩트 for loop을 사용할 수 있습니다.
이 접근방식은 "게을러짐"입니다.작업은 Itable이 요구되었을 때 이루어지는 것이 아니라 내용이 반복될 때에만 이루어집니다.그리고 그 결과를 인식할 필요가 있습니다.DAO를 사용한 예제에서는 데이터베이스 트랜잭션 내에서 결과에 대해 반복을 의미합니다.
그래서 여러 가지 주의사항이 있지만, 이것은 많은 경우에 여전히 유용한 관용구가 될 수 있다.
Iterator
를 반복할 수 있는 인터페이스입니다.그것은 일종의 수집품을 통해 이동하는 실행이다.
Iterable
는 액세스 가능한 반복기가 포함되어 있음을 나타내는 기능 인터페이스입니다.
자바8에서는 이렇게 하면 생활이 꽤 편해지고...를 가지고 있는 경우Iterator
단, 필요한 것은Iterable
다음과 같이 할 수 있습니다.
Iterator<T> someIterator;
Iterable<T> = ()->someIterator;
이것은 for-loop에서도 동작합니다.
for (T item : ()->someIterator){
//doSomething with item
}
수용된 답변에는 동의하지만, 저만의 설명을 덧붙이고 싶습니다.
반복기는 통과 상태를 나타냅니다. 예를 들어 반복기에서 현재 요소를 가져와 다음으로 이동할 수 있습니다.
Itherable은 통과할 수 있는 컬렉션을 나타내며, 원하는 수만큼 반복기를 반환할 수 있습니다.각각의 반복기는 자신의 통과 상태를 나타내며, 한 반복기는 첫 번째 요소를 가리키고 다른 반복기는 세 번째 요소를 가리킬 수 있습니다.
Java for loop에서 Iterator와 Iterable을 모두 사용할 수 있으면 좋겠습니다.
의존을 피하기 위해java.util
패키지
원본 JSR에 따르면 Java™ Programming Language의 루프용으로 향상된 인터페이스, 즉 다음과 같습니다.
java.lang.Iterable
java.lang.ReadOnlyIterator
(장착해야 할 것)java.util.Iterator
하지만 이런 일은 없었던 것 같습니다.)
…사용할 수 있도록 설계되어 있습니다.java.lang
패키지 이름 공간 대신java.util
.
JSR 견적을 내려면:
이러한 새로운 인터페이스는 언어가 java.util에 의존하지 않을 경우 발생할 수 있는 문제를 방지하는 역할을 합니다.
그나저나 옛날은java.util.Iterable
는 Java 8+에서 람다 구문에서 사용하기 위한 새로운 메서드를 취득했습니다(passing ).
여기 예가 있습니다.인터페이스는, 임의의 리스트가 전송 되고 있는 것처럼, 인터페이스를 확장합니다.forEach
방법.
List
.of ( "dog" , "cat" , "bird" )
.forEach ( ( String animal ) -> System.out.println ( "animal = " + animal ) );
또, 다음과 같은 것도 많이 볼 수 있습니다.
public Iterator iterator() {
return this;
}
하지만 그게 옳은 건 아니야!이 방법은 당신이 원하는 방법이 아닙니다!
방법iterator()
처음부터 새 반복기를 돌려주기로 되어 있습니다.따라서 다음과 같은 작업을 수행해야 합니다.
public class IterableIterator implements Iterator, Iterable {
//Constructor
IterableIterator(SomeType initdata)
{
this.initdata = iter.initdata;
}
// methods of Iterable
public Iterator iterator() {
return new IterableIterator(this.intidata);
}
// methods of Iterator
public boolean hasNext() {
// ...
}
public Object next() {
// ...
}
public void remove() {
// ...
}
}
질문은: 이것을 수행하는 추상적인 수업을 만드는 방법은 없을까?따라서 ItableIterator를 얻으려면 next()와 hasNext()의 두 가지 메서드만 구현하면 됩니다.
회피책을 찾기 위해 여기에 온 경우 IteratorItable을 사용할 수 있습니다.(Java 1.6 이상에서 사용 가능)
사용 예(벡터 반전).
import java.util.Vector;
import org.apache.commons.collections4.iterators.IteratorIterable;
import org.apache.commons.collections4.iterators.ReverseListIterator;
public class Test {
public static void main(String ... args) {
Vector<String> vs = new Vector<String>();
vs.add("one");
vs.add("two");
for ( String s: vs ) {
System.out.println(s);
}
Iterable<String> is
= new IteratorIterable(new ReverseListIterator(vs));
for ( String s: is ) {
System.out.println(s);
}
}
}
인쇄하다
one
two
two
one
단순성을 위해 반복자와 반복자는 별개의 개념이며, 반복자는 반복자를 반환할 수 있다(I can can return a I erator)의 줄임말입니다.암호는 다음과 같아야 합니다.
for(Object o : someContainer) {
}
Container of con with with 。SomeContainer extends Iterable<Object>
여백으로서:Scala에는 반복기에 toItable() 메서드가 있습니다.암묵적 또는 명시적인 반복자에서 반복 가능으로의 변환 참조
이와 관련하여 Apache Commons Collections 4의 IteratorItable 어댑터가 유용할 수 있습니다.반복기에서 인스턴스를 생성하기만 하면 해당 반복이 가능합니다.
ID: org.apache.commons:commons-collections4:4.0
반복자는 스테이트풀하고, 「다음」요소가 있어, 반복하면 「기진」이 됩니다.문제의 위치를 확인하려면 다음 코드를 실행합니다. 몇 개의 번호가 인쇄되어 있습니까?
Iterator<Integer> iterator = Arrays.asList(1,2,3).iterator();
Iterable<Integer> myIterable = ()->iterator;
for(Integer i : myIterable) System.out.print(i);
System.out.println();
for(Integer i : myIterable) System.out.print(i);
다음의 예를 시험해 보겠습니다.
List ispresent=new ArrayList();
Iterator iterator=ispresent.iterator();
while(iterator.hasNext())
{
System.out.println(iterator.next());
}
언급URL : https://stackoverflow.com/questions/839178/why-is-javas-iterator-not-an-iterable
'programing' 카테고리의 다른 글
실행 시 하나의 Java 클래스가 다른 클래스를 확장하는지 테스트하려면 어떻게 해야 합니까? (0) | 2022.08.14 |
---|---|
onSnapshot에서 검출되지 않은 오류: 오류: signOut()에 대한 권한이 없거나 부족합니다. (0) | 2022.08.14 |
문자열에서 단일 문자를 제거하는 방법 (0) | 2022.08.14 |
최종 정의가 잘못되었나요? (0) | 2022.08.14 |
[Vue warn] :중복된 키가 검출되었습니다.x 。이로 인해 업데이트 오류가 발생할 수 있습니다. (0) | 2022.08.14 |