Convert List to Set in Java
Problem
Every Set implementation has a constructor that accepts any Collection and copies its elements in, which makes converting a List into a Set a single line — duplicate values are simply not added twice.
Given a List that may contain duplicate values, convert it into a Set.
Java Program
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class ConvertListToSet {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>();
numbers.add(5);
numbers.add(2);
numbers.add(5);
numbers.add(8);
numbers.add(2);
Set<Integer> unique = new HashSet<>(numbers); // copies every element in, dropping duplicates
System.out.println("List size: " + numbers.size());
System.out.println("Set size: " + unique.size());
}
}Output
Core Logic
Passing the List directly to HashSet's copy constructor inserts every element in one step, and the Set's own rules handle discarding whichever ones are duplicates.
- 1
numbersis built as anArrayList<Integer>, ending up with five elements including two repeated values. - 2
new HashSet<>(numbers)uses the constructor overload that accepts anyCollection, adding each of the List's elements into the new Set one at a time internally. - 3Since a Set can't hold two equal elements, adding
5a second time and2a second time simply has no effect the second time around. - 4The resulting
Set<Integer>ends up with only the distinct values from the original List.
[5, 2, 5, 8, 2] has 5 elements, but only 3 distinct values — 5, 2, and 8 — so the resulting Set's size is 3.Key Point: This is specifically about the List-to-Set conversion operation itself — the constructor call is a genuinely reusable pattern any time a Collection needs converting into a Set, whether or not deduplication is the actual goal.
Why: Every element of the source List is inserted into the new HashSet once, an O(1) average-case operation each, and the resulting Set holds up to n distinct elements.
Key Concepts
Approach 2: Java 8
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class ConvertListToSetStream {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>();
numbers.add(5);
numbers.add(2);
numbers.add(5);
numbers.add(8);
numbers.add(2);
// Collects the streamed elements into a Set, dropping duplicates
Set<Integer> unique = numbers.stream().collect(Collectors.toSet());
System.out.println("List size: " + numbers.size());
System.out.println("Set size: " + unique.size());
}
}
Output
Core Logic
Collecting the List's stream straight into a Set expresses the same conversion as a pipeline instead of a constructor call.
- 1
numbers.stream()opens a stream over the list's elements. - 2
.collect(Collectors.toSet())gathers every streamed element into a new Set, discarding duplicates along the way exactly like the constructor version does. - 3The returned Set's concrete type isn't guaranteed to be HashSet specifically —
Collectors.toSet()only promises some Set implementation, not which one. - 4Everything else about the conversion — five elements in, three distinct ones out — behaves identically to
new HashSet<>(numbers).
[5, 2, 5, 8, 2] into Collectors.toSet() collects the same three distinct values, 5, 2, and 8.Key Point: Both techniques do the same underlying work — the stream version reads as 'transform this data through a pipeline', which tends to fit more naturally when the List itself came from an earlier stream step rather than being built by hand.
Why: collect(Collectors.toSet()) still inserts each of the n streamed elements into the resulting Set once, the same cost as the constructor-based conversion.