Java Language
Iterator och Iterable
Sök…
Introduktion
java.util.Iterator
är det vanliga Java SE-gränssnittet för objekt som implementerar Iterators designmönster. Gränssnittet java.lang.Iterable
är för objekt som kan ge en iterator.
Anmärkningar
Det är möjligt att iterera över en matris med hjälp av- for
slingan, även om java-matriser inte implementerar Iterable; iterering görs av JVM med hjälp av ett icke tillgängligt index i bakgrunden.
Använda Iterable in för loop
Klasser som implementerar Iterable<>
-gränssnitt kan användas for
slingor. Detta är faktiskt bara syntaktiskt socker för att få en iterator från objektet och använda det för att få alla element i följd; det gör koden tydligare, snabbare att skriva slut mindre felutsatt.
public class UsingIterable {
public static void main(String[] args) {
List<Integer> intList = Arrays.asList(1,2,3,4,5,6,7);
// List extends Collection, Collection extends Iterable
Iterable<Integer> iterable = intList;
// foreach-like loop
for (Integer i: iterable) {
System.out.println(i);
}
// pre java 5 way of iterating loops
for(Iterator<Integer> i = iterable.iterator(); i.hasNext(); ) {
Integer item = i.next();
System.out.println(item);
}
}
}
Använd den råa iteratorn
Även om det är enkelt att använda förhandslingan (eller "utökad för slinga") är det ibland fördelaktigt att använda iteratorn direkt. Om du till exempel vill skriva ut ett antal komma-separerade värden, men inte vill att det sista objektet ska ha kommat:
List<String> yourData = //...
Iterator<String> iterator = yourData.iterator();
while (iterator.hasNext()){
// next() "moves" the iterator to the next entry and returns it's value.
String entry = iterator.next();
System.out.print(entry);
if (iterator.hasNext()){
// If the iterator has another element after the current one:
System.out.print(",");
}
}
Detta är mycket lättare och tydligare än att ha en variabel isLastEntry
eller göra beräkningar med loopindex.
Skapa din egen Iterable.
För att skapa din egen Iterable som med alla gränssnitt implementerar du bara de abstrakta metoderna i gränssnittet. För Iterable
finns det bara en som kallas iterator()
. Men dess Iterator
är i sig ett gränssnitt med tre abstrakta metoder. Du kan returnera en iterator som är associerad med någon samling eller skapa en egen anpassad implementering:
public static class Alphabet implements Iterable<Character> {
@Override
public Iterator<Character> iterator() {
return new Iterator<Character>() {
char letter = 'a';
@Override
public boolean hasNext() {
return letter <= 'z';
}
@Override
public Character next() {
return letter++;
}
@Override
public void remove() {
throw new UnsupportedOperationException("Doesn't make sense to remove a letter");
}
};
}
}
Att använda:
public static void main(String[] args) {
for(char c : new Alphabet()) {
System.out.println("c = " + c);
}
}
Den nya Iterator
bör ha ett tillstånd som pekar på det första objektet, varje uppmaning till nästa uppdaterar sitt tillstånd för att peka till nästa. hasNext()
kontrollerar om iteratorn är i slutet. Om iteratorn var ansluten till en modifierbar samling kan iterators valfria remove()
-metod implementeras för att ta bort det objekt som för närvarande pekas på från den underliggande samlingen.
Ta bort element med en iterator
Iterator.remove()
är en valfri metod som tar bort elementet som returnerades av det föregående samtalet till Iterator.next()
. Till exempel innehåller följande kod en lista med strängar och tar bort alla tomma strängar.
List<String> names = new ArrayList<>();
names.add("name 1");
names.add("name 2");
names.add("");
names.add("name 3");
names.add("");
System.out.println("Old Size : " + names.size());
Iterator<String> it = names.iterator();
while (it.hasNext()) {
String el = it.next();
if (el.equals("")) {
it.remove();
}
}
System.out.println("New Size : " + names.size());
Utgång:
Old Size : 5
New Size : 3
Observera att koden ovan är det säkra sättet att ta bort element medan du upprepar en typisk samling. Om du istället försöker ta bort element från en samling som denna:
for (String el: names) {
if (el.equals("")) {
names.remove(el); // WRONG!
}
}
en typisk samling (som ArrayList
) som ger iteratorer med fail-snabb iteratorsemantik kommer att kasta en ConcurrentModificationException
.
Metoden remove()
kan bara ringas (en gång) efter ett next()
samtal next()
. Om det anropas innan du ringer next()
eller om det kallas två gånger efter ett next()
samtal next()
, kommer det att remove()
-samtalet att kasta en IllegalStateException
.
Ta remove
operationen beskrivs som en valfri operation; dvs inte alla iteratorer tillåter det. Exempel där det inte stöds inkluderar iteratorer för immutable samlingar, skrivskyddade vyer av samlingar eller samlingar i fast storlek. Om remove()
kallas när iteratorn inte stöder borttagning, kommer det att kasta en UnsupportedOperationException
.