Улучшенная коллекция Iterator

Лично я считаю набор функций, предоставляемых java.util.Iterator, довольно жалкими. Как минимум, мне бы хотелось иметь такие методы, как:

  • peek () возвращает следующий элемент без перемещения итератора вперед
  • previous () возвращает предыдущий элемент

Хотя есть много других возможностей, таких как first () и last ().

Кто-нибудь знает, существует ли такой сторонний итератор? Вероятно, его нужно будет реализовать как декоратор java.util.Iterator, чтобы он мог работать с существующими коллекциями java. В идеале он должен быть «осведомленным о дженериках».

Заранее спасибо, Дон

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
12
0
8 185
11
Перейти к ответу Данный вопрос помечен как решенный

Ответы 11

Вы можете легко получить previous(), просто используя java.util.ListIterator.

Peek в этот момент легко реализовать, выполнив

public <T> T peek(ListIterator<T> iter) throws NoSuchElementException {
    T obj = iter.next();
    iter.previous();
    return obj;
}

К сожалению, будет проще использовать его в качестве вспомогательного метода, поскольку каждый класс коллекции реализует свои собственные итераторы. Создание оболочки для получения метода просмотра каждой коллекции на каком-либо интерфейсе, таком как MyListIterator, потребует довольно много работы.

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

Мне также не нравится, что итераторы Java не имеют возможности получить текущее значение, не перемещая его (и поэтому вы не можете легко написать код, который разветвляется на основе значения, просто передавая итератор - вы должны передать значение, которое вы теперь тоже есть).

Я никогда не сталкивался с проблемой, когда мне нужно было бы peek (); Iterator отлично работал у меня. Мне любопытно, как вы используете итераторы, если считаете, что вам нужна эта дополнительная функциональность.

Думаю, самый частый случай - это какая-то рассылка. Вы хотите прочитать первый элемент, чтобы увидеть, кто должен его обрабатывать и отправлять - если получателю нужна вся последовательность, неплохо просто передать это и не передавать также удаленный объект.

Lou Franco 10.10.2008 22:01

Я вижу. Это просто пахнет чем-то, что можно было бы сделать гораздо проще другим способом, например, посетителем или чем-то в этом роде.

Steve g 10.10.2008 22:05

Одна вещь, на которую я бы посмотрел, - это реализация Seq в clojure

http://clojure.org/sequences

Реализация базовых классов находится на Java, и доступен полный исходный код. Seqs являются декораторами на итераторах java (принимают и реализуют интерфейсы итераторов java), но они также предоставляют свой собственный интерфейс, который может быть больше того, что вы хотите - или, по крайней мере, отправной точкой.

Ответ принят как подходящий

Коллекции Apache Commons

Коллекции Google

Спасибо, но AFAIK общие коллекции Apache по-прежнему не были обобщены

Dónal 10.10.2008 22:45

обе эти ссылки теперь мертвы

Quince 09.03.2017 17:39

исправил ссылки, спасибо. Apache теперь тоже поддерживает обобщения, а коллекции Google доступны как часть guava.

ykaganovich 10.03.2017 21:32

Поддерживает ли какой-либо итератор в Google Commons как peek(), так и previous()? PeekingIterator поддерживает peek(), но не previous().

Phil 07.11.2018 20:54

Похоже, вам может быть лучше использовать стек.

Есть чертовски хорошая причина, по которой универсальные операторы не реализуют эти функции: они существуют не для всех контейнеров. Типичным примером является контейнер, представляющий ввод некоторых внешних данных, например файл, рассматриваемый как поток. Каждый раз, когда вы читаете значение, вы потреблять его и перемещаете указатель вперед, хотите вы этого или нет. Если вы наложите эти ограничения на универсальные итераторы, вы потеряете универсальность итераторов.

Если вам нужен метод previous, как предлагается, используйте ListIterator<>, который затем ограничивается контейнером, который ведет себя как списки.

Аргумент файла не совсем убедителен, нет причин, по которым мы не могли бы получить текущий символ (или то, что мы читаем) без перемещения курсора в файле. Однако я согласен с тем, что функция previous не может быть предоставлена ​​каждым итератором (особенно итераторами «генераторами», которые генерируют новое значение на каждом шаге).

Luc Touraille 30.06.2011 13:10

@Luc: это потому, что вы видите файлы как произвольный доступ. И они действительно не должны быть такими. Если вы предпочитаете, рассмотрите поток, такой как сетевые сокеты. Вы читаете то, что получаете, и если вы хотите заглянуть вперед, вам понадобится целый механизм кэширования. Итак, если вы хотите, чтобы ваш итератор использовался во всех ситуациях, вам В самом деле нужен интерфейс, предоставляемый Java. После этого вы можете использовать адаптеры или более специализированные итераторы. Остается, что интерфейс, предоставляемый Java, является наиболее разумным для универсальных итераторов.

PierreBdR 01.07.2011 00:30

Это не вопрос произвольного доступа: даже в прямом потоке я не вижу причины, по которой доступ к только что прочитанному значению и чтение следующего следует рассматривать как одну операцию. Но я думаю, это довольно субъективно, и нам придется согласиться, чтобы не согласиться :). Однако я хотел бы добавить, что мне немного странно иметь метод remove в интерфейсе, который должен быть очень общим, когда удаление - это операция, которая возможна только для довольно ограниченного набора повторяемых объектов.

Luc Touraille 01.07.2011 03:02

Как предложил ykaganovich, вы можете проверить материал Google-коллекции. Определенно есть поддержка некоторых вещей, которые вам нужны, например подглядывать. Кроме того, как отмечали некоторые другие, реализация всех этих вещей для всех коллекций может быть опасной с точки зрения возможности или производительности.

Коллекции Java были написаны для обеспечения минимального набора полезных функций. Это очень хороший подход для кода, который имеет должен быть реализован любым, кто реализует Java. Раздутие интерфейса с функциональностью, полезной для мощь, может привести к значительному увеличению объема кода с улучшениями, замеченными лишь некоторыми. Если peek () и previous () были частью стандартного итератора, это означает, что каждый, кто пишет новый тип Collection, должен реализует его, независимо от того, разумно это или нет.

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

public class Iterazor<T> {
  private Iterator<T> it;
  public T top;
  public Iterazor(Collection<T> co) {
    this.it = co.iterator(); 
    top = it.hasNext()? it.next(): null; 
  }
  public void advance() { 
    top = it.hasNext()? it.next(): null; 
  }
}

// usage

for(Iterazor<MyObject> iz = new Iterazor<MyObject>(MyCollection); 
    iz.top!=null; iz.advance())
  iz.top.doStuff();
}

Я видел, что кто-то связан с коллекциями Google, но никто не упомянул, что метод, который вы ищете, называется Iterators.peekingIterator ().

Тем не менее, было бы лучше, если бы вы могли просто использовать ListIterator.

Другие вопросы по теме