Что такое концепция Java-итератор? - PullRequest
4 голосов
/ 02 марта 2012

Я изучаю интерфейс java iterator и не могу понять, почему он так разработан.

Почему Java-итератор использует hasNext и next вместо того, чтобы объединить их в один метод?

это типичное использование java iterator

Iterator iter = //iterator from a list
while(iter.hasNext()){
    Object obj = iter.next();
    // do something to obj
}

почему бы и нет

Iterator iter = //iterator from a list
Object obj = null;
try {
    while(true){
        obj = iter.next();
        // do something to obj
    }
} catch (NoSuchElementException e) {}

Ясно, что этот подход выглядит некрасиво, но что произойдет, если next вернет ноль, когда достигается конец, вместо того, чтобы генерировать исключение? чем код можно упростить до

Iterator iter = //iterator from a list
Object obj = null;
while((obj = iter.next()) != null){
    // do something to obj
}

так работает NSEnumerator в Objective-C

NSEnumerator *enumerator = // from an array
while (id obj = [enumerator nextObject]) {
    // do something to obj
}

Это увеличивает накладные расходы на установку навесного оборудования iterator.

Это также делает итератор Java не поточно-ориентированным. Например, ArrayList содержит один элемент. Оба потока одновременно запрашивают один итератор для этого списка hasNext. Тогда оба потока увидят true и вызовут next на этом итераторе. Потому что есть только один элемент, и итератор был задан дважды, что определенно приведет к состоянию исключения или ошибки.

Я знаю, что существует поточно-ориентированный итератор, но я не уверен, что он реализован, но я думаю, что происходит много блокировок, которые делают его неэффективным.

Я думаю, что проблема в том, что проверка и обновление не происходят атомарно, и я не могу понять, почему Java iterator разработал такой интерфейс.


Обновление

Я вижу, что null может быть значением, поэтому мой подход неверен. Но можно ли обойти проблемы, о которых я говорил выше?

Ответы [ 3 ]

7 голосов
/ 02 марта 2012

Ваше предложение лишит возможности иметь null значений в коллекциях, поскольку оно использует null в качестве «отравленной таблетки» для определения конца итерации.

В очень очень редких случаях два потока совместно используют итератор, вам просто нужно обернуть его внутри некоторого пользовательского класса и синхронизировать доступ к итератору, чтобы сделать операцию check-then-act атомарной. Это необходимо в любом случае, поскольку, даже если у итератора был только один метод, резервная коллекция (в вашем примере ArrayList) не является поточно-ориентированной.

4 голосов
/ 02 марта 2012

Ваше первое предложение - плохой дизайн, потому что он основывается на создании и отлове исключения для условия, которое, как известно, в конечном итоге произойдет.Исключения довольно дороги и предназначены только для «исключительных» ситуаций, которые обычно не должны возникать.

Ваше второе предложение не учитывает, что Iterable s может иметь нулевые элементы.

Что касается бита безопасности потока, то да, стандартные Iterator имеют тенденцию не быть потокобезопасными, и потребуется специальная реализация с дополнительными издержками.Это верно для большинства структур Java.* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *.

2 голосов
/ 02 марта 2012

Для большей ясности исходного кода используйте (пример с набором строк)

Iterable<String> values = ... // typically a Collection (List, Set...)

for (String value : values) {
    // do something with the value
}

Я согласен с предыдущими ответами об ограниченных нулями коллекциях, циклическом управлении с исключениями (что является ужасной формой) и безопасности потоков.

Из ваших предложений нулевая привязка к коллекции является наименее неразумной, особенно если в вашем коде есть политика "нет нулей". Однако это очень однотипная Java (правка: и нарушает контракт интерфейса Iterator), поэтому она может сбить с толку будущих сопровождающих кода (правка: и, возможно, вызвать незначительные и / или неожиданные ошибки).

...