Jak wykonać iterację nad zestawem / zestawem skrótów bez iteratora?


272

Jak mogę iterować po Set/ HashSetbez następujących elementów?

Iterator iter = set.iterator();
while (iter.hasNext()) {
    System.out.println(iter.next());
}

31
Czy faktycznie próbujesz uniknąć użycia iteratora, czy po prostu nie chcesz go widzieć w kodzie źródłowym?
Jon Skeet,

2
Możesz sprawić, że kod będzie krótszy i bardziej przejrzysty, ale musisz użyć iteratora. Czy jest powód, dla którego chcesz tego uniknąć?
Peter Lawrey,

5
Dla przypomnienia i dla wyjaśnienia, dlaczego warto unikać iteratora: obecnie mam do czynienia z tym problemem w grze na Androida napisanej w Javie. Obecnie używam HashSet do przechowywania słuchaczy, którzy muszą być regularnie powiadamiani o zdarzeniach. Jednak powtarzające się iteracje kolekcji powodują intensywne działania śmieciarek, które mogą obciążać pętlę gry. I nie da się tego zrobić w grze Java. Zamierzam przepisać te części.
tiguchi

12
@ thecoshman Mówię tylko z perspektywy tworzenia gier Java, w której chcesz uniknąć GC podczas regularnych aktualizacji stanu gry za wszelką cenę. Iteratory są tylko tymczasowo użytecznymi obiektami, ponieważ nie można ich zresetować do początku, dlatego są one odtwarzane przy każdym wywołaniu metody iteracji (patrz na przykład źródło ArrayList.java). Jeśli zostanie użyty w pętli gry do iteracji obiektów sceny i biorąc pod uwagę co najmniej 30 aktualizacji na sekundę, otrzymujesz co najmniej 60 (scena jest zwykle iterowana dwa razy na cykl) obiektów iteratora na sekundę czekających na GC. Ma to duży wpływ na Androida.
tiguchi

9
Być może w takim przypadku należy wybrać bardziej odpowiednią strukturę danych? Zestaw nie jest przeznaczony do iteracji. Dlaczego nie skorzystać z ArrayList i iterować ją za pomocą standardowej pętli for? Nie są tworzone dodatkowe iteratory, dostęp do odczytu jest bardzo szybki.
stef77

Odpowiedzi:


491

Możesz użyć rozszerzonej pętli for :

Set<String> set = new HashSet<String>();

//populate set

for (String s : set) {
    System.out.println(s);
}

Lub z Javą 8:

set.forEach(System.out::println);

65
Wierzę, że używa to iteratora za kulisami.
munyengm

22
@munyengm Tak to robi. Nie ma sposobu na iterację po zestawie bez iteratora, oprócz uzyskania dostępu do podstawowej struktury, która przechowuje dane poprzez odbicie i replikacji kodu dostarczonego przez Set # iterator ...
assylias

1
To działa, ale jeśli może powodować problemy, nie jest to dla mnie rozwiązanie. Chyba nie mam wyboru, muszę użyć Iteratora. Dzięki za wszystko.
user1621988,

39
@ user1621988 Jakie problemy? Nie ma problemów z podanym kodem. Zapewnia po prostu przyjemny i czysty sposób na iterację po zestawie bez konieczności jawnego używania iteratora.
assylias

90

Istnieje co najmniej sześć dodatkowych sposobów na iterację w zestawie. Znane są mi:

Metoda 1

// Obsolete Collection
Enumeration e = new Vector(movies).elements();
while (e.hasMoreElements()) {
  System.out.println(e.nextElement());
}

Metoda 2

for (String movie : movies) {
  System.out.println(movie);
}

Metoda 3

String[] movieArray = movies.toArray(new String[movies.size()]);
for (int i = 0; i < movieArray.length; i++) {
  System.out.println(movieArray[i]);
}

Metoda 4

// Supported in Java 8 and above
movies.stream().forEach((movie) -> {
  System.out.println(movie);
});

Metoda 5

// Supported in Java 8 and above
movies.stream().forEach(movie -> System.out.println(movie));

Metoda 6

// Supported in Java 8 and above
movies.stream().forEach(System.out::println);

Oto, HashSetczego użyłem w moich przykładach:

Set<String> movies = new HashSet<>();
movies.add("Avatar");
movies.add("The Lord of the Rings");
movies.add("Titanic");

10
Cześć @ benny-neugebauer W przypadku metody 4 , metody 5 , metody 6 można po prostu usunąć zbędne stream().
Eugene T

5
Nie wspominając o tym, że metoda 4, metoda 5 i metoda 6 są takie same.
GustavoCinque

24

Przekształcenie zestawu w tablicę może również pomóc w iteracji po elementach:

Object[] array = set.toArray();

for(int i=0; i<array.length; i++)
   Object o = array[i];

45
Dla przypomnienia toArraywywołuje iterator zestawu.
assylias

13

Aby zademonstrować, rozważ następujący zestaw, który zawiera różne obiekty Person:

