LearnAI ToolsCareerPractice BuildsPlayContact
Lesson 2865 min read

Collections Basics in Java

Learn Java Collections from the fundamentals, including the Collection Framework, List, Set, Queue, Map, ArrayList, LinkedList, HashSet, TreeSet, PriorityQueue, HashMap, iteration, sorting, comparison, and best practices.

Introduction

Collections are one of the most important parts of Java programming. They provide ready-made data structures for storing, organizing, searching, sorting, and processing groups of objects.

Simple Collection Example
import java.util.*;
List<String> languages =
new ArrayList<>();
languages.add("Java");
languages.add("Python");
languages.add("JavaScript");
System.out.println(languages);
Output
[Java, Python, JavaScript]
What You Will Learn
  • What collections are.
  • Why collections are needed.
  • The difference between arrays and collections.
  • The Java Collections Framework.
  • The Collection interface hierarchy.
  • How generic collections work.
  • The List interface.
  • How ArrayList works.
  • How LinkedList works.
  • The difference between ArrayList and LinkedList.
  • The basics of Vector and Stack.
  • The Set interface.
  • How HashSet works.
  • How LinkedHashSet works.
  • How TreeSet works.
  • The Queue interface.
  • How PriorityQueue works.
  • The Deque interface.
  • How ArrayDeque works.
  • The Map interface.
  • How HashMap works.
  • How LinkedHashMap works.
  • How TreeMap works.
  • The basics of Hashtable.
  • How Iterator works.
  • How ListIterator works.
  • Different ways to iterate collections.
  • How to remove elements safely while iterating.
  • How the Collections utility class works.
  • How to sort collections.
  • How Comparable works.
  • How Comparator works.
  • How immutable collections work.
  • How to convert arrays and collections.
  • How nested collections work.
  • How to choose the correct collection.

What is a Collection?

A collection is an object that stores and manages a group of other objects. The objects stored inside a collection are called elements.

Collection Concept
COLLECTION
┌─────────────────────────┐
│ │
│ "Java" │
│ │
│ "Python" │
│ │
│ "JavaScript" │
│ │
└─────────────────────────┘
Collection Object
│
▼
Stores Multiple Elements
Collection Example
List<String> names =
new ArrayList<>();
names.add("Amit");
names.add("Neha");
names.add("Rahul");

Why Collections?

Dynamic Storage

Collections can grow and shrink while the program is running.

Searching

Collections provide convenient methods for finding elements.

Iteration

Collections can be processed using loops, iterators, and forEach.

Sorting

Elements can be sorted using built-in utilities and custom rules.

Unique Values

Set implementations can prevent duplicate elements.

Key-Value Data

Maps store values associated with unique keys.

Arrays vs Collections

Comparison
ARRAY
Fixed Size
Student[] students =
new Student[10];
COLLECTION
Dynamic Size
List<Student> students =
new ArrayList<>();
Arrays and Collections
ARRAYS
✓ Fixed size
✓ Can store primitives
✓ Can store objects
✓ Fast indexed access
✗ Limited built-in operations
COLLECTIONS
✓ Dynamic size
✓ Rich built-in operations
✓ Multiple data structures
✓ Easy searching and sorting
✗ Store objects, not primitives directly
Primitive Values
  • Collections use reference types.
  • Primitive values are stored using wrapper classes.
  • Use Integer instead of int.
  • Use Double instead of double.
  • Autoboxing makes this conversion convenient.
Primitive Wrapper Collection
List<Integer> numbers =
new ArrayList<>();
numbers.add(10);
numbers.add(20);
numbers.add(30);

Java Collections Framework

The Java Collections Framework is a unified architecture containing interfaces, implementations, and algorithms for working with groups of objects.

Framework Components
JAVA COLLECTIONS FRAMEWORK
├── Interfaces
│
│ ├── Collection
│ ├── List
│ ├── Set
│ ├── Queue
│ ├── Deque
│ └── Map
│
├── Implementations
│
│ ├── ArrayList
│ ├── LinkedList
│ ├── HashSet
│ ├── TreeSet
│ ├── PriorityQueue
│ ├── ArrayDeque
│ ├── HashMap
│ └── TreeMap
│
└── Algorithms
├── Sort
├── Search
├── Reverse
├── Shuffle
├── Min
└── Max

Collection Hierarchy

Collection Hierarchy
Iterable
│
▼
Collection
│
┌────────────┼────────────┐
│ │ │
▼ ▼ ▼
List Set Queue
│ │ │
│ │ └── Deque
│ │
│ ├── HashSet
│ ├── LinkedHashSet
│ └── TreeSet
│
├── ArrayList
├── LinkedList
├── Vector
└── Stack
Map
├── HashMap
├── LinkedHashMap
├── TreeMap
└── Hashtable
Map is Different
  • Map is part of the Java Collections Framework.
  • Map does not extend the Collection interface.
  • Map stores key-value pairs instead of individual elements.

Collection Interface

Collection is the root interface for most collection types. It defines common operations for managing groups of elements.

Common Collection Methods
add(element)
addAll(collection)
remove(element)
removeAll(collection)
retainAll(collection)
contains(element)
containsAll(collection)
size()
isEmpty()
clear()
iterator()
toArray()
Collection Reference
Collection<String> names =
new ArrayList<>();
names.add("Amit");
names.add("Neha");
System.out.println(
names.size()
);

Generic Collections

Generic collections specify the type of elements they can store. This provides compile-time type safety and avoids unnecessary casting.

Without Generic Type
List values =
new ArrayList();
values.add("Java");
values.add(100);
values.add(true);
With Generic Type
List<String> languages =
new ArrayList<>();
languages.add("Java");
languages.add("Python");
// Compile-time error
// languages.add(100);
Use Generic Collections
  • Generic collections provide type safety.
  • Errors are detected during compilation.
  • Explicit casting is usually unnecessary.
  • Code becomes easier to understand.

