Back to Collectors
Q15Question 15 of 21

Collect employee names into a Set<String> (removing duplicates)

Key Concepts
  • map(Employee::getName).collect(toSet()) gathers names into a Set, automatically removing duplicates
  • A Set stores each element once by equals and hashCode, so no explicit distinct() is needed
  • toSet() returns a HashSet by default with no guaranteed iteration order
  • For sorted order use toCollection(TreeSet::new); for insertion order use toCollection(LinkedHashSet::new)
  • Deduplication relies on correct equals and hashCode on the element type (String has them)
  • toSet() is equivalent to distinct().collect(toList()) but expresses the uniqueness intent directly

Definition

`map(getName).collect(toSet())` collects distinct names into a `Set`, dropping duplicates automatically because a set stores each value only once.
  • map(Employee::getName) extracts the name from each employee.
  • collect(Collectors.toSet()) gathers names into a Set that holds each value once.
  • Deduplication is automatic: the set uses equals and hashCode to detect duplicates.
  • No guaranteed order: toSet() returns a HashSet by default.
  • For ordered sets, use toCollection(TreeSet::new) or toCollection(LinkedHashSet::new).

At the National Bank of India, Priya compiles a mailing list of unique employee names. If two employees share the same name, it appears only once in the list.

Understanding the Concepts

What does collecting into a Set achieve?

A Set stores each element only once, determined by equals and hashCode. Collecting names into a set automatically removes duplicate names without needing an explicit distinct() call. The result is the set of unique names.

How do you implement it?

JAVA
package com.bank.hr;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

public class CollectToSet {

    record Employee(String id, String name, String department, BigDecimal salary) {}

    public static void main(String[] args) {
        List<Employee> staff = List.of(
            new Employee("SAV2001", "Rajesh",  "TRADING",    new BigDecimal("1800000")),
            new Employee("SAV2002", "Priya",   "RISK",       new BigDecimal("1200000")),
            new Employee("SAV2003", "Rajesh",  "OPERATIONS", new BigDecimal("900000")),
            new Employee("SAV2004", "Meera",   "TRADING",    new BigDecimal("1500000")),
            new Employee("SAV2005", "Priya",   "COMPLIANCE", new BigDecimal("1050000"))
        );

        Set<String> uniqueNames = staff.stream()
            .map(Employee::name)
            .collect(Collectors.toSet());

        System.out.println("Unique names: " + uniqueNames);
        System.out.println("Count: " + uniqueNames.size());
    }
}
TEXT
Unique names: [Meera, Priya, Rajesh]
Count: 3

How do you control the set type and ordering?

JAVA
// Sorted (TreeSet): alphabetical order
TreeSet<String> sorted = staff.stream()
    .map(Employee::name)
    .collect(Collectors.toCollection(TreeSet::new));
// [Meera, Priya, Rajesh]

// Insertion order (LinkedHashSet): first-seen order
LinkedHashSet<String> insertionOrder = staff.stream()
    .map(Employee::name)
    .collect(Collectors.toCollection(LinkedHashSet::new));
// [Rajesh, Priya, Meera] – first occurrence order

How is toSet() different from distinct().toList()?

| Approach | Result type | Uniqueness | Order |
|---|---|---|---|
| toSet() | Set | By set contract | Unordered (HashSet) |
| distinct().toList() | List | By distinct + equals | Encounter order preserved |
| toCollection(TreeSet::new) | TreeSet | By comparator | Sorted |

What are common mistakes?

Mistake: Assuming toSet() preserves insertion order.

JAVA
// WRONG assumption: order is preserved
Set<String> names = staff.stream().map(Employee::name).collect(Collectors.toSet());
// Iteration order is unpredictable (HashSet)

// CORRECT for insertion order
LinkedHashSet<String> ordered = staff.stream()
    .map(Employee::name)
    .collect(Collectors.toCollection(LinkedHashSet::new));

What about custom objects and equals/hashCode?

For custom objects, deduplication depends entirely on correct equals and hashCode. If those are wrong, the set will not deduplicate as expected.

JAVA
// Records automatically generate equals/hashCode from all components
record AccountId(String branch, int number) {}

Set<AccountId> uniqueAccounts = transactions.stream()
    .map(Transaction::accountId)
    .collect(Collectors.toSet());
// Correct deduplication because record equals checks all fields

What about null elements?

HashSet allows one null element, but TreeSet throws NullPointerException because it needs to compare elements. Filter nulls before collecting into a TreeSet.

What should a senior engineer know?

toSet() gives no ordering guarantee and no control over the concrete type. When ordering or a specific set type matters, use toCollection with a supplier. For custom objects, verify that equals and hashCode are correct before relying on set deduplication.

What are common interview follow-up questions?

  • "How do you get a sorted set?" Use toCollection(TreeSet::new).
  • "What if equals/hashCode are wrong?" The set will not deduplicate correctly.
  • "How is toSet different from distinct?" toSet returns a Set; distinct returns a Stream that can be collected into any structure.

Visual Overview

DIAGRAM
  Input: [Rajesh, Priya, Rajesh, Meera, Priya]
       │
       │  collect(toSet())
       ▼
  ┌──────────────────────────────┐
  │  HashSet<String>             │
  │  {Rajesh, Priya, Meera}     │
  │  ← duplicates removed       │
  │  ← order not guaranteed     │
  └──────────────────────────────┘

Key Takeaway

Collecting names into a Set with map(getName).collect(toSet()) automatically removes duplicates because a set holds each element only once by equals and hashCode. No explicit distinct() call is needed. At the National Bank of India, Priya uses this for mailing lists where each name should appear once.

The default toSet() returns a HashSet with no guaranteed iteration order. For sorted order, use toCollection(TreeSet::new). For insertion order (first-seen order), use toCollection(LinkedHashSet::new). The choice depends on whether the consumer needs ordering.

For custom objects, deduplication is only as good as their equals and hashCode. If those are not implemented correctly, the set will not dedupe as expected. Records are safe because they auto-generate correct equals and hashCode from all components.

Remember one sentence: toSet() collects distinct values automatically because a set holds each element once, but use toCollection with a supplier when ordering matters.

---

Share
Use ← → arrow keys to navigate