Почему Iterable <E> и Iterator <E> в разных пакетах?

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.

Ответ 1

Отчасти это история: Iterator работает с нами с JDK 1.2, а Iterable - с JDK 1.5. Iterable пришел с расширенным циклом for.

Плохой дизайн? Нет, эволюция. Там нет всезнающего создателя. По мере изучения уроков они включены в JDK.

Ответ 2

java.lang зарезервирован для классов, которые являются зависимостями для языковых функций. Iterable имеет поддержку уровня языка непосредственно через цикл for-each, но Iterator нет.

Ответ 3

Большинство коллекций реализуют Iterable, чтобы вы могли использовать удобный для синтаксиса цикл:

Iterable<T> someIterableThing;
for (T x : someIterableThing) { ... }

Я бы предположил, что Iterable находится в java.lang, потому что он сильно связан с этим синтаксисом, особенностью языка Java.

Ответ 4

С течением времени подпакеты Java java.* разработали различные круговые зависимости. Например,

  • java.lang.Process - java.io
  • java.lang.Readable - java.io, java.nio
  • java.lang.String - java.util
  • java.lang.System - java.io, java.nio, java.util

Поэтому я думаю, что лучше не думать о подпакетах как о механизме для явного зависимости уровней. Скорее, связанное с субпакетами специализированное поведение (за исключением catch-all util) и lang выборочно втягивает некоторые очень полезные конструкции, такие как Iterator и Locale.

Я думаю, можно было бы все это сделать до энтропии.

Ответ 5

Чтобы ответить на дополнительный вопрос:

Усовершенствованный цикл 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.)