List Interface

List represents an ordered collection. It preserves element position, allows duplicate values, and provides index-based access.

List Characteristics
LIST
✓ Ordered
✓ Indexed
✓ Allows Duplicates
✓ Allows Multiple Null Values
Example:
Index Value
0 Java
1 Python
2 Java
3 null
List Implementations
List
├── ArrayList
├── LinkedList
├── Vector
└── Stack

ArrayList

ArrayList is a resizable array implementation of the List interface. It is one of the most commonly used collection classes in Java.

ArrayList Concept
ARRAYLIST
Index:
0 1 2 3
┌─────────┬─────────┬─────────┬─────────┐
│ Java │ Python │ C++ │ Go │
└─────────┴─────────┴─────────┴─────────┘
Dynamic Array

Creating an ArrayList

ArrayList Declaration
List<String> languages =
new ArrayList<>();
Concrete Reference
ArrayList<String> languages =
new ArrayList<>();
Program to an Interface
  • Prefer List as the reference type when List operations are sufficient.
  • The implementation can then be changed more easily.
  • Use the concrete type when implementation-specific methods are required.

Adding Elements

add()
List<String> languages =
new ArrayList<>();
languages.add("Java");
languages.add("Python");
languages.add("JavaScript");
System.out.println(languages);
Add at Index
languages.add(
1,
"C++"
);
addAll()
List<String> backend =
List.of(
"Java",
"Python"
);
List<String> frontend =
new ArrayList<>();
frontend.add("JavaScript");
frontend.add("TypeScript");
frontend.addAll(backend);

Accessing Elements

get()
List<String> languages =
List.of(
"Java",
"Python",
"JavaScript"
);
String language =
languages.get(1);
System.out.println(language);
Output
Python

Updating Elements

set()
List<String> languages =
new ArrayList<>(
List.of(
"Java",
"Python",
"JavaScript"
)
);
languages.set(
1,
"C++"
);
System.out.println(languages);
Output
[Java, C++, JavaScript]

Removing Elements

Remove by Index
languages.remove(1);
Remove by Value
languages.remove("Java");
Remove All Elements
languages.clear();
Integer Removal Ambiguity
  • List<Integer>.remove(1) removes the element at index 1.
  • To remove the Integer value 1, use Integer.valueOf(1).
Remove Integer Value
List<Integer> numbers =
new ArrayList<>(
List.of(
1,
2,
3
)
);
numbers.remove(
Integer.valueOf(1)
);

Searching Elements

contains()
boolean exists =
languages.contains(
"Java"
);
indexOf()
int index =
languages.indexOf(
"Java"
);
lastIndexOf()
int lastIndex =
languages.lastIndexOf(
"Java"
);

ArrayList Size

Size and Empty Check
System.out.println(
languages.size()
);
System.out.println(
languages.isEmpty()
);

Iterating an ArrayList

Traditional For Loop
for (
int i = 0;
i < languages.size();
i++
) {
System.out.println(
languages.get(i)
);
}
Enhanced For Loop
for (
String language : languages
) {
System.out.println(language);
}
forEach()
languages.forEach(
System.out::println
);

ArrayList of Objects

Student.java
public class Student {
private final int id;
private final String name;
public Student(
int id,
String name
) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
@Override
public String toString() {
return id
+ " - "
+ name;
}
}
StudentListExample.java
List<Student> students =
new ArrayList<>();
students.add(
new Student(
101,
"Amit"
)
);
students.add(
new Student(
102,
"Neha"
)
);
students.add(
new Student(
103,
"Rahul"
)
);
for (Student student : students) {
System.out.println(student);
}

LinkedList

LinkedList is a doubly linked list implementation of both the List and Deque interfaces.

LinkedList Concept
null
│
▼
┌───────────────┐
│ Previous │
│ Java │
│ Next │
└───────────────┘
│
▼
┌───────────────┐
│ Previous │
│ Python │
│ Next │
└───────────────┘
│
▼
┌───────────────┐
│ Previous │
│ JavaScript │
│ Next │
└───────────────┘
│
▼
null
LinkedList Example
LinkedList<String> languages =
new LinkedList<>();
languages.add("Java");
languages.add("Python");
languages.addFirst(
"C++"
);
languages.addLast(
"JavaScript"
);
System.out.println(languages);
LinkedList Operations
languages.getFirst();
languages.getLast();
languages.removeFirst();
languages.removeLast();

ArrayList vs LinkedList

Comparison
ARRAYLIST
Internal Structure:
Dynamic Array
Best For:
✓ Frequent indexed access
✓ Reading elements
✓ General-purpose List usage
Consideration:
Insertion or removal in the middle
may shift elements
LINKEDLIST
Internal Structure:
Doubly Linked Nodes
Best For:
✓ Operations at both ends
✓ Deque operations
Consideration:
Indexed access requires traversal

Vector

Vector is a legacy resizable-array implementation of List. Its methods are synchronized.

Vector Example
Vector<String> languages =
new Vector<>();
languages.add("Java");
languages.add("Python");
System.out.println(languages);
Modern Usage
  • ArrayList is usually preferred for general single-threaded List usage.
  • Vector remains available for legacy code.
  • Synchronization requirements should be handled using appropriate modern concurrency tools.

Stack

Stack is a legacy LIFO collection class that extends Vector.

LIFO
LAST IN, FIRST OUT
Push A
┌─────┐
│ A │
└─────┘
Push B
┌─────┐
│ B │ ← Top
├─────┤
│ A │
└─────┘
Pop
Returns B
Stack Example
Stack<String> stack =
new Stack<>();
stack.push("Page 1");
stack.push("Page 2");
stack.push("Page 3");
System.out.println(
stack.peek()
);
System.out.println(
stack.pop()
);
Modern Stack Recommendation
  • Deque is generally preferred over the legacy Stack class.
  • ArrayDeque is a common implementation for stack behavior.

