Różnica między wyliczaniem w języku Java a iteratorem


Odpowiedzi:


142

Patrząc na specyfikację interfejsu API języka Java dla Iteratorinterfejsu, wyjaśniono różnice między Enumeration:

Iteratory różnią się od wyliczeń na dwa sposoby:

  • Iteratory umożliwiają wywołującemu usuwanie elementów z podstawowej kolekcji podczas iteracji z dobrze zdefiniowaną semantyką.
  • Nazwy metod zostały poprawione.

Najważniejsze jest to, że oba Enumerationi Iteratorbędą dawać kolejne elementy, ale Iteratorjest ulepszony w taki sposób, że nazwy metod są krótsze i ma dodatkową removemetodę. Oto porównanie side-by-side:

  Enumeration                     Iterator
  ----------------                ----------------
  hasMoreElement()                hasNext()
  nextElement()                   next()
  N/A                             remove()

Jak wspomniano również w specyfikacji interfejsu API języka Java, w przypadku nowszych programów Iteratorpowinno być preferowane Enumeration, ponieważ „Iterator zastępuje wyliczanie w strukturze kolekcji Java”. (Ze Iteratorspecyfikacji.)


9
Myślę, że w tej odpowiedzi brakuje trochę wyjaśnienia dotyczącego współbieżności.
Maarten Bodewes

@Paul_Draper: Edycje nie powinny nadawać nowego znaczenia postowi, do tego służą komentarze.
Emil

2
@coobird Czy na pewno „Wyliczenia są zazwyczaj szybsze”? ponieważ Enumeration ma "synchronizujący blok kodu wewnątrz nextElement ()" I nie mamy synchronizacji na Iteratorach, co powoduje rit ConcurrentModificationException ?? Czy nazywamy to Iteratory są zwykle szybsze, a wyliczenia są trochę bezpieczniejsze. ??
Kanagavelu Sugumar

@KanagaveluSugumar Dziękuję za zwrócenie na to uwagi. (Nie zauważyłem, że dodatkowa dyskusja została dodana do tej odpowiedzi). Wycofałem edycję, ponieważ nie była ona całkowicie dokładna.
coobird

Myślę, że warto zwrócić uwagę, że remove () jest opcjonalną metodą w interfejsie Iteratora i sporo klas implementujących jej nie implementuje.
Kutzi,

35

Iteratory działają szybko . tj. gdy jeden wątek zmienia kolekcję przez operacje dodawania / usuwania, podczas gdy inny wątek przechodzi przez nią przez Iterator przy użyciu hasNext() or next()metody, iterator szybko kończy się niepowodzeniem przez wyrzucanie ConcurrentModificationException. Bezawaryjne zachowanie iteratorów może być używane tylko do wykrywania błędów. Wyliczenia zwracane przez metody klas, takich jak Hashtable, Vector nie są szybkie, co jest osiągane przez synchronizację bloku kodu wewnątrz nextElement()metody, która blokuje bieżący obiekt Vector, co kosztuje dużo czasu.


5
Tylko częściowo prawda: to zachowanie nie jest zdefiniowane w interfejsie, zależy od implementacji Iteratora. To prawda, że ​​„stare” implementacje kolekcji w java.util (HashSet, ArrayList itp.) Wykazują takie zachowanie. Jednak nowsze kolekcje „współbieżne” nigdy nie będą zgłaszać wyjątku ConcurrentModificationException, będą przechodzić przez kolekcję w momencie tworzenia iteratora. Inne implementacje mogą nadal wykazywać inne zachowanie.
Kutzi

1
Warto również zwrócić uwagę: „Należy pamiętać, że nie można zagwarantować zachowania bezawaryjnego, ponieważ, ogólnie rzecz biorąc, niemożliwe jest zapewnienie jakichkolwiek twardych gwarancji w obecności niezsynchronizowanej, współbieżnej modyfikacji. Operacje wymagające szybkiego niepowodzenia rzucają wyjątek ConcurrentModificationException na zasadzie najlepszych wysiłków. błędem byłoby napisanie programu, który zależałby od tego wyjątku ze względu na jego poprawność: wyjątek ConcurrentModificationException powinien być używany tylko do wykrywania błędów. " docs.oracle.com/javase/7/docs/api/java/util/…
Kutzi,

11

"Oficjalnie" mają być podobne z interfejsem iteratora obsługującym dodatkowe operacje (np. Usuwanie). Ogólnie rzecz biorąc, istnieje tendencja do używania iteratorów.

Oto z interfejsu wyliczania javadocs :

