Почему Iterable <E>и Iterator <E>находятся в разных пакетах? - PullRequest
10 голосов
/ 02 августа 2011

Iterable<E> в java.lang, тогда как Iterator<E> в java.util. Есть ли для этого веская причина или это просто артефакт плохого дизайна?

Это кажется странным, поскольку единственное, для чего подходит Iterable<E>, - это Iterator<E>.

РЕДАКТИРОВАТЬ : Одна потенциальная причина из-за (тогда-) недавно введенного для каждого цикла. Я думаю, тогда мой вопрос будет, они эквивалентны?

for(Object o : collection)
    ...
vs
for( Iterator iter = collection.iterator(); iter.hasNext(); ) {
    o = iter.next();
    ...

Если это так, то это по-прежнему не объясняет, почему два класса находятся в разных пакетах, поскольку компилятор должен был бы в любом случае импортировать java.util, чтобы использовать конструкцию Iterator.

Ответы [ 5 ]

9 голосов
/ 02 августа 2011

Часть истории: Iterator был с нами с JDK 1.2 , а Iterable поставлялся с JDK 1.5 . Iterable поставляется с улучшенной петлей for.

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

8 голосов
/ 02 августа 2011

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

5 голосов
/ 02 августа 2011

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

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

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

2 голосов
/ 02 августа 2011

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

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

2 голосов
/ 02 августа 2011

Со временем в подпакетах Java java.* появились различные циклические зависимости. Например,

  1. java.lang.Process - java.io
  2. java.lang.Readable - java.io, java.nio
  3. java.lang.String - java.util
  4. java.lang.System - java.io, java.nio, java.util

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

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

...