Set Interface

Set represents a collection that does not allow duplicate elements.

Set Characteristics
SET
Input:
Java
Python
Java
C++
Python
Stored Values:
Java
Python
C++
Duplicates Removed
Set Implementations
Set
├── HashSet
├── LinkedHashSet
└── TreeSet

HashSet

HashSet stores unique elements using hashing. It does not guarantee iteration order.

HashSet Example
Set<String> languages =
new HashSet<>();
languages.add("Java");
languages.add("Python");
languages.add("Java");
languages.add("C++");
System.out.println(languages);
HashSet Characteristics
  • Duplicate elements are rejected.
  • Iteration order is not guaranteed.
  • One null element is permitted.
  • HashSet is useful for fast membership checks.

LinkedHashSet

LinkedHashSet stores unique elements while preserving insertion order.

LinkedHashSet Example
Set<String> languages =
new LinkedHashSet<>();
languages.add("Java");
languages.add("Python");
languages.add("C++");
System.out.println(languages);
Output
[Java, Python, C++]

TreeSet

TreeSet stores unique elements in sorted order.

TreeSet Example
Set<Integer> numbers =
new TreeSet<>();
numbers.add(50);
numbers.add(10);
numbers.add(30);
numbers.add(20);
System.out.println(numbers);
Output
[10, 20, 30, 50]

Set Comparison

HashSet vs LinkedHashSet vs TreeSet
HASHSET
✓ Unique Elements
✓ No Guaranteed Order
✓ Fast General-Purpose Set
LINKEDHASHSET
✓ Unique Elements
✓ Insertion Order
TREESET
✓ Unique Elements
✓ Sorted Order

Queue Interface

Queue represents a collection designed for processing elements in a particular order, commonly first-in, first-out.

FIFO Queue
FIRST IN, FIRST OUT
Add:
A → B → C
Queue:
FRONT REAR
A → B → C
Remove:
A leaves first

Queue Methods

Queue Method Pairs
INSERT
add(element)
Throws exception on failure
offer(element)
Returns false on failure
REMOVE
remove()
Throws exception if empty
poll()
Returns null if empty
EXAMINE
element()
Throws exception if empty
peek()
Returns null if empty
Queue Example
Queue<String> queue =
new LinkedList<>();
queue.offer("Task 1");
queue.offer("Task 2");
queue.offer("Task 3");
System.out.println(
queue.peek()
);
System.out.println(
queue.poll()
);

PriorityQueue

PriorityQueue processes elements according to their priority rather than strict insertion order.

PriorityQueue Example
Queue<Integer> numbers =
new PriorityQueue<>();
numbers.offer(50);
numbers.offer(10);
numbers.offer(30);
numbers.offer(20);
while (
!numbers.isEmpty()
) {
System.out.println(
numbers.poll()
);
}
Output
10
20
30
50

Deque Interface

Deque means double-ended queue. It allows insertion and removal from both the front and the rear.

Deque
FRONT REAR
⇄ A B C D ⇄
Insert Front
Insert Rear
Remove Front
Remove Rear

ArrayDeque

ArrayDeque Example
Deque<String> deque =
new ArrayDeque<>();
deque.addFirst("B");
deque.addFirst("A");
deque.addLast("C");
deque.addLast("D");
System.out.println(deque);
ArrayDeque as Stack
Deque<String> stack =
new ArrayDeque<>();
stack.push("Page 1");
stack.push("Page 2");
stack.push("Page 3");
System.out.println(
stack.pop()
);

Map Interface

Map stores data as key-value pairs. Every key must be unique, while values may be duplicated.

Map Concept
KEY VALUE
101 → Amit
102 → Neha
103 → Rahul
Keys:
✓ Unique
Values:
✓ May Repeat
Map Implementations
Map
├── HashMap
├── LinkedHashMap
├── TreeMap
└── Hashtable

HashMap

HashMap stores key-value pairs using hashing. It does not guarantee iteration order.

HashMap Example
Map<Integer, String> students =
new HashMap<>();
students.put(
101,
"Amit"
);
students.put(
102,
"Neha"
);
students.put(
103,
"Rahul"
);
System.out.println(students);

Adding Map Entries

put()
students.put(
104,
"Priya"
);
putIfAbsent()
students.putIfAbsent(
101,
"Different Name"
);

put() replaces the value when the key already exists, while putIfAbsent() adds the entry only when the key is not already associated with a value.

Accessing Map Values

get()
String name =
students.get(101);
System.out.println(name);
getOrDefault()
String name =
students.getOrDefault(
999,
"Unknown Student"
);

Updating Map Values

Update with put()
students.put(
101,
"Amit Sharma"
);
replace()
students.replace(
101,
"Amit"
);

Removing Map Entries

Remove by Key
students.remove(101);
Remove Matching Entry
students.remove(
102,
"Neha"
);
Clear Map
students.clear();

Searching a Map

containsKey()
boolean hasStudent =
students.containsKey(101);
containsValue()
boolean hasName =
students.containsValue(
"Amit"
);

Iterating a Map

Iterate Keys
for (
Integer id : students.keySet()
) {
System.out.println(id);
}
Iterate Values
for (
String name : students.values()
) {
System.out.println(name);
}
Iterate Entries
for (
Map.Entry<Integer, String> entry
: students.entrySet()
) {
System.out.println(
entry.getKey()
+ " - "
+ entry.getValue()
);
}
Map forEach()
students.forEach(
(id, name) ->
System.out.println(
id
+ " - "
+ name
)
);