Set<Person> people = new HashSet<Person>();
people.add(new Person("Tharindu", 10));
people.add(new Person("Martin", 20));
people.add(new Person("Fowler", 30));

Klasa modelu osoby

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    //TODO - getters,setters ,overridden toString & compareTo methods

}
  1. Instrukcja for ma formę zaprojektowaną do iteracji po kolekcjach i tablicach. Forma ta jest czasem nazywana rozszerzoną instrukcją for i może być używana do tworzenia bardziej zwartych i czytelnych pętli.
for(Person p:people){
  System.out.println(p.getName());
}
  1. Java 8 - java.lang.Iterable.forEach (konsument)
people.forEach(p -> System.out.println(p.getName()));
default void forEach(Consumer<? super T> action)

Performs the given action for each element of the Iterable until all elements have been processed or the action throws an exception. Unless otherwise specified by the implementing class, actions are performed in the order of iteration (if an iteration order is specified). Exceptions thrown by the action are relayed to the caller. Implementation Requirements:

The default implementation behaves as if: 

for (T t : this)
     action.accept(t);

Parameters: action - The action to be performed for each element

Throws: NullPointerException - if the specified action is null

Since: 1.8

11

Możesz użyć operacji funkcjonalnej, aby uzyskać bardziej czysty kod

Set<String> set = new HashSet<String>();

set.forEach((s) -> {
     System.out.println(s);
});

Połączenie wymaga API 24
djdance

11

Oto kilka wskazówek, jak iterować Zestaw wraz z ich występami:

public class IterateSet {

    public static void main(String[] args) {

        //example Set
        Set<String> set = new HashSet<>();

        set.add("Jack");
        set.add("John");
        set.add("Joe");
        set.add("Josh");

        long startTime = System.nanoTime();
        long endTime = System.nanoTime();

        //using iterator
        System.out.println("Using Iterator");
        startTime = System.nanoTime();
        Iterator<String> setIterator = set.iterator();
        while(setIterator.hasNext()){
            System.out.println(setIterator.next());
        }
        endTime = System.nanoTime();
        long durationIterator = (endTime - startTime);


        //using lambda
        System.out.println("Using Lambda");
        startTime = System.nanoTime();
        set.forEach((s) -> System.out.println(s));
        endTime = System.nanoTime();
        long durationLambda = (endTime - startTime);


        //using Stream API
        System.out.println("Using Stream API");
        startTime = System.nanoTime();
        set.stream().forEach((s) -> System.out.println(s));
        endTime = System.nanoTime();
        long durationStreamAPI = (endTime - startTime);


        //using Split Iterator (not recommended)
        System.out.println("Using Split Iterator");
        startTime = System.nanoTime();
        Spliterator<String> splitIterator = set.spliterator();
        splitIterator.forEachRemaining((s) -> System.out.println(s));
        endTime = System.nanoTime();
        long durationSplitIterator = (endTime - startTime);


        //time calculations
        System.out.println("Iterator Duration:" + durationIterator);
        System.out.println("Lamda Duration:" + durationLambda);
        System.out.println("Stream API:" + durationStreamAPI);
        System.out.println("Split Iterator:"+ durationSplitIterator);
    }
}

Kod jest oczywisty.

Wynikiem tych czasów są:

Iterator Duration: 495287
Lambda Duration: 50207470
Stream Api:       2427392
Split Iterator:    567294

Widzimy, że Lambdazajmuje to najdłużej, podczas gdy Iteratorjest najszybszy.


2

Wyliczenie(?):

Enumeration e = new Vector(set).elements();
while (e.hasMoreElements())
    {
        System.out.println(e.nextElement());
    }

Inny sposób (java.util.Collections.enumeration ()):

for (Enumeration e1 = Collections.enumeration(set); e1.hasMoreElements();)
    {
        System.out.println(e1.nextElement());
    }

Java 8:

set.forEach(element -> System.out.println(element));

lub

set.stream().forEach((elem) -> {
    System.out.println(elem);
});

0

Istnieją jednak bardzo dobre odpowiedzi na to pytanie. Oto moja odpowiedź:

1. set.stream().forEach(System.out::println); // It simply uses stream to display set values
2. set.forEach(System.out::println); // It uses Enhanced forEach to display set values

Ponadto, jeśli ten zestaw jest typu klasy niestandardowej, na przykład: klient.

Set<Customer> setCust = new HashSet<>();
    Customer c1 = new Customer(1, "Hena", 20);
    Customer c2 = new Customer(2, "Meena", 24);
    Customer c3 = new Customer(3, "Rahul", 30);

setCust.add(c1);
setCust.add(c2);
setCust.add(c3);
    setCust.forEach((k) -> System.out.println(k.getId()+" "+k.getName()+" "+k.getAge()));

// Klasa klienta:

class Customer{
private int id;
private String name;
private int age;

public Customer(int id,String name,int age){
this.id=id;
this.name=name;
this.age=age;
} // Getter, Setter methods are present.}
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.