UWAGA: Funkcjonalność tego interfejsu jest dublowana przez interfejs Iteratora. Ponadto Iterator dodaje opcjonalną operację usuwania i ma krótsze nazwy metod. Nowe implementacje powinny rozważyć użycie Iteratora zamiast wyliczenia.


6

Jednym prostym faktem, o którym nie wspomniano w poprzednich odpowiedziach, jest to, że Iterator<T>służy Iterable<T>do interpretacji for(_type_ element:collection){...}struktury.


5

Istnieją trzy podstawowe różnice w wyliczaniu i iteratorze

Wyliczenie
1. jest używane tylko dla klasy lagacy (np. Vector)

    Enumeration e = v.elements();  
    v is the object of `Vector` class

2. Można wykonać operację odczytu, nie możemy usunąć elementu.
3. Dostępne są dwie metody

  • public boolean hasNextElement ();
  • public Object nextElement ();

Iterator

  1. ma zastosowanie do wszystkich kolekcji

    Iterator itr = c.iterator();  
    where c is any `Collection` class
  2. Można wykonać operację odczytu i usuwania

  3. Dostępne są trzy metody

    • public boolean hasNext ();
    • public Object next ();
    • public void remove ();

Ograniczenie w obu

  • Poruszaj się tylko do przodu
  • Nie ma żadnych metod na Add objectiReplace object

2

Jeśli piszesz własną klasę kolekcji i rozszerzasz dowolną z istniejących klas lub implementujesz dowolny z interfejsów struktury kolekcji, w zasadzie nie masz innego wyboru, jak tylko użyć Iteratora.

Jeśli z jakiegoś powodu (o którym nie mam pojęcia) tworzysz niestandardową klasę kolekcji, która w żaden sposób nie jest związana z java.util.Collection ani java.util.Map, nadal powinieneś zaimplementować Iterable, aby ludzie mogli używać Twoja klasa w pętli for.


2

Główną różnicą jest to, że wyliczenie nie ujawnia metody remove (). Co więcej, Iterator nie pozwala na jednoczesną nawigację i modyfikację bazowego obiektu. Mają kontrolę, aby sprawdzić, czy istnieją równoległe modyfikacje, a zatem wymagają więcej przetwarzania. Więc wydajność Enumeration jest praktycznie o 50% szybsza niż Iterator. Jeśli potrzebujemy tylko nawigacji ignorującej taką synchronizację, po prostu użyj Enumeration.


Prawdą jest, że Enumeration „nie” ujawnia metody remove () - ale nie zwraca również uwagi na wywołanie funkcji API Remove () z kolekcji Collection. Na przykład następujący kod po prostu wypisze: AAA, CCC, EEE. -------------------------------------------------- --- Vector <String> v = new Vector <String> (6); v.add („AAA”); v.add („BBB”); v.add („CCC”); v.add ("DDD"); v.add („EEE”); v.add ("FFF"); Wyliczenie <String> en = v.elements (); while (en.hasMoreElements ()) String value = (String) en.nextElement (); System.out.println (wartość); v.remove (wartość);
javauser71

1

1) Główną różnicą między Iteratorem a Enumeration jest usunięcie elementu podczas przeglądania kolekcji. Iterator może usunąć element podczas przeglądania kolekcji, ponieważ ma metodę remove (). Wyliczenie nie ma metody remove ().

2) Wyliczenie jest z natury bezpieczne. Nie zgłasza ConcurrentModificationException, jeśli Collection zostanie zmodyfikowana podczas przechodzenia. Iterator jest z natury odporny na awarie. Zgłasza ConcurrentModificationException, jeśli Collection zostanie zmodyfikowana podczas iteracji innej niż jej własna metoda remove ().

3) Enumeration to starszy interfejs, który jest używany do przechodzenia przez Vector, Hashtable. Iterator nie jest starszym interfejsem. Iterator może być używany do przechodzenia przez HashMap, LinkedList, ArrayList, HashSet, TreeMap, TreeSet.


0

Wyliczenie może być używane tylko dla starszych klas (Vector, Stack ...), podczas gdy Iterator może być używany dla wszystkich.


-1

Zarówno iterator, jak i wyliczenie są używane do pobierania danych, różnica polega na tym, że wyliczenie może być używane tylko dla starszych klas, tj. Wektor / stos, podczas gdy iteratory mogą być używane do reszty. Wyliczenie można również zastosować dla klucza ustawionego w mapach.


Gdzie widziałeś, że możesz użyć wyliczenia dla zestawów kluczy mapy?
Kutzi
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.