LinkedHashMap

LinkedHashMap stores key-value pairs while preserving insertion order.

LinkedHashMap Example
Map<Integer, String> students =
new LinkedHashMap<>();
students.put(103, "Rahul");
students.put(101, "Amit");
students.put(102, "Neha");
System.out.println(students);

TreeMap

TreeMap stores entries sorted according to their keys.

TreeMap Example
Map<Integer, String> students =
new TreeMap<>();
students.put(103, "Rahul");
students.put(101, "Amit");
students.put(102, "Neha");
System.out.println(students);
Output
{101=Amit, 102=Neha, 103=Rahul}

Hashtable

Hashtable is a legacy synchronized key-value collection.

Hashtable Example
Map<Integer, String> students =
new Hashtable<>();
students.put(
101,
"Amit"
);
students.put(
102,
"Neha"
);
Hashtable Characteristics
  • Hashtable is synchronized.
  • It does not allow null keys.
  • It does not allow null values.
  • It is mainly encountered in legacy code.
  • Modern applications often use more appropriate Map implementations or concurrent collections.

Map Comparison

Map Implementations
HASHMAP
✓ Unique Keys
✓ No Guaranteed Order
✓ General-Purpose Map
LINKEDHASHMAP
✓ Unique Keys
✓ Insertion Order
TREEMAP
✓ Unique Keys
✓ Sorted by Keys
HASHTABLE
✓ Unique Keys
✓ Synchronized
✓ Legacy Class

Iterator

Iterator provides a standard way to traverse collection elements one at a time.

Iterator Example
List<String> languages =
new ArrayList<>(
List.of(
"Java",
"Python",
"JavaScript"
)
);
Iterator<String> iterator =
languages.iterator();
while (
iterator.hasNext()
) {
String language =
iterator.next();
System.out.println(language);
}
Iterator Methods
hasNext()
Checks whether another
element exists
next()
Returns next element
remove()
Removes current element
through iterator

ListIterator

ListIterator is designed for List collections and supports traversal in both forward and backward directions.

Forward Traversal
ListIterator<String> iterator =
languages.listIterator();
while (
iterator.hasNext()
) {
System.out.println(
iterator.next()
);
}
Backward Traversal
while (
iterator.hasPrevious()
) {
System.out.println(
iterator.previous()
);
}

Enhanced For Loop

Enhanced For Loop
for (
String language : languages
) {
System.out.println(language);
}

The enhanced for loop is simple and readable when index access or structural modification is not required.

forEach Method

Lambda Expression
languages.forEach(
language ->
System.out.println(language)
);
Method Reference
languages.forEach(
System.out::println
);

Removing While Iterating

Incorrect Removal
for (String language : languages) {
if (
language.equals("Python")
) {
// Unsafe structural modification
// languages.remove(language);
}
}
Iterator Removal
Iterator<String> iterator =
languages.iterator();
while (
iterator.hasNext()
) {
String language =
iterator.next();
if (
language.equals("Python")
) {
iterator.remove();
}
}
removeIf()
languages.removeIf(
language ->
language.startsWith("P")
);

Collections Utility Class

The Collections class provides static utility methods for working with collections.

Common Utility Methods
Collections.sort()
Collections.reverse()
Collections.shuffle()
Collections.min()
Collections.max()
Collections.frequency()
Collections.binarySearch()
Collections.swap()
Collections.fill()
Collections.copy()

Sorting Collections

Collections.sort()
List<Integer> numbers =
new ArrayList<>(
List.of(
50,
10,
30,
20
)
);
Collections.sort(numbers);
System.out.println(numbers);
Output
[10, 20, 30, 50]
List.sort()
numbers.sort(
Comparator.naturalOrder()
);

Reversing Collections

reverse()
Collections.reverse(numbers);
System.out.println(numbers);

Shuffling Collections

shuffle()
Collections.shuffle(numbers);
System.out.println(numbers);

Minimum and Maximum

min() and max()
int minimum =
Collections.min(numbers);
int maximum =
Collections.max(numbers);
System.out.println(
"Minimum: "
+ minimum
);
System.out.println(
"Maximum: "
+ maximum
);

Frequency

frequency()
List<String> languages =
List.of(
"Java",
"Python",
"Java",
"C++",
"Java"
);
int count =
Collections.frequency(
languages,
"Java"
);
System.out.println(count);
Output
3
binarySearch()
List<Integer> numbers =
new ArrayList<>(
List.of(
10,
20,
30,
40,
50
)
);
int index =
Collections.binarySearch(
numbers,
30
);
System.out.println(index);
Sort Before Binary Search
  • Binary search requires the collection to be sorted according to the same ordering.
  • Searching unsorted data can produce incorrect results.

Comparable

Comparable defines the natural ordering of objects. A class implements Comparable and provides the compareTo() method.

Student.java
public class Student
implements Comparable<Student> {
private final int id;
private final String name;
public Student(
int id,
String name
) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
@Override
public int compareTo(
Student other
) {
return Integer.compare(
this.id,
other.id
);
}
@Override
public String toString() {
return id
+ " - "
+ name;
}
}
Natural Sorting
List<Student> students =
new ArrayList<>();
students.add(
new Student(
103,
"Rahul"
)
);
students.add(
new Student(
101,
"Amit"
)
);
students.add(
new Student(
102,
"Neha"
)
);
Collections.sort(students);
students.forEach(
System.out::println
);

Comparator

Comparator defines an external custom ordering without requiring the class itself to define that ordering.

Sort by Name
students.sort(
Comparator.comparing(
Student::getName
)
);
Sort by ID Descending
students.sort(
Comparator.comparingInt(
Student::getId
).reversed()
);
Multiple Sorting Rules
students.sort(
Comparator
.comparing(
Student::getName
)
.thenComparingInt(
Student::getId
)
);

