import java.util.HashSet;
HashSet<String> languages = new HashSet<>();
languages.add("Java");
languages.add("Python");
languages.add("Java");
System.out.println(languages);Java HashSet and LinkedHashSet: Unique Elements and Ordering
Direct Answer & Core Concept
HashSet and LinkedHashSet are Java collection classes used when you need a set of unique elements. Unlike a List, a set does not allow duplicate elements.
Both classes are part of the Java Collections Framework and implement the Set interface. HashSet focuses on efficient hash-based storage without guaranteeing iteration order, while LinkedHashSet additionally preserves insertion order.
Understanding the difference between these two collections is important when choosing the right data structure for storing unique values.
Detailed Explanation & Mechanics
What Is HashSet in Java?
HashSet is a collection class from the java.util package that stores unique elements using hashing.
Example:
The second "Java" is not added because sets do not store duplicates.
The exact printed order should not be relied upon with HashSet.
What Is LinkedHashSet in Java?
LinkedHashSet is a subclass of HashSet that maintains a linked structure alongside its hash table so that iteration normally follows insertion order.
Example:
import java.util.LinkedHashSet;
LinkedHashSet<String> languages = new LinkedHashSet<>();
languages.add("Java");
languages.add("Python");
languages.add("C++");
System.out.println(languages);Output:
[Java, Python, C++]If you add a duplicate:
languages.add("Java");the existing element remains in its original position.
HashSet vs LinkedHashSet
The main difference is ordering.
| Feature | HashSet | LinkedHashSet |
|---|---|---|
| Allows duplicates | No | No |
| Hash-based | Yes | Yes |
| Preserves insertion order | No guarantee | Yes |
null | Allows one | Allows one |
| Average basic operations | Typically O(1) | Typically O(1) |
| Extra ordering structure | No | Yes |
| Memory overhead | Generally lower | Generally higher |
The complexity values are typical rather than absolute guarantees for every implementation or workload.
Importing HashSet
Use:
import java.util.HashSet;Then create a set:
HashSet<String> names = new HashSet<>();A more flexible declaration is:
Set<String> names = new HashSet<>();This programs to the Set interface.
Importing LinkedHashSet
Use:
import java.util.LinkedHashSet;Example:
LinkedHashSet<String> names = new LinkedHashSet<>();Or:
Set<String> names = new LinkedHashSet<>();The second form makes it easier to change the implementation later.
Creating a HashSet
The basic syntax is:
HashSet<Type> set = new HashSet<>();For strings:
HashSet<String> names = new HashSet<>();For integers:
HashSet<Integer> numbers = new HashSet<>();Java collections store objects, so wrapper types such as Integer are used instead of primitive int.
Creating a LinkedHashSet
The syntax is similar:
LinkedHashSet<Type> set = new LinkedHashSet<>();Example:
LinkedHashSet<String> cities = new LinkedHashSet<>();
cities.add("Kolkata");
cities.add("Delhi");
cities.add("Mumbai");
System.out.println(cities);Output:
[Kolkata, Delhi, Mumbai]The insertion sequence is preserved during iteration.
Adding Elements to HashSet
Use the add() method.
HashSet<String> fruits = new HashSet<>();
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Mango");You can print the set:
System.out.println(fruits);Unlike ArrayList, you should not expect a predictable iteration order.
Duplicate Elements in HashSet
One of the most important properties of a set is that duplicate elements are not stored.
HashSet<String> names = new HashSet<>();
names.add("Amit");
names.add("Rahul");
names.add("Amit");
System.out.println(names);The set contains only:
AmitRahulThe order shown by a HashSet is not guaranteed.
Checking Whether an Element Was Added
The add() method returns a boolean.
It returns true when the set changes because the element was added.
HashSet<String> names = new HashSet<>();
System.out.println(names.add("Amit"));Output:
trueAdding the same element again:
System.out.println(names.add("Amit"));Output:
falseThis makes add() useful when you need to know whether a value was already present.
How HashSet Detects Duplicates
Hash-based sets use an object's hashCode() and equals() behavior to determine whether elements should be treated as duplicates.
Conceptually:
New object↓hashCode()↓Find possible location↓equals()↓Duplicate or new element?A matching hash code alone is not enough to establish that two objects are equal.
The equals() method is also important.
hashCode() and equals()
For objects used in a HashSet, the equals() and hashCode() contract matters.
If two objects are considered equal according to equals(), they must return the same hash code.
For example:
class User {
private int id;
User(int id) {
this.id = id;
} @Override public boolean equals(Object obj) {
if (this == obj) {
return true;
} if (!(obj instanceof User)) {
return false;
} User other =(User) obj;
return id == other.id;
} @Override public int hashCode() {
return Integer.hashCode(id);
}
}Now two User objects with the same ID can be treated as equal by hash-based collections.
Why equals() and hashCode() Must Agree
Suppose:
User user1 = new User(101);
User user2 = new User(101);If:
user1.equals(user2)returns true, both objects must have the same hash code.
Otherwise, a HashSet can behave incorrectly because hash-based lookup relies on the contract between these methods.
This is one of the most important rules when storing custom objects in HashSet.
HashSet and null
A HashSet can contain one null element.
Example:
HashSet<String> values = new HashSet<>();
values.add("Java");
values.add(null);
values.add("Python");
values.add(null);
System.out.println(values);Only one null can exist because a set does not allow duplicates.
LinkedHashSet and null
LinkedHashSet can also contain one null element.
LinkedHashSet<String> values = new LinkedHashSet<>();
values.add("Java");
values.add(null);
values.add("Python");
values.add(null);
System.out.println(values);The duplicate null is ignored.
Checking Whether an Element Exists
Use:
contains()Example:
HashSet<String> languages = new HashSet<>();
languages.add("Java");
languages.add("Python");
System.out.println(languages.contains("Java"));Output:
trueIf the element does not exist:
System.out.println(languages.contains("PHP"));Output:
falseHash-based lookup is typically O(1) on average.
Removing an Element
Use:
remove()Example:
HashSet<String> languages = new HashSet<>();
languages.add("Java");
languages.add("Python");
languages.add("C++");
languages.remove("Python");
System.out.println(languages);The "Python" element is removed.
The remove() method returns true if the set contained the specified element and it was removed.
Checking the Size
Use:
size()Example:
HashSet<String> names = new HashSet<>();
names.add("Amit");
names.add("Rahul");
names.add("Priya");
System.out.println(names.size());Output:
3Duplicates do not increase the size.
Checking Whether a Set Is Empty
Use:
isEmpty()Example:
HashSet<String> names = new HashSet<>();
System.out.println(names.isEmpty());Output:
trueAfter adding an element:
names.add("Amit");
System.out.println(names.isEmpty());Output:
falseClearing a HashSet
The clear() method removes every element.
HashSet<String> names = new HashSet<>();
names.add("Amit");
names.add("Rahul");
names.clear();
System.out.println(names);Output:
[]The set becomes empty.
Iterating Through HashSet
You can use an enhanced for loop:
HashSet<String> languages = new HashSet<>();
languages.add("Java");
languages.add("Python");
languages.add("C++");
for (String language : languages) {
System.out.println(language);
}Remember that the iteration order of a HashSet is not guaranteed.
Therefore, do not write application logic that depends on the order in which elements happen to be returned.
Iterating Through LinkedHashSet
The same loop can be used:
LinkedHashSet<String> languages = new LinkedHashSet<>();
languages.add("Java");
languages.add("Python");
languages.add("C++");
for (String language : languages) {
System.out.println(language);
}Iteration follows insertion order.
Output:
JavaPythonC++HashSet and LinkedHashSet with Integer Values
Sets work with numeric wrapper classes too.
HashSet<Integer> numbers = new HashSet<>();
numbers.add(10);
numbers.add(20);
numbers.add(10);
numbers.add(30);
System.out.println(numbers);The duplicate 10 is ignored.
With LinkedHashSet:
LinkedHashSet<Integer> numbers = new LinkedHashSet<>();
numbers.add(30);
numbers.add(10);
numbers.add(20);
numbers.add(10);
System.out.println(numbers);The iteration order is:
301020The duplicate 10 does not create another entry.
Removing Duplicates from a List
One common use of HashSet is removing duplicates from a list.
Suppose you have:
List<String> names = new ArrayList<>();
names.add("Amit");
names.add("Rahul");
names.add("Amit");
names.add("Priya");You can create a set:
Set<String> uniqueNames = new HashSet<>(names);Now only unique values remain.
However, because HashSet does not guarantee order, the original list order should not be relied upon.
If you want to remove duplicates while preserving the original insertion order, use LinkedHashSet:
Set<String> uniqueNames = new LinkedHashSet<>(names);This is a very common practical use case.
Example: Remove Duplicates While Preserving Order
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
public class Main {
public static void main(String[] args) {
List<String> names = new ArrayList<>();
names.add("Amit");
names.add("Rahul");
names.add("Amit");
names.add("Priya");
names.add("Rahul");
Set<String> uniqueNames = new LinkedHashSet<>(names);
System.out.println(uniqueNames);
}
}Output:
[Amit, Rahul, Priya]The duplicates are removed while the first-seen order is preserved.
HashSet vs LinkedHashSet Ordering
Consider the same values:
"Java""Python""C++""JavaScript"With HashSet:
Set<String> set = new HashSet<>();you must not depend on iteration order.
With LinkedHashSet:
Set<String> set = new LinkedHashSet<>();iteration follows the insertion sequence.
This difference is the primary reason to choose LinkedHashSet over HashSet.
LinkedHashSet and Reinserting an Element
Suppose:
LinkedHashSet<String> languages = new LinkedHashSet<>();
languages.add("Java");
languages.add("Python");
languages.add("C++");Now add "Java" again:
languages.add("Java");The set still contains:
[Java, Python, C++]The existing element is not moved to the end.
LinkedHashSet preserves insertion order of the elements that are present; adding an already-present element does not create a new insertion.
HashSet Performance
Typical average-case complexity for basic hash-based operations is:
| Operation | Average Complexity |
|---|---|
add() | O(1) |
remove() | O(1) |
contains() | O(1) |
size() | O(1) |
Worst-case behavior can differ depending on hashing, collisions, implementation details, and workload.
Do not treat O(1) as a guarantee that every operation always takes exactly the same amount of time.
LinkedHashSet Performance
LinkedHashSet provides similar typical average-case performance for basic set operations:
| Operation | Average Complexity |
|---|---|
add() | O(1) |
remove() | O(1) |
contains() | O(1) |
size() | O(1) |
| Iteration | O(n) |
It requires additional memory to maintain insertion-order information.
Therefore, if ordering is unnecessary, HashSet can be a simpler choice.
HashSet vs ArrayList
HashSet and ArrayList solve different problems.
| Feature | ArrayList | HashSet |
|---|---|---|
| Duplicates | Allowed | Not allowed |
| Insertion order | Preserved | No guarantee |
| Index-based access | Yes | No |
contains() | Typically O(n) | Typically O(1) average |
Allows null | Yes | Yes |
| Main purpose | Ordered sequence | Unique elements |
Use ArrayList when order and index access matter.
Use HashSet when uniqueness and fast membership testing matter.
LinkedHashSet vs ArrayList
LinkedHashSet is useful when you need both:
Unique elements
Predictable insertion-order iteration
For example:
LinkedHashSet<String> visitedPages = new LinkedHashSet<>();This can represent unique pages while preserving the order in which they were first encountered.
HashSet vs TreeSet
Another important comparison is TreeSet.
| Feature | HashSet | LinkedHashSet | TreeSet |
|---|---|---|---|
| Unique values | Yes | Yes | Yes |
| Hash-based | Yes | Yes | No |
| Insertion order | No guarantee | Yes | No |
| Sorted order | No | No | Yes |
| Typical basic operation | O(1) average | O(1) average | O(log n) |
| Main purpose | Fast uniqueness | Uniqueness + insertion order | Sorted uniqueness |
If you need sorted elements, TreeSet is usually the relevant collection.
Set Interface
Both classes implement the Set interface.
This means you can write:
Set<String> names = new HashSet<>();or:
Set<String> names = new LinkedHashSet<>();The variable is declared using the interface while the object specifies the implementation.
This is an example of programming to an interface.
Common Set Operations
Java provides useful set operations through the Set interface.
Suppose:
Set<String> first = new HashSet<>();
first.add("Java");
first.add("Python");
first.add("C++");
Set<String> second = new HashSet<>();
second.add("Python");
second.add("JavaScript");Union
Add all elements from the second set:
Set<String> union = new HashSet<>(first);
union.addAll(second);Result:
JavaPythonC++JavaScriptThe exact display order for HashSet is unspecified.
Intersection
Keep only elements found in both sets:
Set<String> intersection = new HashSet<>(first);
intersection.retainAll(second);Result:
PythonDifference
Remove elements found in another set:
Set<String> difference = new HashSet<>(first);
difference.removeAll(second);Result:
JavaC++These operations are useful when comparing groups of unique values.
Checking Whether One Set Contains Another
You can use:
containsAll()Example:
Set<String> required = new HashSet<>();
required.add("Java");
required.add("Python");
Set<String> available = new HashSet<>();
available.add("Java");
available.add("Python");
available.add("C++");
System.out.println(available.containsAll(required));Output:
trueHashSet with Custom Objects
Consider a Student class:
class Student {
private int id;
private String name;
Student(int id, String name) {
this.id = id;
this.name = name;
}
}You can store students:
HashSet<Student> students = new HashSet<>();
students.add(new Student(101, "Amit"));
students.add(new Student(102, "Rahul"));If you want the set to recognize students according to their IDs, you need to implement equals() and hashCode() based on the desired identity.
A Practical Custom Object Example
import java.util.HashSet;
import java.util.Set;
import java.util.Objects;
class Product {
private int id;
private String name;
Product(int id, String name) {
this.id = id;
this.name = name;
} @Override public boolean equals(Object obj) {
if (this == obj) {
return true;
} if (!(obj instanceof Product)) {
return false;
} Product other =(Product) obj;
return id == other.id;
} @Override public int hashCode() {
return Objects.hash(id);
}
}public class Main {
public static void main(String[] args) {
Set<Product> products = new HashSet<>();
products.add(new Product(101, "Laptop"));
products.add(new Product(101, "Laptop"));
System.out.println(products.size());
}
}Output:
1Both objects have the same logical ID, so the set treats them as equal.
Mutable Objects and HashSet
Be careful when using mutable objects as keys or set elements.
Suppose an object's fields used by equals() and hashCode() are changed after the object has been inserted into a HashSet.
The object may no longer be found correctly.
For example, conceptually:
Insert object↓Hash calculated↓Object stored↓Identity field changes↓New hash calculated↓contains() may failFor this reason, fields involved in equality and hashing should generally not be changed while an object is being used as a hash-based collection element.
HashSet and Thread Safety
HashSet is not synchronized by default.
If multiple threads access and modify a shared set concurrently, use an appropriate concurrency strategy.
For example, depending on requirements, a concurrent set can be created using:
Set<String> names = ConcurrentHashMap.newKeySet();Do not assume that wrapping a collection automatically makes every multi-step operation atomic.
LinkedHashSet and Thread Safety
LinkedHashSet is also not synchronized by default.
If concurrent access is required, choose a collection or synchronization strategy specifically designed for the application's concurrency requirements.
Initial Capacity and Load Factor
Hash-based collections use concepts such as:
Initial capacity
Load factor
Hash distribution
Example:
HashSet<String> names = new HashSet<>(100, 0.75f);This creates a set with an initial capacity configuration and load factor.
Most applications can use the default settings.
Custom values are mainly useful when you understand the expected data size and performance requirements.
Common HashSet Mistakes
Mistake 1: Expecting HashSet to Preserve Order
Do not write code that depends on:
HashSet<String> names = new HashSet<>();returning elements in insertion order.
If insertion order matters, consider:
LinkedHashSet<String>Mistake 2: Using a Set When Duplicates Matter
If duplicate values are meaningful, use a List instead.
For example, a list of transaction records may legitimately contain repeated values.
Mistake 3: Forgetting equals() and hashCode()
When using custom objects, correct equals() and hashCode() implementations are essential for hash-based collections.
Mistake 4: Modifying Equality Fields After Insertion
Changing fields used by equals() and hashCode() can make an object difficult to find in a hash-based collection.
Mistake 5: Assuming O(1) Means Guaranteed Constant Time
Hash-based collections provide expected average-case constant-time performance for many basic operations, but actual performance depends on hashing, collisions, implementation, and workload.
Complete HashSet Example
import java.util.HashSet;
import java.util.Set;
public class Main {
public static void main(String[] args) {
Set<String> languages = new HashSet<>();
languages.add("Java");
languages.add("Python");
languages.add("C++");
languages.add("Java");
System.out.println("Languages: " + languages);
System.out.println( "Contains Java: " + languages.contains("Java"));
languages.remove("Python");
System.out.println("After removal: " + languages);
System.out.println("Size: " + languages.size());
}
}The duplicate "Java" is ignored.
The exact printed order is not guaranteed.
Complete LinkedHashSet Example
import java.util.LinkedHashSet;
import java.util.Set;
public class Main {
public static void main(String[] args) {
Set<String> languages = new LinkedHashSet<>();
languages.add("Java");
languages.add("Python");
languages.add("C++");
languages.add("Java");
for (String language : languages) {
System.out.println(language);
}
}
}Output:
JavaPythonC++The duplicate is removed while insertion order is preserved.
Real-World Use Cases
1. Removing Duplicate User IDs
Set<Integer> userIds = new HashSet<>();Useful when you only care whether an ID has already been seen.
2. Preserving Unique Search Terms
Set<String> searchTerms = new LinkedHashSet<>();This keeps only unique terms while preserving the order in which they were first encountered.
3. Tracking Visited URLs
Set<String> visitedUrls = new HashSet<>();A crawler can use a set to quickly check whether a URL has already been processed.
4. Unique Tags
Set<String> tags = new LinkedHashSet<>();This can preserve the order of the first appearance of tags while preventing duplicates.
5. Permission Names
Set<String> permissions = new HashSet<>();A set naturally represents a collection where each permission should appear at most once.
When Should You Use HashSet?
Use HashSet when:
Duplicate values should be rejected.
You need fast average-case membership checks.
Element ordering is not important.
You frequently perform add, remove, and contains operations.
You need to represent a mathematical-style set of unique values.
Example:
Set<String> uniqueEmails = new HashSet<>();When Should You Use LinkedHashSet?
Use LinkedHashSet when:
Duplicate values should be rejected.
Insertion order matters during iteration.
You need predictable iteration order.
You are removing duplicates while preserving first-seen order.
Example:
Set<String> uniqueNames = new LinkedHashSet<>();HashSet, LinkedHashSet, and TreeSet Decision Guide
A simple decision rule is:
Need unique values? | Yes | +---- Need sorted order? | | | Yes → TreeSet | +---- Need insertion order? | | | Yes → LinkedHashSet | +---- No order requirement | HashSetThis helps you choose a set implementation based on the behavior your application actually needs.
Quick Revision
| Concept | HashSet | LinkedHashSet |
|---|---|---|
| Unique elements | Yes | Yes |
| Duplicate values | Rejected | Rejected |
| Insertion order | Not guaranteed | Preserved |
| Hash-based | Yes | Yes |
null | One allowed | One allowed |
contains() | O(1) average | O(1) average |
add() | O(1) average | O(1) average |
remove() | O(1) average | O(1) average |
| Memory usage | Generally lower | Generally higher |
| Best for | Unique values | Unique values + insertion order |
Frequently Asked Questions
What is HashSet in Java?
HashSet is a Set implementation that stores unique elements using hash-based storage.
Does HashSet allow duplicates?
No. If an equal element is already present, adding it does not change the set.
Does HashSet maintain insertion order?
No. HashSet does not guarantee a particular iteration order.
What is LinkedHashSet?
LinkedHashSet is a set implementation that prevents duplicates while maintaining insertion order during iteration.
What is the difference between HashSet and LinkedHashSet?
Both store unique values using hashing. LinkedHashSet additionally maintains insertion order, which requires extra internal bookkeeping.
Can HashSet contain null?
Yes. A HashSet can contain one null element.
Can LinkedHashSet contain null?
Yes. A LinkedHashSet can contain one null element.
Why are equals() and hashCode() important?
Hash-based collections use these methods to determine object equality and locate elements. Equal objects must have the same hash code.
Which is faster, HashSet or LinkedHashSet?
Both generally provide similar average-case complexity for basic operations. LinkedHashSet maintains additional ordering information, so HashSet may use less memory when ordering is unnecessary.
How can I remove duplicates while preserving order?
Use a LinkedHashSet:
Set<String> unique = new LinkedHashSet<>(list);Should I use HashSet or ArrayList?
Use HashSet when uniqueness and membership testing are important. Use ArrayList when ordering, duplicates, and indexed access are important.
Graphics and Design Ideas
1. HashSet Duplicate Removal
Show:
Input[Java][Python][Java][C++][Python]↓HashSet↓[Java][Python][C++]The graphic should emphasize that duplicates are automatically rejected.
2. HashSet vs LinkedHashSet
Create a side-by-side visual:
HashSetJavaC++PythonJavaScriptOrder: Not GuaranteedLinkedHashSetJava → Python → C++ → JavaScriptOrder: Insertion OrderUse different icons for uniqueness and ordering.
3. equals() + hashCode() Diagram
Show the duplicate-detection process:
New Object↓hashCode()↓Hash Location↓equals()↓Already Equal? / \ Yes No↓↓Ignore AddThis is especially useful for explaining custom objects.
4. Set Selection Decision Tree
Create a beginner-friendly visual:
Need unique values? | YES | Need a specific order? / \ No Yes↓↓HashSet What order? / \ Insertion Sorted↓↓LinkedHashSet TreeSet5. Real-World Use Case Cards
Create four visual cards:
Duplicate Removal
Remove repeated values from imported data.
Visited URLs
Track URLs that have already been processed.
Unique Tags
Store unique tags without duplicates.
Search Terms
Keep unique terms while preserving first-seen order with LinkedHashSet.
Runnable Code Example: Java HashSet and LinkedHashSet
Java 17+import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
public class SetDemo {
public static void main(String[] args) {
Set<String> hashSet = new HashSet<>();
hashSet.add("Zebra");
hashSet.add("Apple");
hashSet.add("Mango");
hashSet.add("Apple");
// Duplicate ignored
Set<String> linkedSet = new LinkedHashSet<>();
linkedSet.add("Zebra");
linkedSet.add("Apple");
linkedSet.add("Mango");
System.out.println("HashSet (Unordered, Unique): " + hashSet);
System.out.println("LinkedHashSet (Insertion Ordered): " + linkedSet);
}
}