Generic Top

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Introduction

Iterating over elements is one of the most fundamental operations we can execute on a collection.

In this tutorial, we'll take a look at how to iterate over elements of a Set and how it differs from the similar tasks on a List or array.

2. Getting Acces to Elements in a Set

A Set, unlike a List and many other collections, isn't sequential. Their elements aren't indexed, and depending on the implementation, they may not maintain order.

That means that we can't ask about a specific element of the set by its number. Because of that, we can't use a typical for loop or any other index-based method.

2.1. Iterator

The most basic and close-to-metal method of iterating over the set is invoking the iterator method exposed by every Set:

Set<String> names = Sets.newHashSet("Tom", "Jane", "Karen");
Iterator<String> namesIterator = names.iterator();

Then we can use the obtained iterator to get elements of that Set, one by one. The most iconic way is checking if the iterator has a next element in the while loop:

while(namesIterator.hasNext()) {
   System.out.println(namesIterator.next());
}

We can also use the forEachRemaining method added in Java 8:

namesIterator.forEachRemaining(System.out::println);

We can also mix these solutions:

String firstName = namesIterator.next(); // save first name to variable
namesIterator.forEachRemaining(System.out::println); // print rest of the names

All other methods will use an Iterator in some way under the hood.

3. Streams

Every Set exposes the spliterator() method. Because of that, a Set can be easily transformed into a Stream:

names.stream().forEach(System.out::println);

We can also leverage the rich Streams API to create more complex pipelines. For example, let's map, log, and then reduce elements of the set to a single string:

String namesJoined = names.stream()
    .map(String::toUpperCase)
    .peek(System.out::println)
    .collect(Collectors.joining());

4. Enhanced Loop

While we can't use a simple, indexed for loop to iterate over a Set, we can use the enhanced loop feature introduced in Java 5:

for (String name : names) {
    System.out.println(name);
}

5. Iterating with Index

5.1. Converting to Array

Sets aren't indexed, but we can add an index artificially. One possible solution is to simply convert the Set to some more approachable data structure like an array:

Object[] namesArray = names.toArray();
for (int i = 0; i < namesArray.length; i++) {
    System.out.println(i + ": " + namesArray[i]);
}

Mind that conversion to an array alone will iterate over the Set once. So, in terms of complexity, we'll be iterating over the Set twice. That may be a problem if performance is crucial.

5.2. Zipping with Index

Another approach is to create an index and zip it with our Set. While we could do it in vanilla Java, there are libraries that provide tools just for that.

For example, we can use Vavr's streams:

Stream.ofAll(names)
  .zipWithIndex()
  .forEach(t -> System.out.println(t._2() + ": " + t._1()));

6. Summary

In this tutorial, we looked at various ways of iterating over elements of the Set instance. We explored the usage of iterators, streams, and loops, and the differences between them.

As always, examples are available over on GitHub.

Generic bottom

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course:

>> CHECK OUT THE COURSE
Generic footer banner
Comments are closed on this article!