Comparable vs Comparator

Comparison
COMPARABLE
Package:
java.lang
Method:
compareTo()
Purpose:
Natural Ordering
Location:
Implemented inside class
Number of Orderings:
Usually one natural ordering
COMPARATOR
Package:
java.util
Method:
compare()
Purpose:
Custom Ordering
Location:
Separate from class
Number of Orderings:
Multiple possible orderings

Immutable Collections

Java provides factory methods for creating collections that cannot be structurally modified.

List.of()
List<String> languages =
List.of(
"Java",
"Python",
"JavaScript"
);
// UnsupportedOperationException
// languages.add("C++");
Set.of()
Set<String> languages =
Set.of(
"Java",
"Python",
"C++"
);
Map.of()
Map<Integer, String> students =
Map.of(
101,
"Amit",
102,
"Neha"
);
Factory Collection Rules
  • List.of(), Set.of(), and Map.of() create unmodifiable collections.
  • They do not permit null elements, keys, or values.
  • Set.of() rejects duplicate elements.
  • Map.of() rejects duplicate keys.

Converting Arrays and Collections

Array to List
String[] array = {
"Java",
"Python",
"C++"
};
List<String> list =
new ArrayList<>(
Arrays.asList(array)
);
List to Array
String[] array =
list.toArray(
new String[0]
);
Modern Array Conversion
String[] array =
list.toArray(
String[]::new
);

Nested Collections

A collection can contain other collections, allowing complex data structures to be created.

List of Lists
List<List<String>> courses =
new ArrayList<>();
courses.add(
List.of(
"Java",
"Spring"
)
);
courses.add(
List.of(
"JavaScript",
"React"
)
);
for (
List<String> course : courses
) {
System.out.println(course);
}
Map of Lists
Map<String, List<String>>
technologies =
new HashMap<>();
technologies.put(
"Backend",
List.of(
"Java",
"Spring"
)
);
technologies.put(
"Frontend",
List.of(
"JavaScript",
"React"
)
);

Choosing the Right Collection

Collection Selection Guide
NEED ORDERED ELEMENTS?
│
▼
LIST
│
├── General Purpose
│ ▼
│ ArrayList
│
└── Frequent Deque Operations
▼
LinkedList
NEED UNIQUE ELEMENTS?
│
▼
SET
│
├── No Order Required
│ ▼
│ HashSet
│
├── Insertion Order
│ ▼
│ LinkedHashSet
│
└── Sorted Order
▼
TreeSet
NEED PROCESSING ORDER?
│
▼
QUEUE
│
├── Priority
│ ▼
│ PriorityQueue
│
└── Both Ends
▼
ArrayDeque
NEED KEY-VALUE PAIRS?
│
▼
MAP
│
├── No Order Required
│ ▼
│ HashMap
│
├── Insertion Order
│ ▼
│ LinkedHashMap
│
└── Sorted Keys
▼
TreeMap

Student Management Example

Student.java
public class Student {
private final int id;
private final String name;
private final double marks;
public Student(
int id,
String name,
double marks
) {
this.id = id;
this.name = name;
this.marks = marks;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public double getMarks() {
return marks;
}
@Override
public String toString() {
return id
+ " - "
+ name
+ " - "
+ marks;
}
}
StudentManager.java
import java.util.*;
public class StudentManager {
private final List<Student>
students =
new ArrayList<>();
public void addStudent(
Student student
) {
students.add(student);
}
public Student findById(
int id
) {
for (
Student student : students
) {
if (
student.getId() == id
) {
return student;
}
}
return null;
}
public void sortByMarks() {
students.sort(
Comparator
.comparingDouble(
Student::getMarks
)
.reversed()
);
}
public void displayAll() {
students.forEach(
System.out::println
);
}
}

Word Frequency Example

WordFrequency.java
import java.util.*;
public class WordFrequency {
public static void main(
String[] args
) {
List<String> words =
List.of(
"java",
"spring",
"java",
"angular",
"java",
"spring"
);
Map<String, Integer>
frequency =
new HashMap<>();
for (String word : words) {
frequency.put(
word,
frequency.getOrDefault(
word,
0
) + 1
);
}
frequency.forEach(
(word, count) ->
System.out.println(
word
+ " = "
+ count
)
);
}
}

Task Queue Example

TaskQueue.java
import java.util.*;
public class TaskQueue {
private final Queue<String>
tasks =
new ArrayDeque<>();
public void addTask(
String task
) {
tasks.offer(task);
}
public String nextTask() {
return tasks.poll();
}
public String viewNextTask() {
return tasks.peek();
}
public boolean hasTasks() {
return !tasks.isEmpty();
}
public static void main(
String[] args
) {
TaskQueue queue =
new TaskQueue();
queue.addTask(
"Send email"
);
queue.addTask(
"Generate report"
);
queue.addTask(
"Backup files"
);
while (
queue.hasTasks()
) {
System.out.println(
"Processing: "
+ queue.nextTask()
);
}
}
}

Common Collection Errors

Common Errors
COLLECTION ERRORS
├── Using Raw Collection Types
├── Mixing Unrelated Element Types
├── Using Wrong Collection Type
├── Expecting ArrayList to Have Fixed Size
├── Expecting Arrays to Grow Dynamically
├── Using Primitives as Generic Types
├── Forgetting Wrapper Classes
├── Invalid List Index
├── Confusing size() with Last Index
├── Using <= Instead of < in Indexed Loops
├── Confusing remove(index) and remove(value)
├── Modifying List.of() Collections
├── Adding Null to List.of()
├── Adding Duplicate Values to Set.of()
├── Adding Duplicate Keys to Map.of()
├── Expecting HashSet Order
├── Expecting HashMap Order
├── Expecting PriorityQueue Iteration to Be Sorted
├── Using List When Uniqueness Is Required
├── Using Set When Duplicates Are Required
├── Using List for Key-Value Data
├── Using Map When Only Values Are Needed
├── Using ArrayList for Every Problem
├── Using LinkedList for Fast Random Access
├── Using Legacy Stack Instead of Deque
├── Using Hashtable Without Reason
├── Assuming Map Extends Collection
├── Forgetting Map Keys Must Be Unique
├── Assuming Map Values Must Be Unique
├── Replacing Existing Map Values Accidentally
├── Ignoring Null Return from Map.get()
├── Confusing Missing Key with Null Value
├── Modifying Collection During Enhanced For Loop
├── Causing ConcurrentModificationException
├── Calling Iterator.next() Without hasNext()
├── Removing Directly Instead of Iterator.remove()
├── Sorting Non-Comparable Objects Without Comparator
├── Incorrect compareTo() Implementation
├── Returning Only 1 or -1 from Comparison
├── Integer Subtraction Overflow in Comparators
├── Inconsistent equals() and hashCode()
├── Mutable Objects Used as HashMap Keys
├── Modifying Fields Used by HashSet Hashing
├── Forgetting to Sort Before Binary Search
├── Assuming Collections.sort() Works on Immutable List
├── Ignoring Generic Type Safety
├── Unnecessary Casting
├── Exposing Mutable Internal Collections
├── Returning Modifiable Collections Accidentally
├── Using Nested Collections Without Clear Types
├── Ignoring Empty Collections
├── Returning null Instead of Empty Collections
├── Assuming Collection Operations Are Thread-Safe
├── Using Synchronized Legacy Classes Automatically
├── Ignoring Memory Usage
├── Storing Unnecessary Duplicate Objects
├── Performing Repeated Linear Searches
├── Choosing Collection by Habit
└── Ignoring Data Structure Characteristics

Best Practices

