Como iterar em um Set / HashSet sem um iterador?


273

Como posso iterar sobre um Set/ HashSetsem o seguinte?

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

31
Você está realmente tentando evitar o uso de um iterador ou simplesmente não deseja vê-lo no seu código- fonte ?
precisa saber é o seguinte

2
Você pode tornar o código mais curto e limpo, mas é necessário usar um iterador. Existe uma razão para você querer evitá-lo?
Peter Lawrey

5
Apenas para registro e como explicação do porquê evitar o iterador: Atualmente, estou enfrentando esse problema em um jogo Android escrito em Java. No momento, estou usando um HashSet para armazenar ouvintes que precisam ser notificados regularmente sobre eventos. No entanto, iterar repetidamente as coleções causa uma atividade pesada do coletor de lixo que pode sobrecarregar o loop do jogo. E isso é proibido em um jogo Java. Vou reescrever essas partes.
tiguchi

12
@thecoshman Estou falando apenas de uma perspectiva de desenvolvimento de jogos Java, na qual você deseja evitar o GC durante atualizações regulares do estado do jogo a todo custo. Os iteradores são apenas objetos temporariamente úteis, pois você não pode redefini-los para o início; portanto, eles são recriados a cada chamada do método de iteração (consulte a fonte ArrayList.java, por exemplo). Se usado em um loop de jogo para iterar objetos de cena e considerar pelo menos 30 atualizações por segundo, você terá pelo menos 60 (a cena é iterada duas vezes por ciclo) objetos iteradores por segundo na memória aguardando o GC. Isso tem um grande impacto no Android.
precisa saber é o seguinte

9
Talvez deva-se escolher uma estrutura de dados mais adequada nesse caso? Um conjunto não foi projetado para iterar de maneira eficiente. Por que não usar um ArrayList e iterar sobre ele com um padrão para loop? Nenhum iterador adicional é criado, o acesso de leitura é muito rápido.
stef77

Respostas:


492

Você pode usar um loop for aprimorado :

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

//populate set

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

Ou com Java 8:

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

65
Eu acredito que isso usa um iterador nos bastidores.
munyengm

22
@munyengm Sim, sim. Não há nenhuma maneira para iterar sobre um conjunto sem um iterador, além de acessar a estrutura subjacente que contém os dados através da reflexão, e replicar o código fornecido pelo Set # iterador ...
assylias

1
Isso funciona, mas se isso der problemas, não é a solução para mim. Acho que não tenho escolha, devo usar o Iterator. Obrigado por todos de qualquer maneira.
user1621988

39
@ user1621988 Que problemas? Não há problemas com o código que forneci. Ele apenas fornece uma maneira agradável e limpa de interagir com um conjunto sem precisar usar explicitamente um iterador.
assylias 17/09/12

90

Existem pelo menos seis maneiras adicionais de iterar em um conjunto. Os seguintes são conhecidos por mim:

Método 1

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

Método 2

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

Método 3

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

Método 4

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

Método 5

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

Método 6

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

Isto é o HashSetque eu usei para meus exemplos:

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

10
Oi @ benny-neugebauer Para o Método 4 , Método 5 , Método 6, você pode simplesmente remover redundante stream().
Eugene T

5
Sem mencionar que os métodos 4, 5 e 6 são iguais.
GustavoCinque

24

A conversão do seu conjunto em uma matriz também pode ajudá-lo a iterar sobre os elementos:

Object[] array = set.toArray();

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

45
Apenas para o registro, toArraychama o iterador do aparelho.
assylias 17/09/12

13

Para demonstrar, considere o seguinte conjunto, que contém diferentes objetos 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));

Classe de modelo de pessoa

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. A instrução for possui um formulário projetado para iteração por meio de coleções e matrizes. Este formulário às vezes é chamado de aprimorado para instrução e pode ser usado para tornar seus loops mais compactos e fáceis de ler.
for(Person p:people){
  System.out.println(p.getName());
}
  1. Java 8 - java.lang.Iterable.forEach (consumidor)
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

Você pode usar a operação funcional para obter um código mais limpo

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

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

A chamada requer API 24
djdance

11

Aqui estão algumas dicas sobre como iterar um conjunto junto com suas performances:

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

O código é auto-explicativo.

O resultado das durações são:

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

Podemos ver que a Lambdademora mais longa Iteratoré a mais rápida.


2

Enumeração(?):

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

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

ou

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

0

No entanto, já existem respostas muito boas para isso. Aqui está a minha resposta:

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

Além disso, se este conjunto for do tipo de classe personalizada, por exemplo: cliente.

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

// Classe do cliente:

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.}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.