A Beginner's Guide to Java Collections


Hey everyone! If you're starting your journey with Java, you've probably heard about the Java Collections Framework (JCF). It sounds complex, but it's one of the most powerful and essential parts of Java. Its job is to give you a bunch of tools to store and manage groups of objects efficiently.
But what's the best way to understand it? Let's forget the complicated jargon for a minute and think about something we all know: school.
Imagine you're the principal of a school, and you need to manage all your students, classes, and records. You wouldn't use the same method for everything, right?
A
List
is like your daily attendance register. It's an ordered list of students. You can have two students named 'Rahul' (duplicates are allowed), and you know who is at roll number 1, 5, or 20 (it's ordered by an index).A
Queue
is like the line for the school canteen. The student who gets in line first is the first one to get their food (First-In, First-Out).A
Set
is like the list of unique house teams (e.g., Red, Blue, Green, Yellow). You can't have 'Blue' house listed twice. Itβs a collection of unique items.A
Map
is like a student's report card. It connects a unique key (the subject, like 'Maths') to a value (the marks, like 95).
Throughout this guide, we'll keep coming back to this simple analogy to understand how each part of the Java Collections Framework works.
1. The List
Interface: The Attendance Register π
A List
is an ordered collection that allows duplicate elements. It's your go-to when you need to control the position of elements and access them by their number in the list (their index).
ArrayList
An ArrayList
is like a standard student roster written on a sheet of paper.
Theory: It uses a dynamic array in the background. This makes it super fast to find a student if you know their roll number (getting an element by index), which takes O(1) time. However, if a new student joins in the middle, you have to erase and shift all the students below them, which is slow (O(n)).
Best For: When you need to read data frequently and don't have too many additions or removals.
Java
// Create an ArrayList
List<Integer> al = new ArrayList<>();
// Add elements
al.add(4); // Appends 4 to the end -> [4]
al.add(40); // Appends 40 to the end -> [4, 40]
al.add(1, 33); // Inserts 33 at index 1 -> [4, 33, 40]
System.out.println(al); // Output: [4, 33, 40]
LinkedList
A LinkedList
is like a chain of students holding hands.
Theory: Each student (or "node") only knows who is in front of them and who is behind them. This makes it very easy for a new student to join or leave the middle of the chainβthey just need to grab or let go of hands. This is very fast (O(1)). But, to find the 10th student, you have to start from the beginning and count one by one, which is slow (O(n)).
Best For: When you have a lot of additions and removals in your list.
Java
// Create a LinkedList
List<Integer> ll = new LinkedList<>();
// Operations are the same as ArrayList
ll.add(4);
ll.add(40);
ll.add(2, 33); // Inserts 33 at index 2 -> [4, 40, 33]
System.out.println(ll); // Output: [4, 40, 33]
Stack
A Stack
is like a stack of notebooks on a desk. You can only take the top one.
Theory: It follows a Last-In, First-Out (LIFO) principle. The last book you put on the stack is the first one you remove. The main operations are
push()
(add to top),pop()
(remove from top), andpeek()
(look at the top item).Modern Practice: While
Stack
works, it's an older class. For stack operations today, it's better to use anArrayDeque
.
Java
Stack<Integer> s = new Stack<>();
s.push(1);
s.push(2); // 2 is now at the top
System.out.println("Stack: " + s); // Output: [1, 2]
System.out.println("Top of Stack: " + s.peek()); // Output: 2
2. The Queue
Interface: The Canteen Line πΆββοΈπΆββοΈπΆββοΈπΆββοΈπΆββοΈ
A Queue
is used to hold elements before you process them. Usually, this is done in a First-In, First-Out (FIFO) manner, just like a line.
PriorityQueue
This is not your normal queue; it's a VIP queue.
Theory: Instead of being strictly FIFO, elements are ordered based on priority. By default, the smallest element gets the highest priority (this is called a min-heap). Imagine a younger student being allowed to get their food first. You can change this to a max-heap (where the largest element gets priority) if you need to.
Performance: Adding and removing elements takes O(logn) time.
Java
// Min-Heap (smallest element has priority)
Queue<Integer> pq = new PriorityQueue<>();
pq.offer(10);
pq.offer(40);
pq.offer(5); // 5 is the highest priority
System.out.println("Min-Heap: " + pq); // Output: [5, 40, 10]
System.out.println("Head of queue is: " + pq.peek()); // Output: 5
// Max-Heap (largest element has priority)
Queue<Integer> pqMax = new PriorityQueue<>(Comparator.reverseOrder());
pqMax.offer(10);
pqMax.offer(40);
pqMax.offer(5); // 40 is the highest priority
System.out.println("Max-Heap: " + pqMax); // Output: [40, 10, 5]
System.out.println("Head of queue is: " + pqMax.peek()); // Output: 40
ArrayDeque
This is a "double-ended" queue, like a line where people can join or leave from both the front and the back.
Theory:
ArrayDeque
(Array Double Ended Queue) is super versatile. Because you can add or remove from both ends, it can act as a normal queue (FIFO) or a stack (LIFO). It's faster and more efficient than the olderStack
andLinkedList
classes for these jobs.Performance: Adding or removing from either end takes O(1) time on average.
Java
ArrayDeque<Integer> ad = new ArrayDeque<>();
ad.offer(20); // Adds to the end -> [20]
ad.offerFirst(10); // Adds to the front -> [10, 20]
ad.offerLast(30); // Adds to the end -> [10, 20, 30]
System.out.println(ad); // Output: [10, 20, 30]
ad.pollFirst(); // Removes from front -> [20, 30]
System.out.println(ad); // Output: [20, 30]
3. The Set
Interface: The Unique House Teams π
A Set
is a collection that holds no duplicate elements. Itβs perfect when you just need to store unique items and don't care about their order.
HashSet
Stores items in a hash table. Think of it as throwing all the unique house names into a big, unorganized box.
Theory: It's extremely fast because it uses a technique called hashing to store items. The downside? There are no guarantees about the order of the elements.
Performance: O(1) average time for adding, removing, and checking if an item exists.
LinkedHashSet
This is like HashSet
, but it also remembers the order you added the items in.
Theory: It combines the speed of a hash table with the predictability of a linked list. The elements will always be in insertion order.
Performance: Almost as fast as
HashSet
.
TreeSet
This keeps the elements sorted at all times.
Theory: It stores elements in a special tree structure (a Red-Black Tree) that automatically keeps them in sorted order.
Performance: A bit slower than
HashSet
, with O(logn) time for adding, removing, and checking for items.
Java
Set<Integer> hs = new HashSet<>(); // Unordered
hs.add(30); hs.add(10); hs.add(50); hs.add(20);
System.out.println("HashSet (Unordered): " + hs);
Set<Integer> lhs = new LinkedHashSet<>(); // Insertion Order
lhs.add(30); lhs.add(10); lhs.add(50); lhs.add(20);
System.out.println("LinkedHashSet (Insertion Order): " + lhs);
Set<Integer> ts = new TreeSet<>(); // Sorted Order
ts.add(30); ts.add(10); ts.add(50); ts.add(20);
System.out.println("TreeSet (Sorted Order): " + ts);
4. The Map
Interface: The Report Card π
A Map
is an object that stores key-value pairs. Just like a report card maps a subject (key) to marks (value), a Map
links a unique key to a specific value. Keys must be unique.
HashMap
The fastest type of map, but it makes no promises about order.
Theory: It uses the key's hash code to store the key-value pair. It's unordered. If you add a new value with an existing key, the old value gets replaced.
Performance: O(1) average time to get or put a value.
LinkedHashMap
This is a HashMap
that also remembers the order in which you inserted the items.
Theory: It maintains insertion order, so when you iterate through it, the elements appear in the same sequence you added them.
Performance: Nearly as fast as
HashMap
.
TreeMap
This map keeps its entries sorted by the key.
Theory: It stores the key-value pairs in a tree structure, ensuring the map is always sorted by its keys.
Performance: O(logn) time for getting, putting, and removing entries.
Java
// Unordered
Map<Integer, String> hm = new HashMap<>();
hm.put(1, "Dad");
hm.put(55, "Son");
hm.put(2, "Mother");
System.out.println("HashMap (Unordered): " + hm);
// Insertion Order
Map<Integer, String> lhm = new LinkedHashMap<>();
lhm.put(1, "Dad");
lhm.put(55, "Son");
lhm.put(2, "Mother");
System.out.println("LinkedHashMap (Insertion Order): " + lhm);
// Sorted by key
Map<Integer, String> tm = new TreeMap<>();
tm.put(1, "Dad");
tm.put(55, "Son");
tm.put(2, "Mother");
System.out.println("TreeMap (Sorted by Key): " + tm);
Final Thoughts
And that's it! The Java Collections Framework is all about choosing the right tool for the job. By remembering our school analogy, you can easily decide which collection you need:
Need an ordered list with duplicates? Use a
List
.Need a First-In, First-Out queue? Use a
Queue
.Need to store unique items? Use a
Set
.Need to link unique keys to values? Use a
Map
.
Subscribe to my newsletter
Read articles from Sambhav Rana directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by