  • Use generic collections.
  • Avoid raw collection types.
  • Program to interfaces when practical.
  • Use List instead of ArrayList as the reference type when only List operations are needed.
  • Use Set when duplicate elements must be prevented.
  • Use Map for key-value relationships.
  • Use Queue when processing order matters.
  • Use Deque for stack and double-ended queue operations.
  • Choose collection implementations based on required behavior.
  • Use ArrayList as a strong default for general-purpose List usage.
  • Use LinkedList when its specific linked-list or Deque behavior is useful.
  • Do not choose LinkedList simply because insertions exist.
  • Use HashSet for general-purpose uniqueness.
  • Use LinkedHashSet when insertion order matters.
  • Use TreeSet when sorted unique elements are required.
  • Use HashMap for general-purpose key-value storage.
  • Use LinkedHashMap when insertion order matters.
  • Use TreeMap when sorted keys are required.
  • Use PriorityQueue when priority-based processing is required.
  • Use ArrayDeque for stack behavior instead of legacy Stack.
  • Prefer modern collection classes over legacy Vector, Stack, and Hashtable when appropriate.
  • Understand whether order is guaranteed.
  • Never rely on HashSet iteration order.
  • Never rely on HashMap iteration order.
  • Remember that PriorityQueue iteration order is not guaranteed to be sorted.
  • Use poll() when an empty queue is a normal possibility.
  • Use peek() when an empty queue is a normal possibility.
  • Use getOrDefault() for convenient default Map values.
  • Use putIfAbsent() when existing values should not be replaced.
  • Use entrySet() when both Map keys and values are required.
  • Use keySet() when only keys are required.
  • Use values() when only values are required.
  • Use enhanced for loops for simple traversal.
  • Use Iterator when safe removal during traversal is required.
  • Use ListIterator for bidirectional List traversal.
  • Use removeIf() for condition-based removal.
  • Do not structurally modify collections during enhanced for loops.
  • Use Collections utility methods for common algorithms.
  • Sort data before using binary search.
  • Use Comparable for natural ordering.
  • Use Comparator for custom ordering.
  • Use Integer.compare() instead of subtraction for integer comparison.
  • Use Comparator.comparing() for readable comparison logic.
  • Use thenComparing() for multiple sorting rules.
  • Keep comparison rules consistent and predictable.
  • Implement equals() and hashCode() correctly for objects stored in hash-based collections.
  • Avoid mutating fields used by equals() and hashCode() while objects are stored in HashSet or used as HashMap keys.
  • Prefer immutable keys for maps.
  • Use List.of(), Set.of(), and Map.of() for fixed unmodifiable data.
  • Remember that collection factory methods reject null values.
  • Create a mutable copy when modification is required.
  • Use new ArrayList<>(existingList) for a mutable List copy.
  • Use empty collections instead of null where practical.
  • Avoid exposing internal mutable collections directly.
  • Return unmodifiable views or copies when callers should not modify internal data.
  • Use meaningful generic type names.
  • Avoid deeply nested collections when a domain class would be clearer.
  • Use domain objects to model complex relationships.
  • Consider performance characteristics for large data sets.
  • Avoid repeated linear searches when a Set or Map can provide better lookup behavior.
  • Measure performance before making unnecessary optimizations.
  • Do not assume collections are thread-safe.
  • Use appropriate concurrent collections for concurrent access.
  • Keep collection responsibilities separate from business logic.
  • Encapsulate collection operations inside service classes when appropriate.
  • Validate indexes before accessing lists when input is external.
  • Handle empty queues and collections safely.
  • Use isEmpty() for readability.
  • Use clear variable names such as students, products, and tasks.
  • Choose data structures based on required semantics first.
  • Prefer correctness and clarity over clever collection code.

Common Misconceptions

Avoid These Misconceptions
  • Collections and arrays are not the same.
  • Collections do not directly store primitive types.
  • Autoboxing allows primitives to appear convenient in collections.
  • ArrayList does not have a permanently fixed size.
  • ArrayList is not always better than every other collection.
  • LinkedList is not automatically faster for every insertion.
  • List allows duplicate elements.
  • Set prevents duplicate elements.
  • Set does not automatically mean sorted order.
  • HashSet does not preserve insertion order.
  • LinkedHashSet preserves insertion order.
  • TreeSet stores elements in sorted order.
  • Map does not extend Collection.
  • Map keys must be unique.
  • Map values do not need to be unique.
  • HashMap does not guarantee iteration order.
  • LinkedHashMap preserves insertion order.
  • TreeMap sorts by keys.
  • PriorityQueue does not guarantee sorted iteration.
  • Queue and List have different intended purposes.
  • Deque can be used as both a queue and stack.
  • Stack is a legacy class.
  • Vector is not required for every multithreaded application.
  • Hashtable is not the only synchronized Map option.
  • Iterator is not only for Lists.
  • ListIterator is specifically for Lists.
  • Removing directly during enhanced for iteration can fail.
  • List.of() does not create a mutable ArrayList.
  • Arrays.asList() is not the same as new ArrayList().
  • Collections.sort() modifies the supplied mutable list.
  • Binary search requires correctly sorted data.
  • Comparable and Comparator are not identical.
  • Comparable defines natural ordering.
  • Comparator defines custom ordering.
  • Hash-based collections depend on equals() and hashCode().
  • Changing a hash-based key after insertion can cause problems.
  • Collection choice should depend on required behavior.

Practice Exercises

Exercise 1: Programming Languages List
  • Create an ArrayList of programming languages.
  • Add five languages.
  • Insert one language at index 2.
  • Update one element.
  • Remove one element.
  • Display all remaining languages.
Exercise 2: Remove Duplicates
  • Create a List containing duplicate numbers.
  • Convert it to a Set.
  • Display unique values.
  • Preserve insertion order using LinkedHashSet.
Exercise 3: Sorted Unique Names
  • Create a TreeSet of names.
  • Add names in random order.
  • Add a duplicate name.
  • Display the final sorted set.
Exercise 4: Customer Queue
  • Create a Queue of customer names.
  • Add five customers.
  • Display the next customer.
  • Process customers one by one.
  • Continue until the queue is empty.
Exercise 5: Student Map
  • Create a Map using student IDs as keys.
  • Add five students.
  • Find a student by ID.
  • Update one student name.
  • Remove one student.
  • Display all entries.
Exercise 6: Word Counter
  • Create a List of repeated words.
  • Use a HashMap to count each word.
  • Display each word and its count.
  • Find the most frequently occurring word.
Exercise 7: Custom Student Sorting
  • Create a Student class.
  • Store students in an ArrayList.
  • Sort by ID.
  • Sort by name.
  • Sort by marks descending.
  • Use Comparator for custom sorting.
Exercise 8: Browser History Stack
  • Use ArrayDeque as a stack.
  • Push visited page names.
  • Display the current page.
  • Go back by popping the top page.
  • Continue until the stack is empty.

Common Interview Questions

It is a unified architecture of interfaces, implementations, and algorithms for storing and processing groups of objects.

Collection is an interface, while Collections is a utility class containing static methods for collection operations.

List preserves element positions and allows duplicates, while Set prevents duplicate elements.

ArrayList uses a dynamic array and provides fast indexed access, while LinkedList uses linked nodes and supports efficient operations at its ends.

HashSet does not guarantee order, while TreeSet stores unique elements in sorted order.

HashSet does not guarantee iteration order, while LinkedHashSet preserves insertion order.

Queue is a collection designed for processing elements in a particular order, commonly FIFO.

PriorityQueue processes elements according to their priority or ordering.

Deque is a double-ended queue that supports insertion and removal from both ends.

HashMap does not guarantee key order, while TreeMap stores entries sorted by keys.

No. Map is part of the Collections Framework but does not extend Collection.

Iterator is an interface used to traverse collection elements one at a time.

Iterator supports forward traversal of collections, while ListIterator supports forward and backward traversal of Lists.

Comparable defines the natural ordering of objects through compareTo().

Comparator defines custom external ordering rules for objects.

Hash-based collections use them to determine object equality and storage behavior.

Stack is a legacy Vector-based class, while ArrayDeque provides a modern and efficient implementation for stack operations.

Frequently Asked Questions

Start with ArrayList, then learn HashSet, HashMap, Queue, and the other implementations based on their behavior.

No. Use ArrayList for general-purpose ordered data, but choose Set, Map, Queue, or other implementations when their semantics better match the problem.

Collections store objects. Primitive values are represented using wrapper classes such as Integer and Double.

Many mutable List implementations such as ArrayList allow null, but factory collections created with List.of() do not.

No. A Set prevents duplicate elements according to its equality rules.

No. Adding an existing key normally replaces its associated value.

HashMap is a common general-purpose choice when no specific ordering is required.

No. HashMap is not designed for unsynchronized concurrent modification.

You have completed the planned Core Java foundation syllabus. The next step can be Advanced Java Collections, Generics, Lambda Expressions, Stream API, Multithreading, JDBC, or a Core Java project.

Key Takeaways

