Wie iteriere ich über ein Set / HashSet ohne Iterator?

272

Wie kann ich über ein Set/ HashSetohne Folgendes iterieren ?

Iterator iter = set.iterator();
while (iter.hasNext()) {
    System.out.println(iter.next());
}
user1621988
quelle
31
Versuchen Sie , tatsächlich die Verwendung eines Iterators zu vermeiden, oder wollen Sie einfach nicht in der sehen Quelle Code?
Jon Skeet
2
Sie können den Code kürzer und sauberer machen, müssen jedoch einen Iterator verwenden. Gibt es einen Grund, warum Sie dies vermeiden möchten?
Peter Lawrey
5
Nur zur Veranschaulichung und als Erklärung, warum der Iterator vermieden werden sollte: Ich bin derzeit mit diesem Problem in einem in Java geschriebenen Android-Spiel konfrontiert. Im Moment verwende ich ein HashSet zum Speichern von Listenern, die regelmäßig über Ereignisse benachrichtigt werden müssen. Das wiederholte Iterieren von Sammlungen führt jedoch zu einer starken Garbage Collector-Aktivität, die die Spielschleife belasten kann. Und das ist ein No-Go in einem Java-Spiel. Ich werde diese Teile umschreiben.
Tiguchi
12
@thecoshman Ich spreche nur aus der Perspektive der Java-Spieleentwicklung, bei der Sie GC bei regelmäßigen Aktualisierungen des Spielstatus um jeden Preis vermeiden möchten. Iteratoren sind nur vorübergehend nützliche Objekte, da Sie sie nicht auf den Start zurücksetzen können. Daher werden sie bei jedem Aufruf der Iterationsmethode neu erstellt (siehe z. B. ArrayList.java-Quelle). Wenn Sie in einer Spielschleife zum Iterieren von Szenenobjekten und unter Berücksichtigung von mindestens 30 Aktualisierungen pro Sekunde verwendet werden, erhalten Sie mindestens 60 (Szene wird normalerweise zweimal pro Zyklus iteriert) Iteratorobjekte pro Sekunde im Speicher, die auf GC warten. Das hat einen großen Einfluss auf Android.
Tiguchi
9
Vielleicht sollte man in diesem Fall eine adäquatere Datenstruktur wählen? Ein Set ist nicht dafür ausgelegt, effizient zu iterieren. Warum nicht eine ArrayList verwenden und mit einer Standard-for-Schleife darüber iterieren? Es werden keine zusätzlichen Iteratoren erstellt, der Lesezugriff ist sehr schnell.
stef77

Antworten:

491

Sie können eine erweiterte for-Schleife verwenden :

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

//populate set

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

Oder mit Java 8:

set.forEach(System.out::println);
Assylien
quelle
65
Ich glaube, dies verwendet einen Iterator hinter den Kulissen.
Munyengm
22
@ Munyengm Ja, das tut es. Es gibt keine Möglichkeit, über einen Satz ohne Iterator zu iterieren, außer auf die zugrunde liegende Struktur zuzugreifen, die die Daten durch Reflexion enthält, und den von Set #
iterator
1
Das funktioniert, aber wenn es Probleme geben könnte, dann ist es nicht die Lösung für mich. Ich denke, ich habe keine Wahl, ich muss Iterator verwenden. Trotzdem danke für alles.
user1621988
39
@ user1621988 Welche Probleme? Es gibt keine Probleme mit dem von mir bereitgestellten Code. Es bietet nur eine schöne und saubere Möglichkeit, über einen Satz zu iterieren, ohne explizit einen Iterator verwenden zu müssen.
Assylias
90

Es gibt mindestens sechs zusätzliche Möglichkeiten, einen Satz zu durchlaufen. Folgendes ist mir bekannt:

Methode 1

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

Methode 2

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

Methode 3

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

Methode 4

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

Methode 5

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

Methode 6

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

Dies ist das, HashSetwas ich für meine Beispiele verwendet habe:

Set<String> movies = new HashSet<>();
movies.add("Avatar");
movies.add("The Lord of the Rings");
movies.add("Titanic");
Benny Neugebauer
quelle
10
Hi @ benny-neugebauer Für Methode 4 , Methode 5 , Methode 6 können Sie einfach redundante entfernen stream().
Eugene T
5
Ganz zu schweigen davon, dass Methode 4, Methode 5 und Methode 6 gleich sind.
GustavoCinque
24

Das Konvertieren Ihres Sets in ein Array kann Ihnen auch beim Durchlaufen der Elemente helfen:

Object[] array = set.toArray();

for(int i=0; i<array.length; i++)
   Object o = array[i];
Juvanis
quelle
45
Ruft nur zur Aufzeichnung toArrayden Iterator des Sets auf.
Assylias
13

Betrachten Sie zur Demonstration den folgenden Satz, der verschiedene Personenobjekte enthält:

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

Personenmodellklasse

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. Die for-Anweisung verfügt über ein Formular, das für die Iteration durch Sammlungen und Arrays entwickelt wurde. Dieses Formular wird manchmal als erweiterte for-Anweisung bezeichnet und kann verwendet werden, um Ihre Schleifen kompakter und leichter lesbar zu machen.
for(Person p:people){
  System.out.println(p.getName());
}
  1. Java 8 - java.lang.Iterable.forEach (Consumer)
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
Tharindu Rajarathna
quelle
11

Sie können die Funktionsoperation für einen übersichtlicheren Code verwenden

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

set.forEach((s) -> {
     System.out.println(s);
});
Samuel Moshie
quelle
Anruf erfordert API 24
djdance
11

Hier sind einige Tipps, wie Sie ein Set zusammen mit ihren Leistungen wiederholen können:

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);
    }
}

Der Code ist selbsterklärend.

Das Ergebnis der Dauer sind:

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

Wir können sehen, dass es am Lambdalängsten dauert, während Iteratores am schnellsten ist.

Pritam Banerjee
quelle
2

Aufzählung(?):

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

Ein anderer Weg (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));

oder

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

Hierfür gibt es jedoch bereits sehr gute Antworten. Hier ist meine Antwort:

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

Wenn es sich bei diesem Satz um einen benutzerdefinierten Klassentyp handelt, z. B.: Kunde.

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()));

// Kundenklasse:

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.}
Garima Garg
quelle