Як перенести набір / HashSet без ітератора?


272

Як я можу повторити перелік Set/ HashSetбез наступного?

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

31
Ви насправді намагаєтесь уникати використання ітератора, чи просто не хочете бачити його у своєму вихідному коді?
Джон Скіт

2
Ви можете зробити код коротшим і більш чистим, але вам доведеться використовувати Ітератор. Чи є причина, яку ви хочете цього уникнути?
Пітер Лорі

5
Тільки для запису та пояснення того, чому слід уникати ітератора: я зараз стикаюся з цим питанням в грі Android, написаній на Java. Зараз я використовую HashSet для зберігання слухачів, яким потрібно регулярно повідомляти про події. Однак багаторазове повторення колекцій спричиняє активність збору сміття, яка може навантажувати цикл гри. І це вже не в грі на Java. Я збираюся переписати ці частини.
tiguchi

12
@thecoshman Я говорю лише з точки зору розвитку ігор Java, де ви хочете уникнути GC під час регулярних оновлень стану гри за будь-яку ціну. Ітератори є лише тимчасово корисними об'єктами, оскільки ви не можете їх скинути до початку, тому вони відтворюються під час кожного виклику методу ітерації (див., Наприклад, джерело ArrayList.java). Якщо ви використовуєте в ігровому циклі для ітерації об'єктів сцени і розглядаєте щонайменше 30 оновлень в секунду, ви отримуєте щонайменше 60 (сцена зазвичай повторюється двічі за цикл), ітератор об'єктів в секунду в пам'яті чекає GC. Це має великий вплив на Android.
tiguchi

9
Можливо, варто вибрати в цьому випадку більш адекватну структуру даних? Набір не розрахований на ефективне повторення. Чому б не використати ArrayList і повторити його зі стандартом для циклу? Ніяких додаткових ітераторів не створюється, доступ до читання дуже швидкий.
stef77

Відповіді:


491

Ви можете використовувати розширений цикл :

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

22
@munyengm Так. Немає можливості перебирати набір без ітератора, окрім доступу до базової структури, яка зберігає дані за допомогою відображення, та реплікації коду, наданого Set # iterator ...
assylias

1
Це працює, але якщо це може дати проблеми, то для мене це не рішення. Я думаю, у мене немає вибору, я повинен використовувати Iterator. Спасибі за все-таки.
користувач1621988

39
@ user1621988 Які проблеми? Немає проблем з наданим мені кодом. Це просто забезпечує приємний і чистий спосіб перегляду набору без явного використання ітератора.
assylias

90

Існує щонайменше шість додаткових способів ітерації над набором. Мені відомі такі:

Спосіб 1

// 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().
Євген Т

5
Не кажучи вже про те, що метод 4, метод 5 і метод 6 однакові.
GustavoCinque

24

Перетворення вашого набору в масив може також допомогти вам переглядати елементи:

Object[] array = set.toArray();

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

45
Тільки для запису toArrayвикликає ітератор набору.
assylias

13

Для демонстрації розглянемо наступний набір, який містить різні об'єкти Особи:

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 має форму, призначену для ітерації через Колекції та масиви. Ця форма іноді називається розширеною для оператора, і її можна використовувати, щоб зробити петлі більш компактними та зручними для читання.
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
djdance

11

Ось кілька порад, як ітератувати набір разом із їхніми виступами:

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<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.}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.