Лично я считаю набор функций, предоставляемых java.util.Iterator, довольно жалкими. Как минимум, мне бы хотелось иметь такие методы, как:
Хотя есть много других возможностей, таких как first () и last ().
Кто-нибудь знает, существует ли такой сторонний итератор? Вероятно, его нужно будет реализовать как декоратор java.util.Iterator, чтобы он мог работать с существующими коллекциями java. В идеале он должен быть «осведомленным о дженериках».
Заранее спасибо, Дон
Вы можете легко получить 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 отлично работал у меня. Мне любопытно, как вы используете итераторы, если считаете, что вам нужна эта дополнительная функциональность.
Я вижу. Это просто пахнет чем-то, что можно было бы сделать гораздо проще другим способом, например, посетителем или чем-то в этом роде.
Одна вещь, на которую я бы посмотрел, - это реализация Seq в clojure
Реализация базовых классов находится на Java, и доступен полный исходный код. Seqs являются декораторами на итераторах java (принимают и реализуют интерфейсы итераторов java), но они также предоставляют свой собственный интерфейс, который может быть больше того, что вы хотите - или, по крайней мере, отправной точкой.
Спасибо, но AFAIK общие коллекции Apache по-прежнему не были обобщены
обе эти ссылки теперь мертвы
исправил ссылки, спасибо. Apache теперь тоже поддерживает обобщения, а коллекции Google доступны как часть guava.
Поддерживает ли какой-либо итератор в Google Commons как peek()
, так и previous()
? PeekingIterator
поддерживает peek()
, но не previous()
.
Похоже, вам может быть лучше использовать стек.
Есть чертовски хорошая причина, по которой универсальные операторы не реализуют эти функции: они существуют не для всех контейнеров. Типичным примером является контейнер, представляющий ввод некоторых внешних данных, например файл, рассматриваемый как поток. Каждый раз, когда вы читаете значение, вы потреблять его и перемещаете указатель вперед, хотите вы этого или нет. Если вы наложите эти ограничения на универсальные итераторы, вы потеряете универсальность итераторов.
Если вам нужен метод previous
, как предлагается, используйте ListIterator<>
, который затем ограничивается контейнером, который ведет себя как списки.
Аргумент файла не совсем убедителен, нет причин, по которым мы не могли бы получить текущий символ (или то, что мы читаем) без перемещения курсора в файле. Однако я согласен с тем, что функция previous
не может быть предоставлена каждым итератором (особенно итераторами «генераторами», которые генерируют новое значение на каждом шаге).
@Luc: это потому, что вы видите файлы как произвольный доступ. И они действительно не должны быть такими. Если вы предпочитаете, рассмотрите поток, такой как сетевые сокеты. Вы читаете то, что получаете, и если вы хотите заглянуть вперед, вам понадобится целый механизм кэширования. Итак, если вы хотите, чтобы ваш итератор использовался во всех ситуациях, вам В самом деле нужен интерфейс, предоставляемый Java. После этого вы можете использовать адаптеры или более специализированные итераторы. Остается, что интерфейс, предоставляемый Java, является наиболее разумным для универсальных итераторов.
Это не вопрос произвольного доступа: даже в прямом потоке я не вижу причины, по которой доступ к только что прочитанному значению и чтение следующего следует рассматривать как одну операцию. Но я думаю, это довольно субъективно, и нам придется согласиться, чтобы не согласиться :). Однако я хотел бы добавить, что мне немного странно иметь метод remove
в интерфейсе, который должен быть очень общим, когда удаление - это операция, которая возможна только для довольно ограниченного набора повторяемых объектов.
Как предложил 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.
Думаю, самый частый случай - это какая-то рассылка. Вы хотите прочитать первый элемент, чтобы увидеть, кто должен его обрабатывать и отправлять - если получателю нужна вся последовательность, неплохо просто передать это и не передавать также удаленный объект.