Definition
- new HashSet<>(list): duplicates removed, iteration order unpredictable
- new LinkedHashSet<>(list): duplicates removed, insertion order preserved
- new TreeSet<>(list): duplicates removed, elements sorted by natural order or Comparator
- stream().collect(Collectors.toSet()): returns an unordered HashSet
- stream().collect(Collectors.toCollection(LinkedHashSet::new)): returns an ordered LinkedHashSet
- Duplicate detection uses equals() and hashCode() (for HashSet/LinkedHashSet) or compareTo() (for TreeSet)
You pour a stack of account cards – some duplicated – into a deduplicating tray. A HashSet tray keeps one of each but shuffles them. A LinkedHashSet tray keeps one of each in the order they arrived. A TreeSet tray keeps one of each sorted alphabetically.
Understanding the Concepts
What happens when you convert List to Set?
The Set constructor iterates the List and adds each element. Since Sets reject duplicates, only the first occurrence of each element is kept.
package com.bank.demo;
import java.util.*;
public class ListToSetDemo {
public static void main(String[] args) {
List<String> accounts = List.of(
"SAV2001", "CUR3001", "SAV2001", "FD4001", "CUR3001", "SAV2002"
);
System.out.println("Original list: " + accounts);
System.out.println("List size: " + accounts.size()); // 6
// HashSet: removes duplicates, loses order
Set<String> hashSet = new HashSet<>(accounts);
System.out.println("\nHashSet: " + hashSet);
System.out.println("Size: " + hashSet.size()); // 4
// LinkedHashSet: removes duplicates, keeps insertion order
Set<String> linkedSet = new LinkedHashSet<>(accounts);
System.out.println("\nLinkedHashSet: " + linkedSet);
System.out.println("Size: " + linkedSet.size()); // 4
// TreeSet: removes duplicates, sorts
Set<String> treeSet = new TreeSet<>(accounts);
System.out.println("\nTreeSet: " + treeSet);
System.out.println("Size: " + treeSet.size()); // 4
}
}
Original list: [SAV2001, CUR3001, SAV2001, FD4001, CUR3001, SAV2002]
List size: 6
HashSet: [FD4001, SAV2002, CUR3001, SAV2001]
Size: 4
LinkedHashSet: [SAV2001, CUR3001, FD4001, SAV2002]
Size: 4
TreeSet: [CUR3001, FD4001, SAV2001, SAV2002]
Size: 4
How do you convert back from Set to List?
package com.bank.demo;
import java.util.*;
public class SetToListDemo {
public static void main(String[] args) {
Set<String> accountSet = new LinkedHashSet<>(List.of("SAV2001", "CUR3001", "FD4001"));
// Method 1: ArrayList constructor
List<String> list1 = new ArrayList<>(accountSet);
// Method 2: List.copyOf (Java 10+, immutable)
List<String> list2 = List.copyOf(accountSet);
// Method 3: Stream
List<String> list3 = accountSet.stream().toList();
System.out.println("List: " + list1);
}
}
List: [SAV2001, CUR3001, FD4001]
How do you check how many duplicates were removed?
List<String> original = List.of("A", "B", "A", "C", "B", "A");
Set<String> unique = new LinkedHashSet<>(original);
int duplicateCount = original.size() - unique.size();
System.out.println("Duplicates removed: " + duplicateCount); // 3
What about custom objects?
When converting a list of custom objects to a set, the Set uses equals() and hashCode() to determine uniqueness. Without proper overrides, each object instance is treated as unique.
package com.bank.demo;
import java.math.BigDecimal;
import java.util.*;
public class CustomObjectDedup {
record Account(String id, String holder, BigDecimal balance) {}
// Records auto-generate equals/hashCode based on all components
public static void main(String[] args) {
List<Account> accounts = List.of(
new Account("SAV2001", "Rajesh", new BigDecimal("50000")),
new Account("CUR3001", "Priya", new BigDecimal("75000")),
new Account("SAV2001", "Rajesh", new BigDecimal("50000")), // duplicate
new Account("SAV2001", "Rajesh", new BigDecimal("60000")) // different balance!
);
Set<Account> unique = new LinkedHashSet<>(accounts);
System.out.println("Unique accounts: " + unique.size()); // 3
// The last entry has different balance → different equals → not a duplicate
unique.forEach(a -> System.out.println(" " + a));
}
}
Unique accounts: 3
Account[id=SAV2001, holder=Rajesh, balance=50000]
Account[id=CUR3001, holder=Priya, balance=75000]
Account[id=SAV2001, holder=Rajesh, balance=60000]
What are common mistakes?
Mistake 1: Using HashSet and expecting insertion order in the output
// WRONG: order lost
Set<String> set = new HashSet<>(list);
for (String s : set) { System.out.print(s + " "); } // unpredictable order
// CORRECT: use LinkedHashSet for order
Set<String> set = new LinkedHashSet<>(list);
Mistake 2: Deduplicating objects without proper equals/hashCode
// WRONG: class without equals/hashCode
class Account { String id; }
List<Account> list = List.of(new Account("SAV2001"), new Account("SAV2001"));
Set<Account> set = new HashSet<>(list);
// set.size() = 2! Both treated as different because default equals is identity.
// CORRECT: use record or override equals/hashCode
record Account(String id) {}
What should a senior engineer know?
- Set.copyOf(list) (Java 10+). Creates an immutable set from the list, removing duplicates. Null elements throw NullPointerException. Iteration order is not guaranteed.
- Collectors.toUnmodifiableSet(). In streams: list.stream().collect(Collectors.toUnmodifiableSet()) creates an immutable set. Null and duplicates throw exceptions.
- TreeSet conversion requires Comparable. new TreeSet<>(list) requires elements to implement Comparable. Otherwise, provide a Comparator: new TreeSet<>(comparator) then addAll(list).
What are common interview follow-up questions?
- "How do you remove duplicates from a List?" – new ArrayList<>(new LinkedHashSet<>(list)).
- "What determines if two elements are duplicates?" – equals() and hashCode() for Hash/LinkedHash sets; compareTo() for TreeSet.
- "Is the size of the Set always less than the List?" – Less than or equal. Equal when there are no duplicates.
Visual Overview
List → Set conversion
List: [SAV2001, CUR3001, SAV2001, FD4001, CUR3001]
(5 elements, 2 duplicates)
↓
new HashSet<>(): {FD4001, CUR3001, SAV2001} (no order)
new LinkedHashSet<>(): {SAV2001, CUR3001, FD4001} (insertion order)
new TreeSet<>(): {CUR3001, FD4001, SAV2001} (sorted)
↓
All: 3 elements (2 duplicates removed)
Key Takeaway
Converting a List to a Set is the standard way to remove duplicates in Java. The choice of Set implementation determines the ordering: HashSet gives no ordering, LinkedHashSet preserves insertion order, and TreeSet sorts. The first occurrence of each element is kept; later equal elements are silently discarded.
In the National Bank of India's transaction reconciliation system, Rajesh receives transaction feeds from multiple channels where the same transaction may appear two or three times. He converts the list to a LinkedHashSet to get unique transactions in arrival order, then converts back to a List for the downstream processing pipeline.
The critical detail is that duplicate detection depends on equals() and hashCode(). Custom objects without proper overrides are treated as unique even when their fields are identical. Java records automatically generate correct equals and hashCode based on all components.
Remember one sentence: new LinkedHashSet<>(list) removes duplicates while keeping insertion order; the Set implementation you choose determines the ordering of the result.
---