Programming
Java
Data Structures
Iterable and Collection
Code Conversion

Easy way to convert Iterable to Collection

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Java, Iterable and Collection look close enough that people often try to cast between them, but that is only safe when the concrete type actually implements Collection. In most real code, the right approach is to materialize the iterable into a target collection explicitly. That makes ordering, mutability, and memory behavior much clearer.

Why a Cast Is Usually the Wrong Move

Iterable only guarantees that you can iterate over elements. Collection adds methods such as size, bulk operations, and stronger assumptions that many libraries rely on. Because of that, direct casting is unsafe unless you know the source object already implements the interface.

java
1Iterable<String> source = List.of("a", "b", "c");
2
3if (source instanceof Collection<String> collection) {
4    System.out.println(collection.size());
5}

Pattern matching like this is safe. Blind casting is not. If the Iterable came from a custom generator or framework wrapper, the cast can fail at runtime.

The Most Reliable Conversion Is a Simple Loop

The most portable solution is still the plain loop into a concrete collection, usually ArrayList.

java
1import java.util.ArrayList;
2import java.util.List;
3
4public static <T> List<T> toList(Iterable<T> source) {
5    ArrayList<T> result = new ArrayList<>();
6    for (T item : source) {
7        result.add(item);
8    }
9    return result;
10}

This works with any Iterable, preserves iteration order when the source has a stable order, and makes it obvious that you are materializing all elements.

Choose the Target Type Intentionally

Not every conversion should end in a List. The target type should match the semantics you need:

  • Use ArrayList when order matters and duplicates are allowed.
  • Use LinkedHashSet when uniqueness matters but insertion order should remain visible.
  • Use HashSet when uniqueness matters and order does not.
java
1import java.util.LinkedHashSet;
2import java.util.Set;
3
4public static <T> Set<T> toLinkedHashSet(Iterable<T> source) {
5    LinkedHashSet<T> result = new LinkedHashSet<>();
6    for (T item : source) {
7        result.add(item);
8    }
9    return result;
10}

Making the target type explicit avoids silent semantic changes later, such as losing duplicates or unexpectedly reordering data.

Streams Are Fine, but They Still Materialize

If your team prefers stream-based code, StreamSupport is the standard bridge from an Iterable to a stream pipeline.

java
1import java.util.List;
2import java.util.stream.Collectors;
3import java.util.stream.StreamSupport;
4
5public static <T> List<T> toListWithStreams(Iterable<T> source) {
6    return StreamSupport.stream(source.spliterator(), false)
7            .collect(Collectors.toList());
8}

This version is concise and composable with filtering or mapping. It is not fundamentally more efficient than the loop. It still reads every element and stores the result in memory.

Think About Mutability and Ownership

A conversion is also a contract decision. Should callers be allowed to modify the returned collection, or should the result be treated as a snapshot? If the data should not be changed after conversion, return an unmodifiable view or immutable copy.

java
1import java.util.Collections;
2import java.util.List;
3
4public static <T> List<T> toUnmodifiableList(Iterable<T> source) {
5    ArrayList<T> result = new ArrayList<>();
6    for (T item : source) {
7        result.add(item);
8    }
9    return Collections.unmodifiableList(result);
10}

This protects the conversion boundary and makes downstream ownership clearer.

Materialization Has a Cost

The biggest design question is often not how to convert, but whether you should convert at all. Turning a lazy iterable into a collection means allocating memory for every element up front. For large or streaming sources, that may be the wrong choice.

If conversion appears in a hot path, consider whether the downstream API could accept Iterable instead. Sometimes changing an internal method signature is better than forcing every caller to materialize data early.

This is especially important when the iterable comes from a database cursor, remote page stream, or expensive generator. Conversion may simplify one call site while making the overall system heavier.

Common Pitfalls

The most common mistake is casting Iterable to Collection without proving the concrete type supports it. Another is choosing Set accidentally and losing duplicates, or returning a mutable collection where callers expected a safe snapshot. Teams also often forget that every conversion materializes the source, which can create unnecessary memory pressure.

Summary

  • 'Iterable and Collection are related interfaces, not interchangeable ones.'
  • A simple loop into ArrayList is the most reliable general conversion.
  • Pick the target collection type based on semantics, not habit.
  • Decide whether the returned collection should be mutable or not.
  • Avoid conversion entirely when lazy iteration is the better design.

Course illustration
Course illustration

All Rights Reserved.