The Set Interface in Java
The Set interface is part of the Java Collections Framework and represents a collection of unique elements. Unlike a List, a Set does not allow duplicate values.
The Set interface extends the Collection interface.
Key Characteristics
- Stores only unique elements.
- Does not allow duplicate values.
- Part of the Java Collections Framework.
- Useful when uniqueness is required.
Implementations of the Set Interface
Java provides several implementations of the Set interface.
HashSet
A HashSet stores elements using a hash table.
Features
- Does not maintain insertion order.
- Allows one
nullelement. - Provides fast lookup, insertion, and deletion.
- Average time complexity for
add(),remove(), andcontains()is O(1).
Best Use Cases
- Removing duplicate values.
- Fast searching.
- When ordering is not important.
LinkedHashSet
LinkedHashSet extends HashSet by maintaining a doubly linked list of elements.
Features
- Preserves insertion order.
- Allows one
nullelement. - Slightly slower than
HashSetbecause of the linked list.
Best Use Cases
- When uniqueness and insertion order are both required.
TreeSet
TreeSet implements the NavigableSet interface.
Features
- Stores elements in sorted (ascending) order.
- Does not allow
nullvalues. - Uses a Red-Black Tree internally.
- Basic operations take O(log n) time.
Best Use Cases
- Maintaining sorted data.
- Range-based operations.
- Automatically sorting elements.
HashSet vs LinkedHashSet vs TreeSet
| Feature | HashSet | LinkedHashSet | TreeSet |
|---|---|---|---|
| Duplicate elements | ❌ Not allowed | ❌ Not allowed | ❌ Not allowed |
| Order maintained | No | Insertion order | Sorted order |
| Internal structure | Hash table | Hash table + Linked List | Red-Black Tree |
| Performance | O(1) | O(1) | O(log n) |
| Allows null | Yes (one) | Yes (one) | No |
Real-Life Example
Think of a classroom attendance register.
Each student's name should appear only once.
A Set ensures that duplicate names cannot be added.
Real-Time Testing Example
In Selenium automation, a Set is commonly used to store:
- Browser window handles
- Unique URLs
- Test IDs
Example:
Set<String> windows = driver.getWindowHandles();
Since every browser window has a unique handle, a Set is the ideal collection.
How HashMap Works Internally
HashMap is one of the most commonly used implementations of the Map interface.
It stores data as key-value pairs.
Internal Data Structure
Internally, a HashMap uses an array of buckets.
Each bucket stores one or more entries.
Each entry contains:
- Key
- Value
- Hash value
- Reference to the next node (if collision occurs)
Hashing
When a key-value pair is inserted:
- Java calls the key's
hashCode()method. - The hash code determines the bucket index.
- The entry is stored in that bucket.
Collision Handling
Sometimes two keys produce the same bucket index.
This is called a collision.
HashMap handles collisions using:
- Linked List (before Java 8)
- Balanced Tree (Red-Black Tree) (Java 8 and later, after a threshold)
This improves performance when many collisions occur.
Dynamic Resizing
As more elements are added:
- HashMap automatically increases its capacity.
- Existing entries are rehashed into the new bucket array.
This resizing is controlled by the load factor.
Performance
| Operation | Average Time Complexity |
|---|---|
| put() | O(1) |
| get() | O(1) |
| remove() | O(1) |
| Worst case | O(n) |
NULL Values
A HashMap allows:
- One
nullkey. - Multiple
nullvalues.
Example
import java.util.HashMap;
public class Example {
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<>();
map.put("apple", 10);
map.put("banana", 20);
map.put("cherry", 30);
System.out.println(map.get("apple"));
}
}
Output
10
ArrayList vs LinkedList
Both classes implement the List interface, but they use different internal data structures.
ArrayList
ArrayList stores elements in a dynamic array.
Advantages
- Fast random access.
- Less memory usage.
- Best for read-heavy applications.
LinkedList
LinkedList stores elements as doubly linked nodes.
Advantages
- Fast insertion and deletion.
- Efficient when elements are frequently added or removed.
ArrayList vs LinkedList Comparison
| Feature | ArrayList | LinkedList |
|---|---|---|
| Internal structure | Dynamic array | Doubly linked list |
| Random access | O(1) | O(n) |
| Insertion/Deletion | O(n) | O(1) (at ends or with reference) |
| Memory usage | Lower | Higher |
| Best for | Frequent reading | Frequent insertion/deletion |
Real-Life Example
ArrayList
Like books on a bookshelf.
You can directly pick any book by its position.
LinkedList
Like train coaches.
Adding or removing coaches is easy, but reaching a specific coach takes time.
Real-Time Testing Example
ArrayList
Used for storing:
- Usernames
- Passwords
- Test data
- Static configuration
LinkedList
Used for storing:
- Execution logs
- Retry steps
- Undo history
- Dynamic execution sequences
How to Make a Map Synchronized
By default, HashMap is not thread-safe.
You can make it synchronized using Collections.synchronizedMap().
Example
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class Example {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
Map<String, Integer> synchronizedMap =
Collections.synchronizedMap(map);
}
}
The returned map is thread-safe.
Important Note
When iterating over a synchronized map, you must explicitly synchronize on the map.
synchronized (synchronizedMap) {
for (Map.Entry<String, Integer> entry :
synchronizedMap.entrySet()) {
System.out.println(entry);
}
}
This prevents ConcurrentModificationException.
Real-Life Example
Imagine several people writing in a shared diary.
Only one person can write at a time to prevent overwriting each other's work.
Real-Time Testing Example
In Selenium automation frameworks, synchronized maps are often used to store:
- Environment configuration
- Parallel execution results
- Shared test data
This ensures multiple threads can safely access shared data.
Collections.synchronizedMap() vs ConcurrentHashMap
Both provide thread safety but work differently.
| Feature | Collections.synchronizedMap() | ConcurrentHashMap |
|---|---|---|
| Thread-safe | Yes | Yes |
| Locking | Entire map | Individual buckets/segments |
| Concurrency | One thread at a time | Multiple threads simultaneously |
| Performance | Lower | Higher |
Real-Life Example
synchronizedMap
Only one person can use the shared diary at a time.
ConcurrentHashMap
Multiple people can write in different sections simultaneously.
Which One Should You Use?
- Use Collections.synchronizedMap() when synchronization requirements are simple.
- Use ConcurrentHashMap for high-performance multithreaded applications.
forEach vs Iterator
Both are used for traversing collections.
forEach
Introduced in Java 8.
Uses lambda expressions for concise iteration.
Example
list.forEach(item -> System.out.println(item));
Advantages
- Simple.
- Readable.
- Less code.
Limitation
Cannot safely remove elements while iterating.
Iterator
Available since Java 1.2.
Uses:
hasNext()next()
Example
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
Advantages
- Can safely remove elements using
iterator.remove(). - More control over iteration.
forEach vs Iterator Comparison
| Feature | forEach | Iterator |
|---|---|---|
| Introduced | Java 8 | Java 1.2 |
| Syntax | Lambda expression | hasNext() and next() |
| Remove elements | ❌ No | ✅ Yes |
| Readability | Cleaner | More verbose |
Real-Life Example
forEach
A teacher gives instructions to every student at once.
Iterator
A teacher checks each student individually and removes absent students from the attendance list.
Real-Time Testing Example
forEach
Useful for:
- Printing test results.
- Logging execution details.
Iterator
Useful for:
- Removing failed test cases.
- Filtering test data while iterating.
Try It: The Differences in One Program
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class CollectionsDemo {
public static void main(String[] args) {
List<String> tests = List.of("Login", "Search", "Checkout", "Login", "Cart");
System.out.println("HashSet: " + new HashSet<>(tests)); // no guaranteed order
System.out.println("LinkedHashSet: " + new LinkedHashSet<>(tests)); // insertion order
System.out.println("TreeSet: " + new TreeSet<>(tests)); // sorted
Map<String, String> config = new HashMap<>();
config.put(null, "default"); // one null key is allowed
config.put("browser", null); // null values are allowed
System.out.println("HashMap: " + config.get(null) + ", browser=" + config.get("browser"));
try {
new ConcurrentHashMap<String, String>().put("browser", null);
} catch (NullPointerException e) {
System.out.println("ConcurrentHashMap rejects null keys/values: NullPointerException");
}
List<String> results = new ArrayList<>(List.of("PASS", "FAIL", "PASS", "FAIL"));
try {
for (String r : results) if (r.equals("FAIL")) results.remove(r); // modifying inside for-each
} catch (ConcurrentModificationException e) {
System.out.println("for-each + remove: ConcurrentModificationException");
}
results = new ArrayList<>(List.of("PASS", "FAIL", "PASS", "FAIL"));
Iterator<String> it = results.iterator();
while (it.hasNext()) if (it.next().equals("FAIL")) it.remove(); // safe
System.out.println("Iterator.remove: " + results);
results = new ArrayList<>(List.of("PASS", "FAIL", "PASS", "FAIL"));
results.removeIf(r -> r.equals("FAIL")); // simplest (Java 8+)
System.out.println("removeIf: " + results);
}
}
Output (compiled and run with Java 21):
HashSet: [Checkout, Search, Login, Cart]
LinkedHashSet: [Login, Search, Checkout, Cart]
TreeSet: [Cart, Checkout, Login, Search]
HashMap: default, browser=null
ConcurrentHashMap rejects null keys/values: NullPointerException
for-each + remove: ConcurrentModificationException
Iterator.remove: [PASS, PASS]
removeIf: [PASS, PASS]
What the run proves:
- Order: all three sets dropped the duplicate "Login", but only
LinkedHashSetkept insertion order and onlyTreeSetsorted.HashSet's order is an implementation detail — never assert on it in a test. - Nulls:
HashMapaccepts a null key and null values;ConcurrentHashMapthrowsNullPointerException— something to know before swapping one for the other in a parallel framework. - Removing while iterating: removing inside a for-each loop threw
ConcurrentModificationException;Iterator.remove()andremoveIf()did it safely.
Step through the loop and watch the list change in the Java Code Visualizer. How collections are used across a real framework: Collections in Your Automation Framework.
From Real Projects
Java has been the language of every automation framework I've worked with — Selenium, TestNG, POM classes and Apache POI for Excel data. Interviews for automation roles regularly include basic programs like this one, often followed by a question on OOP concepts. Practice writing it by hand and explaining how you'd test it. On Canolog, the many forms and screens across sales, inventory, finance and service are where keeping page details in POM classes and reusable steps in a business library paid off. Choose the collection by what you need: order, uniqueness or fast lookup by key.
📚 Official documentation: Oracle Java Tutorials: Collections
Thread-Safe Sets in Java (Concurrent Sets)
HashSet isn't thread-safe: two threads adding at once can lose entries or corrupt the set. That matters in test frameworks that run in parallel, for example when collecting failed test names or created test-data IDs from several threads. Java has no ConcurrentHashSet class, but there are four good options:
| Option | Ordering | Best for |
|---|---|---|
ConcurrentHashMap.newKeySet() | None | The default choice: fast, many threads reading and writing |
Collections.synchronizedSet(new HashSet<>()) | None | Simple cases with little contention; you must still lock manually while iterating |
CopyOnWriteArraySet | Insertion order | Small sets that are read far more often than they change |
ConcurrentSkipListSet | Sorted | When you need sorted elements and thread safety |
// Collect IDs of orders created by parallel tests, then clean them up once
private static final Set<String> createdOrderIds = ConcurrentHashMap.newKeySet();
@Test
public void placeOrder() {
String id = api.createOrder(sampleOrder());
createdOrderIds.add(id); // safe from any thread
}
@AfterSuite
public void cleanUp() {
createdOrderIds.forEach(api::deleteOrder);
}
FAQs
1. What Is the Set Interface Used For?
The Set interface stores unique elements and does not allow duplicates.
Common implementations include:
HashSetLinkedHashSetTreeSet
2. How Does a HashMap Work Internally?
A HashMap stores key-value pairs in an array of buckets.
- The key's
hashCode()determines the bucket. - Collisions are handled using a linked list or a balanced tree (Java 8+).
- It automatically resizes based on the load factor.
- It allows one
nullkey and multiplenullvalues.
3. What Is the Difference Between ArrayList and LinkedList?
- ArrayList uses a dynamic array and provides fast random access.
- LinkedList uses doubly linked nodes and provides faster insertion and deletion.
4. How Do You Make a Map Synchronized?
Wrap the map using Collections.synchronizedMap().
While iterating, synchronize on the map inside a synchronized block to avoid ConcurrentModificationException.
5. What Is the Difference Between Collections.synchronizedMap() and ConcurrentHashMap?
Collections.synchronizedMap()locks the entire map, allowing only one thread at a time.ConcurrentHashMaplocks only portions of the map, allowing multiple threads to work concurrently with better performance.
6. What Is the Difference Between forEach and Iterator?
- forEach (Java 8) uses lambda expressions and is concise but cannot remove elements during iteration.
- Iterator (Java 1.2) provides explicit control over iteration and supports safe element removal using
iterator.remove().
7. What is a concurrent set in Java?
A Set that several threads can use at the same time without corrupting it. The usual choice is ConcurrentHashMap.newKeySet(); CopyOnWriteArraySet and ConcurrentSkipListSet cover read-heavy and sorted cases.
8. Is there a ConcurrentHashSet in Java?
No such class exists. Use ConcurrentHashMap.newKeySet(), which returns a thread-safe Set backed by a ConcurrentHashMap.