The Java Collections Framework (JCF) is an important part of Java programming. It provides a set of interfaces and classes that help developers store, manage, search, sort, and manipulate groups of objects efficiently.
Instead of working with fixed-size arrays, we can use collections that provide dynamic storage and various data management capabilities.
In this tutorial, we will understand six important Java collections with real-world examples.
1. ArrayList – Store Duplicate Elements with Index-Based Access
What is ArrayList?
ArrayList is a resizable array implementation of the List interface.
It allows duplicate elements and maintains insertion order. We can access and update elements using their index.
Real-world example: Shopping Cart
Imagine an e-commerce application where a customer adds products to a shopping cart. A customer can add the same product multiple times.
Java Example
import java.util.*;
public class Main {
public static void main(String[] args) {
ArrayList<String> cart = new ArrayList<>();
cart.add("Laptop");
cart.add("Mobile");
cart.add("Laptop");
cart.add("Keyboard");
// Display all products
System.out.println(cart);
// Access using index
System.out.println(cart.get(0));
// Update product
cart.set(1, "iPhone");
// Remove product using index
cart.remove(2);
System.out.println(cart);
}
}
Output:
[Laptop, Mobile, Laptop, Keyboard]
Laptop
[Laptop, iPhone, Keyboard]
Important Features:
- Allows duplicate elements.
- Maintains insertion order.
- Supports index-based access.
- Dynamic in size.
- Fast random access by index.
When should we use ArrayList?
Use ArrayList when you need to store multiple elements, allow duplicates, and access elements using their index.
2. HashSet – Store Unique Elements
What is HashSet?
HashSet is an implementation of the Set interface. It stores unique elements and does not allow duplicates.
It does not guarantee insertion order.
Real-world example: Unique Email Registrations
Imagine a website where users register using their email addresses. We don’t want duplicate email addresses in our collection.
Java Example
import java.util.*;
public class Main {
public static void main(String[] args) {
HashSet<String> emails = new HashSet<>();
emails.add("amit@gmail.com");
emails.add("rahul@gmail.com");
emails.add("amit@gmail.com");
emails.add("priya@gmail.com");
// Display emails
System.out.println(emails);
// Check whether email exists
System.out.println(
emails.contains("amit@gmail.com")
);
}
}
Possible Output:
[rahul@gmail.com, amit@gmail.com, priya@gmail.com]
true
Important Features:
- Does not allow duplicate elements.
- Does not guarantee insertion order.
- Does not support index-based access.
- Uses hashing internally.
- Allows one null element.
When should we use HashSet?
Use HashSet when you want to maintain a collection of unique elements, such as email addresses, employee IDs, or product categories.
3. HashMap – Store Data in Key-Value Pairs
What is HashMap?
HashMap is an implementation of the Map interface. It stores data in key-value pairs.
Each key must be unique, but multiple keys can have the same value.
Real-world example: Employee Database
Imagine an application where each employee has a unique employee ID and an employee name.
We can use the employee ID as the key and the employee name as the value.
Java Example
import java.util.*;
public class Main {
public static void main(String[] args) {
HashMap<Integer, String> employees =
new HashMap<>();
employees.put(101, "Amit");
employees.put(102, "Rahul");
employees.put(103, "Priya");
// Get employee using ID
System.out.println(employees.get(102));
// Add new employee
employees.put(104, "Neha");
// Update employee
employees.put(102, "Rahul Sharma");
// Display all employees
System.out.println(employees);
}
}
Output:
Rahul
{101=Amit, 102=Rahul Sharma, 103=Priya, 104=Neha}
Important Features:
- Stores data in key-value pairs.
- Keys must be unique.
- Values can be duplicated.
- Does not guarantee insertion order.
- Allows one null key and multiple null values.
When should we use HashMap?
Use HashMap when you want to retrieve information using a unique key, such as employee ID, product ID, customer ID, or username.
4. TreeMap – Store Key-Value Pairs in Sorted Order
What is TreeMap?
TreeMap is an implementation of the NavigableMap interface. It stores key-value pairs and automatically sorts entries based on their keys.
By default, keys are sorted in ascending natural order.
Real-world example: Student Records
Imagine a college application where student records should be displayed in ascending order of roll numbers.
Java Example
import java.util.*;
public class Main {
public static void main(String[] args) {
TreeMap<Integer, String> students =
new TreeMap<>();
students.put(105, "Amit");
students.put(102, "Rahul");
students.put(104, "Priya");
students.put(101, "Neha");
// Display sorted student records
System.out.println(students);
}
}
Output:
{101=Neha, 102=Rahul, 104=Priya, 105=Amit}
Important Features:
- Stores key-value pairs.
- Automatically sorts keys.
- Keys must be unique.
- Does not allow null keys with natural ordering.
- Supports operations such as firstKey(), lastKey(), and higherKey().
When should we use TreeMap?
Use TreeMap when you need key-value storage and want the keys to remain sorted automatically.
5. Queue – Process Elements Using FIFO
What is Queue?
Queue is an interface in Java that follows the FIFO (First In, First Out) principle.
The element inserted first is generally the first element to be removed.
Real-world example: Bank Customer Queue
Imagine customers waiting at a bank counter. The first customer who enters the queue gets served first.
Java Example
import java.util.*;
public class Main {
public static void main(String[] args) {
Queue<String> customers =
new LinkedList<>();
customers.add("Amit");
customers.add("Rahul");
customers.add("Priya");
// Display queue
System.out.println(customers);
// Serve first customer
System.out.println(
"Serving: " + customers.poll()
);
// Display remaining customers
System.out.println(customers);
}
}
Output:
[Amit, Rahul, Priya]
Serving: Amit
[Rahul, Priya]
Important Queue Methods:
| Method | Description |
|---|---|
| add() | Inserts an element |
| offer() | Inserts an element |
| poll() | Removes and returns the head |
| peek() | Returns the head without removing it |
| remove() | Removes the head or throws an exception if empty |
Important Features:
- Follows FIFO in a normal FIFO queue.
- Useful for task processing.
- Supports different implementations such as LinkedList and PriorityQueue.
When should we use Queue?
Use Queue when tasks or requests need to be processed in arrival order, such as ticket booking, printer jobs, and customer support requests.
6. ConcurrentHashMap – Thread-Safe Key-Value Storage
What is ConcurrentHashMap?
ConcurrentHashMap is a thread-safe implementation of the ConcurrentMap interface.
It is designed for applications where multiple threads need to access and modify a shared key-value map concurrently.
Real-world example: Multiple Users Updating Login Counters
Imagine an application where multiple threads update the login count of the same employee.
Using a normal HashMap without synchronization can cause concurrency problems.
ConcurrentHashMap provides thread-safe operations for this type of scenario.
Java Example
import java.util.concurrent.*;
public class Main {
public static void main(String[] args) {
ConcurrentHashMap<Integer, Integer> loginCount =
new ConcurrentHashMap<>();
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
loginCount.merge(
101,
1,
Integer::sum
);
}
};
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println(loginCount);
}
}
Output:
{101=2000}
Important Features:
- Supports concurrent access by multiple threads.
- Provides thread-safe operations.
- Does not allow null keys or null values.
- Provides better concurrency than a synchronized HashMap for many workloads.
- Supports atomic operations such as putIfAbsent() and merge().
When should we use ConcurrentHashMap?
Use ConcurrentHashMap when multiple threads need to read and update a shared key-value map safely.
Java Collections Quick Comparison
| Collection | Main Purpose | Duplicates | Ordering |
|---|---|---|---|
| ArrayList | Index-based storage | Allowed | Insertion order |
| HashSet | Unique elements | Not allowed | No guaranteed order |
| HashMap | Key-value storage | Unique keys | No guaranteed order |
| TreeMap | Sorted key-value storage | Unique keys | Sorted keys |
| Queue | FIFO processing | Generally allowed | Processing order |
| ConcurrentHashMap | Concurrent key-value storage | Unique keys | No guaranteed order |
How to Choose the Right Collection?
Remember these practical scenarios:
- Need duplicates and index-based access? Use ArrayList.
- Need unique elements? Use HashSet.
- Need key-value storage? Use HashMap.
- Need sorted keys? Use TreeMap.
- Need FIFO processing? Use Queue.
- Need thread-safe concurrent key-value access? Use ConcurrentHashMap.
Practice Assignments for Students
Try implementing the following scenarios using the appropriate Java collection.
- Create a shopping cart that allows duplicate products.
- Create a collection of unique email addresses.
- Store employee IDs and employee names.
- Store student records sorted by roll number.
- Implement a bank customer waiting queue.
- Create a login counter updated by multiple threads using ConcurrentHashMap.
Conclusion
Java Collections Framework makes it easier to manage data in Java applications.
Understanding when to use ArrayList, HashSet, HashMap, TreeMap, Queue, and ConcurrentHashMap is essential for every Java developer.
Instead of memorizing collection classes, focus on understanding their behavior, internal working, performance characteristics, and real-world use cases.