Если у меня есть список, содержащий [alice, bob, abigail, charlie]
, и я хочу написать итератор, чтобы он повторял элементы, начинающиеся с "a", могу ли я написать свой собственный? Как я могу это сделать?
Можем ли мы написать собственный итератор в Java?
Ответ 1
Конечно. Итератор - это просто реализация интерфейса java.util.Iterator
. Если вы используете существующий итерируемый объект (например, LinkedList
) из java.util
, вам нужно либо подклассировать его, либо переопределить его функцию iterator
, чтобы вы вернули свой собственный или предоставили средство для обертывания стандартный итератор в вашем специальном экземпляре iterator
(который имеет то преимущество, что его более широко используют) и т.д.
Ответ 2
Лучшим вариантом многократного использования является реализация интерфейса Iterable и переопределение метода iterator().
Вот пример класса ArrayList, реализующего интерфейс, в котором вы переопределяете метод Iterator().
import java.util.Iterator;
public class SOList<Type> implements Iterable<Type> {
private Type[] arrayList;
private int currentSize;
public SOList(Type[] newArray) {
this.arrayList = newArray;
this.currentSize = arrayList.length;
}
@Override
public Iterator<Type> iterator() {
Iterator<Type> it = new Iterator<Type>() {
private int currentIndex = 0;
@Override
public boolean hasNext() {
return currentIndex < currentSize && arrayList[currentIndex] != null;
}
@Override
public Type next() {
return arrayList[currentIndex++];
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
return it;
}
}
Этот класс реализует интерфейс Iterable, используя Generics. Учитывая, что у вас есть элементы массива, вы сможете получить экземпляр Iterator, который является необходимым экземпляром, используемым, например, циклом foreach.
Вы можете просто создать анонимный экземпляр итератора без создания расширения Iterator и воспользоваться значением currentSize, чтобы проверить, где вы можете перемещаться по массиву (предположим, вы создали массив емкостью 10, но вы имеют только 2 элемента в 0 и 1). У экземпляра будет свой счетчик владельца, где он есть, и все, что вам нужно сделать, это сыграть с hasNext(), который проверяет, не текущее значение не равно null, и next(), которое вернет экземпляр вашего currentIndex. Ниже приведен пример использования этого API...
public static void main(String[] args) {
// create an array of type Integer
Integer[] numbers = new Integer[]{1, 2, 3, 4, 5};
// create your list and hold the values.
SOList<Integer> stackOverflowList = new SOList<Integer>(numbers);
// Since our class SOList is an instance of Iterable, then we can use it on a foreach loop
for(Integer num : stackOverflowList) {
System.out.print(num);
}
// creating an array of Strings
String[] languages = new String[]{"C", "C++", "Java", "Python", "Scala"};
// create your list and hold the values using the same list implementation.
SOList<String> languagesList = new SOList<String>(languages);
System.out.println("");
// Since our class SOList is an instance of Iterable, then we can use it on a foreach loop
for(String lang : languagesList) {
System.out.println(lang);
}
}
// will print "12345
//C
//C++
//Java
//Python
//Scala
Если вы хотите, вы можете выполнить итерацию по нему, используя экземпляр Iterator:
// navigating the iterator
while (allNumbers.hasNext()) {
Integer value = allNumbers.next();
if (allNumbers.hasNext()) {
System.out.print(value + ", ");
} else {
System.out.print(value);
}
}
// will print 1, 2, 3, 4, 5
Документация foreach находится в http://download.oracle.com/javase/1,5.0/docs/guide/language/foreach.html. Вы можете взглянуть на более полную реализацию в моей личной практике код google.
Теперь, чтобы получить эффект от того, что вам нужно, я думаю, вам нужно подключить концепцию фильтра в Iterator... Поскольку итератор зависит от следующих значений, было бы трудно вернуть true на hasNext(), а затем отфильтруйте реализацию next() со значением, которое не начинается с char "a", например. Я думаю, вам нужно играть со вторичным Interator на основе отфильтрованного списка со значениями с данным фильтром.
Ответ 3
Вы можете реализовать свой собственный итератор. Ваш итератор может быть сконструирован для обертывания Iterator, возвращаемого List, или вы можете сохранить курсор и использовать метод List get (int index). Вам просто нужно добавить логику к следующему методу Iterator, а метод hasNext - учитывать ваши критерии фильтрации. Вам также придется решить, поддерживает ли ваш итератор операцию удаления.
Ответ 4
Хороший пример для Iterable для вычисления факториала
FactorialIterable fi = new FactorialIterable(10);
Iterator<Integer> iterator = fi.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
короткий код для Java 1.8
new FactorialIterable(5).forEach(System.out::println);
пользовательский класс Iterable
public class FactorialIterable implements Iterable<Integer> {
private final FactorialIteartor factorialIteartor;
public FactorialIterable(Integer value) {
factorialIteartor = new FactorialIteartor(value);
}
@Override
public Iterator<Integer> iterator() {
return factorialIteartor;
}
@Override
public void forEach(Consumer<? super Integer> action) {
Objects.requireNonNull(action);
Integer last = 0;
for (Integer t : this) {
last = t;
}
action.accept(last);
}
}
пользовательский класс Iterator
public class FactorialIteartor implements Iterator<Integer> {
private final Integer mNumber;
private Integer mPosition;
private Integer mFactorial;
public FactorialIteartor(Integer number) {
this.mNumber = number;
this.mPosition = 1;
this.mFactorial = 1;
}
@Override
public boolean hasNext() {
return mPosition <= mNumber;
}
@Override
public Integer next() {
if (!hasNext())
return 0;
mFactorial = mFactorial * mPosition;
mPosition++;
return mFactorial;
}
}