Podemos escrever o nosso iterator em Java?
Se eu tiver uma lista contendo {[[0]} e eu quiser escrever um iterador de modo que itere sobre elementos que começam com 'a', Posso escrever o meu próprio ? Como posso fazer isso ?
6 answers
java.util.Iterator
interface. Se você estiver usando um iterable objeto (digamos, um LinkedList
) a partir de java.util
, terá de subclasse-lo e substituir o seu iterator
a função para que você retornar a sua própria, ou fornecer um meio de moldagem de um padrão iterator em seu especial Iterator
exemplo (que tem a vantagem de ser mais amplamente utilizado), etc.
A melhor opção reutilizável é implementar a interface iterável e anular o método iterator().
Aqui está um exemplo de uma classe como ArrayList implementando a interface, na qual você sobrepõe o método 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;
}
}
Esta classe implementa a interface iterável usando genéricos . Considerando que você tem elementos para a matriz, você será capaz de obter uma instância de um iterador, que é a instância necessária usada pelo laço "foreach", para instancia.
Você pode simplesmente criar um anônimo instância do iterador sem criar estendendo Iterador e aproveitar o valor do currentSize para verificar até onde você pode navegar sobre a matriz (digamos que você criou uma matriz com a capacidade de 10, mas você tem apenas 2 elementos 0 e 1). A instância terá seu contador proprietário de onde ele está e tudo que você precisa fazer é brincar com o hasNext (), que verifica se o valor atual não é nulo, e o próximo (), que irá devolve a instância do teu index actual. Abaixo está um exemplo de usar esta 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
Se quiseres, também podes usar a instância 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
O foreach documentação está localizado em http://download.oracle.com/javase/1,5.0/docs/guide/language/foreach.html. Você pode dar uma olhada em uma implementação mais completa na minha prática pessoal google code.
Agora, para obter os efeitos do que você precisa, acho que você precisa plugar um conceito de filtro no iterador... Uma vez que o iterator depende dos próximos valores, seria difícil retornar verdadeiro no hasNext(), e então filtrar a próxima implementação() com um valor que não começa com um char "a", por exemplo. Eu acho que você precisa brincar com um Interador secundário baseado em uma lista filtrada com os valores com o filtro dado.Bom exemplo para calcular factorial
FactorialIterable fi = new FactorialIterable(10);
Iterator<Integer> iterator = fi.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
Código abreviado para Java 1.8
new FactorialIterable(5).forEach(System.out::println);
Classe iterável personalizada
public class FactorialIterable implements Iterable<Integer> {
private final FactorialIterator factorialIterator;
public FactorialIterable(Integer value) {
factorialIterator = new FactorialIterator(value);
}
@Override
public Iterator<Integer> iterator() {
return factorialIterator;
}
@Override
public void forEach(Consumer<? super Integer> action) {
Objects.requireNonNull(action);
Integer last = 0;
for (Integer t : this) {
last = t;
}
action.accept(last);
}
}
Iterator personalizado
public class FactorialIterator implements Iterator<Integer> {
private final Integer mNumber;
private Integer mPosition;
private Integer mFactorial;
public FactorialIterator(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;
}
}
Este é o código completo para escrever um iterador tal que itera sobre elementos que começam com 'a':
import java.util.Iterator;
public class AppDemo {
public static void main(String args[]) {
Bag<String> bag1 = new Bag<>();
bag1.add("alice");
bag1.add("bob");
bag1.add("abigail");
bag1.add("charlie");
for (Iterator<String> it1 = bag1.iterator(); it1.hasNext();) {
String s = it1.next();
if (s != null)
System.out.println(s);
}
}
}
Iterator personalizado
import java.util.ArrayList;
import java.util.Iterator;
public class Bag<T> {
private ArrayList<T> data;
public Bag() {
data = new ArrayList<>();
}
public void add(T e) {
data.add(e);
}
public Iterator<T> iterator() {
return new BagIterator();
}
public class BagIterator<T> implements Iterator<T> {
private int index;
private String str;
public BagIterator() {
index = 0;
}
@Override
public boolean hasNext() {
return index < data.size();
}
@Override
public T next() {
str = (String) data.get(index);
if (str.startsWith("a"))
return (T) data.get(index++);
index++;
return null;
}
}
}
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
class ListIterator implements Iterator<String>{
List<String> list;
int pos = 0;
public ListIterator(List<String> list) {
this.list = list;
}
@Override
public boolean hasNext() {
while(pos < list.size()){
if (list.get(pos).startsWith("a"))
return true;
pos++;
}
return false;
}
@Override
public String next() {
if (hasNext())
return list.get(pos++);
throw new NoSuchElementException();
}
}
public class IteratorTest {
public static void main(String[] args) {
List<String> list = Arrays.asList("alice", "bob", "abigail", "charlie");
ListIterator itr = new ListIterator(list);
while(itr.hasNext())
System.out.println(itr.next()); // prints alice, abigail
}
}
-
ListIterator
é o iterador para o array que devolve os elementos que começam com 'a'.
Não é necessário implementar uma interface iterável. Mas isso é uma possibilidade.
Não há necessidade de implementar isto genericamente.
- satisfaz plenamente o contrato para o hasNext() e o next(). ie se o hasNext() diz que ainda existem elementos, o next () irá devolver esses elementos. And if hasNext() diz que não há mais elementos, devolve uma excepção válida
NoSuchElementException
.