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.
import java.util.*;
List<String> languages =
new ArrayList<>();
languages.add("Java");
languages.add("Python");
languages.add("JavaScript");
System.out.println(languages);[Java, Python, JavaScript]- 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
┌─────────────────────────┐
│ │
│ "Java" │
│ │
│ "Python" │
│ │
│ "JavaScript" │
│ │
└─────────────────────────┘
Collection Object
│
▼
Stores Multiple ElementsList<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
ARRAY
Fixed Size
Student[] students =
new Student[10];
COLLECTION
Dynamic Size
List<Student> students =
new ArrayList<>();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- 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.
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.
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
└── MaxCollection Hierarchy
Iterable
│
▼
Collection
│
┌────────────┼────────────┐
│ │ │
▼ ▼ ▼
List Set Queue
│ │ │
│ │ └── Deque
│ │
│ ├── HashSet
│ ├── LinkedHashSet
│ └── TreeSet
│
├── ArrayList
├── LinkedList
├── Vector
└── Stack
Map
├── HashMap
├── LinkedHashMap
├── TreeMap
└── Hashtable- 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.
add(element)
addAll(collection)
remove(element)
removeAll(collection)
retainAll(collection)
contains(element)
containsAll(collection)
size()
isEmpty()
clear()
iterator()
toArray()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.
List values =
new ArrayList();
values.add("Java");
values.add(100);
values.add(true);List<String> languages =
new ArrayList<>();
languages.add("Java");
languages.add("Python");
// Compile-time error
// languages.add(100);- 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
✓ Ordered
✓ Indexed
✓ Allows Duplicates
✓ Allows Multiple Null Values
Example:
Index Value
0 Java
1 Python
2 Java
3 nullList
├── ArrayList
├── LinkedList
├── Vector
└── StackArrayList
ArrayList is a resizable array implementation of the List interface. It is one of the most commonly used collection classes in Java.
ARRAYLIST
Index:
0 1 2 3
┌─────────┬─────────┬─────────┬─────────┐
│ Java │ Python │ C++ │ Go │
└─────────┴─────────┴─────────┴─────────┘
Dynamic ArrayCreating an ArrayList
List<String> languages =
new ArrayList<>();ArrayList<String> languages =
new ArrayList<>();- 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
List<String> languages =
new ArrayList<>();
languages.add("Java");
languages.add("Python");
languages.add("JavaScript");
System.out.println(languages);languages.add(
1,
"C++"
);List<String> backend =
List.of(
"Java",
"Python"
);
List<String> frontend =
new ArrayList<>();
frontend.add("JavaScript");
frontend.add("TypeScript");
frontend.addAll(backend);Accessing Elements
List<String> languages =
List.of(
"Java",
"Python",
"JavaScript"
);
String language =
languages.get(1);
System.out.println(language);PythonUpdating Elements
List<String> languages =
new ArrayList<>(
List.of(
"Java",
"Python",
"JavaScript"
)
);
languages.set(
1,
"C++"
);
System.out.println(languages);[Java, C++, JavaScript]Removing Elements
languages.remove(1);languages.remove("Java");languages.clear();- List<Integer>.remove(1) removes the element at index 1.
- To remove the Integer value 1, use Integer.valueOf(1).
List<Integer> numbers =
new ArrayList<>(
List.of(
1,
2,
3
)
);
numbers.remove(
Integer.valueOf(1)
);Searching Elements
boolean exists =
languages.contains(
"Java"
);int index =
languages.indexOf(
"Java"
);int lastIndex =
languages.lastIndexOf(
"Java"
);ArrayList Size
System.out.println(
languages.size()
);
System.out.println(
languages.isEmpty()
);Iterating an ArrayList
for (
int i = 0;
i < languages.size();
i++
) {
System.out.println(
languages.get(i)
);
}for (
String language : languages
) {
System.out.println(language);
}languages.forEach(
System.out::println
);ArrayList of Objects
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;
}
}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.
null
│
▼
┌───────────────┐
│ Previous │
│ Java │
│ Next │
└───────────────┘
│
▼
┌───────────────┐
│ Previous │
│ Python │
│ Next │
└───────────────┘
│
▼
┌───────────────┐
│ Previous │
│ JavaScript │
│ Next │
└───────────────┘
│
▼
nullLinkedList<String> languages =
new LinkedList<>();
languages.add("Java");
languages.add("Python");
languages.addFirst(
"C++"
);
languages.addLast(
"JavaScript"
);
System.out.println(languages);languages.getFirst();
languages.getLast();
languages.removeFirst();
languages.removeLast();ArrayList vs LinkedList
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 traversalVector
Vector is a legacy resizable-array implementation of List. Its methods are synchronized.
Vector<String> languages =
new Vector<>();
languages.add("Java");
languages.add("Python");
System.out.println(languages);- 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.
LAST IN, FIRST OUT
Push A
┌─────┐
│ A │
└─────┘
Push B
┌─────┐
│ B │ ← Top
├─────┤
│ A │
└─────┘
Pop
Returns BStack<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()
);- 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
Input:
Java
Python
Java
C++
Python
Stored Values:
Java
Python
C++
Duplicates RemovedSet
├── HashSet
├── LinkedHashSet
└── TreeSetHashSet
HashSet stores unique elements using hashing. It does not guarantee iteration order.
Set<String> languages =
new HashSet<>();
languages.add("Java");
languages.add("Python");
languages.add("Java");
languages.add("C++");
System.out.println(languages);- 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.
Set<String> languages =
new LinkedHashSet<>();
languages.add("Java");
languages.add("Python");
languages.add("C++");
System.out.println(languages);[Java, Python, C++]TreeSet
TreeSet stores unique elements in sorted order.
Set<Integer> numbers =
new TreeSet<>();
numbers.add(50);
numbers.add(10);
numbers.add(30);
numbers.add(20);
System.out.println(numbers);[10, 20, 30, 50]Set Comparison
HASHSET
✓ Unique Elements
✓ No Guaranteed Order
✓ Fast General-Purpose Set
LINKEDHASHSET
✓ Unique Elements
✓ Insertion Order
TREESET
✓ Unique Elements
✓ Sorted OrderQueue Interface
Queue represents a collection designed for processing elements in a particular order, commonly first-in, first-out.
FIRST IN, FIRST OUT
Add:
A → B → C
Queue:
FRONT REAR
A → B → C
Remove:
A leaves firstQueue Methods
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 emptyQueue<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.
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()
);
}10
20
30
50Deque Interface
Deque means double-ended queue. It allows insertion and removal from both the front and the rear.
FRONT REAR
⇄ A B C D ⇄
Insert Front
Insert Rear
Remove Front
Remove RearArrayDeque
Deque<String> deque =
new ArrayDeque<>();
deque.addFirst("B");
deque.addFirst("A");
deque.addLast("C");
deque.addLast("D");
System.out.println(deque);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.
KEY VALUE
101 → Amit
102 → Neha
103 → Rahul
Keys:
✓ Unique
Values:
✓ May RepeatMap
├── HashMap
├── LinkedHashMap
├── TreeMap
└── HashtableHashMap
HashMap stores key-value pairs using hashing. It does not guarantee iteration order.
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
students.put(
104,
"Priya"
);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
String name =
students.get(101);
System.out.println(name);String name =
students.getOrDefault(
999,
"Unknown Student"
);Updating Map Values
students.put(
101,
"Amit Sharma"
);students.replace(
101,
"Amit"
);Removing Map Entries
students.remove(101);students.remove(
102,
"Neha"
);students.clear();Searching a Map
boolean hasStudent =
students.containsKey(101);boolean hasName =
students.containsValue(
"Amit"
);Iterating a Map
for (
Integer id : students.keySet()
) {
System.out.println(id);
}for (
String name : students.values()
) {
System.out.println(name);
}for (
Map.Entry<Integer, String> entry
: students.entrySet()
) {
System.out.println(
entry.getKey()
+ " - "
+ entry.getValue()
);
}students.forEach(
(id, name) ->
System.out.println(
id
+ " - "
+ name
)
);LinkedHashMap
LinkedHashMap stores key-value pairs while preserving insertion order.
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.
Map<Integer, String> students =
new TreeMap<>();
students.put(103, "Rahul");
students.put(101, "Amit");
students.put(102, "Neha");
System.out.println(students);{101=Amit, 102=Neha, 103=Rahul}Hashtable
Hashtable is a legacy synchronized key-value collection.
Map<Integer, String> students =
new Hashtable<>();
students.put(
101,
"Amit"
);
students.put(
102,
"Neha"
);- 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
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 ClassIterator
Iterator provides a standard way to traverse collection elements one at a time.
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);
}hasNext()
Checks whether another
element exists
next()
Returns next element
remove()
Removes current element
through iteratorListIterator
ListIterator is designed for List collections and supports traversal in both forward and backward directions.
ListIterator<String> iterator =
languages.listIterator();
while (
iterator.hasNext()
) {
System.out.println(
iterator.next()
);
}while (
iterator.hasPrevious()
) {
System.out.println(
iterator.previous()
);
}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
languages.forEach(
language ->
System.out.println(language)
);languages.forEach(
System.out::println
);Removing While Iterating
for (String language : languages) {
if (
language.equals("Python")
) {
// Unsafe structural modification
// languages.remove(language);
}
}Iterator<String> iterator =
languages.iterator();
while (
iterator.hasNext()
) {
String language =
iterator.next();
if (
language.equals("Python")
) {
iterator.remove();
}
}languages.removeIf(
language ->
language.startsWith("P")
);Collections Utility Class
The Collections class provides static utility methods for working with collections.
Collections.sort()
Collections.reverse()
Collections.shuffle()
Collections.min()
Collections.max()
Collections.frequency()
Collections.binarySearch()
Collections.swap()
Collections.fill()
Collections.copy()Sorting Collections
List<Integer> numbers =
new ArrayList<>(
List.of(
50,
10,
30,
20
)
);
Collections.sort(numbers);
System.out.println(numbers);[10, 20, 30, 50]numbers.sort(
Comparator.naturalOrder()
);Reversing Collections
Collections.reverse(numbers);
System.out.println(numbers);Shuffling Collections
Collections.shuffle(numbers);
System.out.println(numbers);Minimum and Maximum
int minimum =
Collections.min(numbers);
int maximum =
Collections.max(numbers);
System.out.println(
"Minimum: "
+ minimum
);
System.out.println(
"Maximum: "
+ maximum
);Frequency
List<String> languages =
List.of(
"Java",
"Python",
"Java",
"C++",
"Java"
);
int count =
Collections.frequency(
languages,
"Java"
);
System.out.println(count);3Binary Search
List<Integer> numbers =
new ArrayList<>(
List.of(
10,
20,
30,
40,
50
)
);
int index =
Collections.binarySearch(
numbers,
30
);
System.out.println(index);- 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.
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;
}
}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.
students.sort(
Comparator.comparing(
Student::getName
)
);students.sort(
Comparator.comparingInt(
Student::getId
).reversed()
);students.sort(
Comparator
.comparing(
Student::getName
)
.thenComparingInt(
Student::getId
)
);Comparable vs Comparator
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 orderingsImmutable Collections
Java provides factory methods for creating collections that cannot be structurally modified.
List<String> languages =
List.of(
"Java",
"Python",
"JavaScript"
);
// UnsupportedOperationException
// languages.add("C++");Set<String> languages =
Set.of(
"Java",
"Python",
"C++"
);Map<Integer, String> students =
Map.of(
101,
"Amit",
102,
"Neha"
);- 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
String[] array = {
"Java",
"Python",
"C++"
};
List<String> list =
new ArrayList<>(
Arrays.asList(array)
);String[] array =
list.toArray(
new String[0]
);String[] array =
list.toArray(
String[]::new
);Nested Collections
A collection can contain other collections, allowing complex data structures to be created.
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<String, List<String>>
technologies =
new HashMap<>();
technologies.put(
"Backend",
List.of(
"Java",
"Spring"
)
);
technologies.put(
"Frontend",
List.of(
"JavaScript",
"React"
)
);Choosing the Right Collection
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
▼
TreeMapStudent Management Example
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;
}
}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
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
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
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 CharacteristicsBest 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
- 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
- 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.
- Create a List containing duplicate numbers.
- Convert it to a Set.
- Display unique values.
- Preserve insertion order using LinkedHashSet.
- Create a TreeSet of names.
- Add names in random order.
- Add a duplicate name.
- Display the final sorted set.
- Create a Queue of customer names.
- Add five customers.
- Display the next customer.
- Process customers one by one.
- Continue until the queue is empty.
- 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.
- 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.
- Create a Student class.
- Store students in an ArrayList.
- Sort by ID.
- Sort by name.
- Sort by marks descending.
- Use Comparator for custom sorting.
- 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
What is the Java Collections Framework?
It is a unified architecture of interfaces, implementations, and algorithms for storing and processing groups of objects.
What is the difference between Collection and Collections?
Collection is an interface, while Collections is a utility class containing static methods for collection operations.
What is the difference between List and Set?
List preserves element positions and allows duplicates, while Set prevents duplicate elements.
What is the difference between ArrayList and LinkedList?
ArrayList uses a dynamic array and provides fast indexed access, while LinkedList uses linked nodes and supports efficient operations at its ends.
What is the difference between HashSet and TreeSet?
HashSet does not guarantee order, while TreeSet stores unique elements in sorted order.
What is the difference between HashSet and LinkedHashSet?
HashSet does not guarantee iteration order, while LinkedHashSet preserves insertion order.
What is a Queue?
Queue is a collection designed for processing elements in a particular order, commonly FIFO.
What is a PriorityQueue?
PriorityQueue processes elements according to their priority or ordering.
What is a Deque?
Deque is a double-ended queue that supports insertion and removal from both ends.
What is the difference between HashMap and TreeMap?
HashMap does not guarantee key order, while TreeMap stores entries sorted by keys.
Does Map extend Collection?
No. Map is part of the Collections Framework but does not extend Collection.
What is Iterator?
Iterator is an interface used to traverse collection elements one at a time.
What is the difference between Iterator and ListIterator?
Iterator supports forward traversal of collections, while ListIterator supports forward and backward traversal of Lists.
What is Comparable?
Comparable defines the natural ordering of objects through compareTo().
What is Comparator?
Comparator defines custom external ordering rules for objects.
Why are equals() and hashCode() important?
Hash-based collections use them to determine object equality and storage behavior.
Why is ArrayDeque preferred over Stack?
Stack is a legacy Vector-based class, while ArrayDeque provides a modern and efficient implementation for stack operations.
Frequently Asked Questions
Which collection should a beginner learn first?
Start with ArrayList, then learn HashSet, HashMap, Queue, and the other implementations based on their behavior.
Should I always use ArrayList?
No. Use ArrayList for general-purpose ordered data, but choose Set, Map, Queue, or other implementations when their semantics better match the problem.
Can collections store primitive values?
Collections store objects. Primitive values are represented using wrapper classes such as Integer and Double.
Can a List contain null?
Many mutable List implementations such as ArrayList allow null, but factory collections created with List.of() do not.
Can a Set contain duplicates?
No. A Set prevents duplicate elements according to its equality rules.
Can a Map contain duplicate keys?
No. Adding an existing key normally replaces its associated value.
Which Map should I use most often?
HashMap is a common general-purpose choice when no specific ordering is required.
Is HashMap thread-safe?
No. HashMap is not designed for unsynchronized concurrent modification.
What should I learn after Collections Basics?
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.
- 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.