  • Collections store and manage groups of objects.
  • Collections can grow and shrink dynamically.
  • Arrays have fixed lengths.
  • Collections provide rich built-in operations.
  • The Java Collections Framework contains interfaces, implementations, and algorithms.
  • Collection is the root interface for most collection types.
  • Map does not extend Collection.
  • Generic collections provide type safety.
  • Collections store objects rather than primitive types directly.
  • Wrapper classes represent primitive values in collections.
  • List is ordered and allows duplicates.
  • ArrayList uses a dynamic array.
  • ArrayList provides fast indexed access.
  • LinkedList uses linked nodes.
  • LinkedList implements List and Deque.
  • Vector is a legacy synchronized List.
  • Stack is a legacy LIFO class.
  • ArrayDeque is generally preferred for stack operations.
  • Set prevents duplicate elements.
  • HashSet does not guarantee iteration order.
  • LinkedHashSet preserves insertion order.
  • TreeSet stores elements in sorted order.
  • Queue is designed for ordered processing.
  • offer() inserts into a queue.
  • poll() removes and returns the next element.
  • peek() examines the next element.
  • PriorityQueue processes elements according to priority.
  • Deque supports operations at both ends.
  • ArrayDeque supports queue and stack behavior.
  • Map stores key-value pairs.
  • Map keys must be unique.
  • Map values may be duplicated.
  • HashMap does not guarantee iteration order.
  • LinkedHashMap preserves insertion order.
  • TreeMap sorts entries by keys.
  • Hashtable is a legacy synchronized Map.
  • Iterator traverses collection elements.
  • ListIterator traverses Lists in both directions.
  • Enhanced for loops provide simple iteration.
  • forEach() supports functional-style iteration.
  • Iterator.remove() supports safe removal during iteration.
  • removeIf() removes elements matching a condition.
  • Collections is a utility class.
  • Collections.sort() sorts mutable Lists.
  • Collections.reverse() reverses Lists.
  • Collections.shuffle() randomizes List order.
  • Collections.min() finds the minimum.
  • Collections.max() finds the maximum.
  • Collections.frequency() counts matching elements.
  • Binary search requires sorted data.
  • Comparable defines natural ordering.
  • Comparator defines custom ordering.
  • compareTo() belongs to Comparable.
  • compare() belongs to Comparator.
  • Comparator.comparing() creates readable sorting rules.
  • List.of() creates an unmodifiable List.
  • Set.of() creates an unmodifiable Set.
  • Map.of() creates an unmodifiable Map.
  • Collection factory methods reject null values.
  • Arrays can be converted to collections.
  • Collections can be converted to arrays.
  • Collections can contain other collections.
  • Collection choice should match required behavior.
  • Use List for ordered data.
  • Use Set for unique data.
  • Use Queue for processing order.
  • Use Deque for operations at both ends.
  • Use Map for key-value relationships.
  • Use HashMap and HashSet for general-purpose lookup.
  • Use LinkedHashMap and LinkedHashSet when insertion order matters.
  • Use TreeMap and TreeSet when sorted order matters.
  • Hash-based collections depend on equals() and hashCode().
  • Collections are not automatically thread-safe.
  • Correct collection selection improves code clarity and efficiency.

Summary

The Java Collections Framework provides reusable data structures and algorithms for storing and processing groups of objects. It replaces much of the manual data-management work that would otherwise be required when using arrays alone.

List represents ordered data and allows duplicates. ArrayList is the most common general-purpose List implementation, while LinkedList also provides Deque behavior.

Set stores unique elements. HashSet provides general-purpose uniqueness, LinkedHashSet preserves insertion order, and TreeSet maintains sorted order.

Queue supports ordered processing, PriorityQueue processes elements according to priority, and Deque supports insertion and removal from both ends.

Map stores key-value relationships. HashMap is a common general-purpose implementation, LinkedHashMap preserves insertion order, and TreeMap sorts entries by keys.

Collections can be traversed using loops, Iterator, ListIterator, and forEach. Structural removal during iteration should be performed using safe mechanisms such as Iterator.remove() or removeIf().

The Collections utility class provides algorithms for sorting, reversing, shuffling, searching, and inspecting collections. Comparable defines natural ordering, while Comparator provides custom ordering rules.

Choosing the correct collection requires understanding whether the application needs ordering, uniqueness, key-value relationships, priority processing, indexed access, or operations at both ends.

Lesson 28 Completed
  • You understand what collections are.
  • You understand why collections are needed.
  • You know the difference between arrays and collections.
  • You understand the Java Collections Framework.
  • You understand the collection hierarchy.
  • You understand the Collection interface.
  • You can use generic collections.
  • You understand the List interface.
  • You can use ArrayList.
  • You can add, access, update, remove, and search List elements.
  • You can iterate ArrayLists.
  • You can store custom objects in collections.
  • You understand LinkedList.
  • You know the difference between ArrayList and LinkedList.
  • You understand the basics of Vector.
  • You understand the basics of Stack.
  • You understand the Set interface.
  • You can use HashSet.
  • You can use LinkedHashSet.
  • You can use TreeSet.
  • You understand Set implementation differences.
  • You understand the Queue interface.
  • You understand queue method pairs.
  • You can use PriorityQueue.
  • You understand Deque.
  • You can use ArrayDeque.
  • You understand the Map interface.
  • You can use HashMap.
  • You can add, access, update, remove, and search Map entries.
  • You can iterate Maps.
  • You can use LinkedHashMap.
  • You can use TreeMap.
  • You understand Hashtable.
  • You understand Map implementation differences.
  • You can use Iterator.
  • You can use ListIterator.
  • You can use enhanced for loops.
  • You can use forEach().
  • You can safely remove elements while iterating.
  • You understand the Collections utility class.
  • You can sort collections.
  • You can reverse collections.
  • You can shuffle collections.
  • You can find minimum and maximum values.
  • You can count element frequency.
  • You understand binary search.
  • You understand Comparable.
  • You understand Comparator.
  • You know the difference between Comparable and Comparator.
  • You understand immutable collections.
  • You can convert between arrays and collections.
  • You understand nested collections.
  • You can choose the correct collection type.
  • You can build collection-based applications.
  • You can identify common collection errors.
  • You know collection best practices.
  • You have completed the Core Java foundation syllabus.