如何在没有迭代器的情况下遍历Set / HashSet?


272

如何遍历一个Set/ HashSet不包含以下内容?

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

31
您实际上是在尝试避免使用迭代器,还是只是不想在代码中看到它?
乔恩·斯基特

2
您可以使代码更短,更清晰,但是必须使用Iterator。您有避免的理由吗?
彼得·劳瑞

5
仅作记录并解释为什么避免迭代器:我目前在用Java编写的Android游戏中遇到该问题。现在,我正在使用HashSet来存储需要定期通知事件的侦听器。但是,重复迭代收集会导致大量的垃圾收集器活动,从而增加游戏循环的负担。这在Java游戏中是徒劳的。我将重写这些部分。
tiguchi 2013年

12
@thecoshman我只是从Java游戏开发的角度出发,在这种情况下,您不惜一切代价避免在常规游戏状态更新期间避免使用GC。迭代器只是临时有用的对象,因为您无法将其重置为开始,因此在每次迭代方法调用时都会重新创建它们(例如,请参见ArrayList.java源)。如果在游戏循环中用于迭代场景对象并考虑每秒至少进行30次更新,则最终在内存中至少每秒有60个迭代器对象(场景通常每个循环迭代两次),等待GC。这对Android产生了重大影响。
tiguchi 2014年

9
在这种情况下,也许应该选择一种更合适的数据结构?集合的设计目的不是有效地进行迭代。为什么不使用ArrayList并使用标准的for循环对其进行迭代?没有创建其他迭代器,读取访问非常快。
stef77

Answers:


491

您可以使用增强的for循环

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

//populate set

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

或使用Java 8:

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

65
我相信这在幕后使用了迭代器。
munyengm 2012年

22
@munyengm是的。没有迭代器,就无法在集合上进行迭代,除了访问通过反射来保存数据的底层结构,以及复制Set#iterator提供的代码外……
assylias 2012年

1
这行得通,但是如果它可能带来问题,那么这不是我的解决方案。我想我别无选择,我必须使用Iterator。还是谢谢你。
user1621988 2012年

39
@ user1621988什么问题?我提供的代码没有问题。它只是提供了一种很好而干净的方法来迭代集合,而不必显式使用迭代器。
assylias 2012年

90

至少有六种其他方式可以迭代一个集合。以下是我所知道的:

方法一

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

方法2

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

方法3

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

方法4

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

方法5

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

方法6

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

这是HashSet我用于示例的内容:

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

10
@ benny-neugebauer,您好:对于方法4方法5方法6,您只需删除多余的即可stream()
尤金T

5
更不用说方法4,方法5和方法6相同。
GustavoCinque '18

24

将您的集合转换成数组 也可以帮助您遍历元素:

Object[] array = set.toArray();

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

45
仅作记录,请toArray调用集合的迭代器。
assylias 2012年

13

为了演示,请考虑以下集合,其中包含不同的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));

人物模型类

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. for语句具有一种为通过Collections和数组进行迭代而设计的形式,该形式有时被称为增强的for语句,可用于使循环更紧凑和更易于阅读。
for(Person p:people){
  System.out.println(p.getName());
}
  1. Java 8-java.lang.Iterable.forEach(消费者)
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

您可以使用函数操作获得更简洁的代码

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

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

通话需要API 24
临近

11

以下是一些有关如何迭代Set及其演奏的提示:

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

该代码不言自明。

持续时间的结果是:

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

我们可以看到Lambda花费时间最长而花费Iterator最快。


2

枚举(?):

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

另一种方式(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));

要么

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

0

但是,已经有很好的答案。这是我的答案:

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

另外,如果此Set为Custom类类型,例如:Customer。

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

//客户类别:

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.}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.