Ответ 1
Отчасти это история: Iterator работает с нами с JDK 1.2, а Iterable - с JDK 1.5. Iterable пришел с расширенным циклом for
.
Плохой дизайн? Нет, эволюция. Там нет всезнающего создателя. По мере изучения уроков они включены в JDK.
Iterable<E>
находится в java.lang
, тогда как Iterator<E>
находится в java.util
. Есть ли веская причина для этого или это просто артефакт плохого дизайна?
Кажется странным, поскольку единственное, что подходит Iterable<E>
, - это предоставить Iterator<E>
.
РЕДАКТИРОВАТЬ. Одна из потенциальных причин - из-за недавно появившегося цикла for-each. Думаю, тогда мой вопрос был бы эквивалентен?
for(Object o : collection)
...
vs
for( Iterator iter = collection.iterator(); iter.hasNext(); ) {
o = iter.next();
...
Если они есть, то это все еще не объясняет, почему два класса находятся в разных пакетах, так как компилятор должен будет импортировать java.util
в любом случае, чтобы использовать конструкцию Iterator
.
Отчасти это история: Iterator работает с нами с JDK 1.2, а Iterable - с JDK 1.5. Iterable пришел с расширенным циклом for
.
Плохой дизайн? Нет, эволюция. Там нет всезнающего создателя. По мере изучения уроков они включены в JDK.
java.lang
зарезервирован для классов, которые являются зависимостями для языковых функций. Iterable
имеет поддержку уровня языка непосредственно через цикл for-each, но Iterator
нет.
Большинство коллекций реализуют Iterable
, чтобы вы могли использовать удобный для синтаксиса цикл:
Iterable<T> someIterableThing;
for (T x : someIterableThing) { ... }
Я бы предположил, что Iterable
находится в java.lang
, потому что он сильно связан с этим синтаксисом, особенностью языка Java.
С течением времени подпакеты Java java.*
разработали различные круговые зависимости. Например,
Поэтому я думаю, что лучше не думать о подпакетах как о механизме для явного зависимости уровней. Скорее, связанное с субпакетами специализированное поведение (за исключением catch-all util
) и lang
выборочно втягивает некоторые очень полезные конструкции, такие как Iterator
и Locale
.
Я думаю, можно было бы все это сделать до энтропии.
Чтобы ответить на дополнительный вопрос:
Усовершенствованный цикл for имеет два варианта. Один из них, когда аргумент collection
в
for(E o : collection) {
...
}
- это то, что реализует Iterable<E>
, в точности эквивалентно
for (Iterator<E> iter = collection.iterator(); iter.hasNext(); ) {
E o = iter.next();
...
}
(с той разницей, что Итератор не имеет имени переменной, доступ к которому вы можете получить в остальной части цикла). Компилятор будет генерировать совершенно одинаковый или даже точно такой же код для каждой версии.
Существует еще один вариант расширенного цикла for
: когда collection
является массивом, он будет скомпилирован примерно так:
E[] a = collection;
for(int i = 0; i < a.length; i++) {
E o = a[i];
...
}
(Конечно, здесь мы не можем напрямую обращаться к a
или i
).
Кстати, компилятор не импортирует java.util.Iterator
- в скомпилированный байт-код, каждый тип называется полным именем. (И локальные переменные на самом деле не типизированы, в любом случае - другие для некоторых утверждений checkcast
.)