If you’re learning Java and want to understand how to store and manage a group of elements (like a list of names, numbers, or objects), then List from the Java Collection Framework is one of the most important tools you’ll need.
In this tutorial, we’ll learn step-by-step through the List interface, its types, methods, usage examples, and common pitfalls.
What is a List in Java?
In Java, a List is a part of the Java Collection Framework and is defined in the java.util package.
It represents an ordered collection of elements — meaning the elements are stored in the order they were added.
A list:
- Provides index-based access
- Allows duplicate elements
- Maintains insertion order
Real-life Analogy:
Imagine a list of students in a classroom. Each student has a fixed roll number (index), and duplicate names are allowed. You can also insert or remove students from the list.
Key Characteristics of List
- Ordered: Elements maintain insertion order means Elements are stored in the same order they are added
- Index-based access: You can access elements using an index (starting from 0).
- Duplicates allowed: You can store the same value multiple times.
- Dynamic size: Size can grow or shrink dynamically as elements are added or removed
Where Does List Fit in Java Collection Framework?
Here’s the hierarchy:
java.lang.Object
↳ java.util.Collection
↳ java.util.List
List is a subinterface of Collection, and it has several concrete classes:
ArrayListLinkedListVectorStack
Commonly Used List Implementations
Java provides multiple ways to use List:
Stack– A subclass ofVectorthat works on LIFO principle.ArrayList– Backed by a dynamic array. Fast for access, slower for inserts/removals in the middle.LinkedList– Backed by a doubly linked list. Better for insertions/deletions.Vector– LikeArrayList, but synchronized (thread-safe).
Here Brief Explanations of List Implementations
1. Stack
- A subclass of
Vector. - Follows LIFO (Last In, First Out) principle.
- Useful for undo features, expression evaluation, etc.
Example: Using Stack – LIFO (Last In, First Out)
Problem: Simulate browser back button using a Stack.
Java Code:
import java.util.Stack;
public class BrowserHistory {
public static void main(String[] args) {
Stack<String> history = new Stack<>();
// Simulating visiting web pages
history.push("Home");
history.push("About");
history.push("Services");
history.push("Contact");
System.out.println("Current page: " + history.peek());
// Going back (popping last visited pages)
System.out.println("Going back to: " + history.pop());
System.out.println("Now on page: " + history.peek());
}
}
Output:
Current page: Contact
Going back to: Contact
Now on page: Services
Explanation:
Stackuses push() to add pages and pop() to go back.peek()shows the current page.- Follows LIFO: the last visited page is the first one removed.
2. ArrayList
- Backed by a dynamic array.
- Fast for index-based access.
- Slower for insertions and deletions in the middle.
- Not thread-safe.
Example 2: Using ArrayList – Fast Access, Dynamic Size
Problem: Store and display a list of student names using ArrayList.
Java Code:
import java.util.ArrayList;
public class StudentList {
public static void main(String[] args) {
ArrayList<String> students = new ArrayList<>();
students.add("Aman");
students.add("Priya");
students.add("Rohit");
// Displaying students
for (int i = 0; i < students.size(); i++) {
System.out.println("Student " + (i + 1) + ": " + students.get(i));
}
}
}
Output:
Student 1: Aman
Student 2: Priya
Student 3: Rohit
Explanation:
ArrayListprovides index-based access usingget(i).- It dynamically resizes as elements are added.
- Best for read-heavy operations.
3. LinkedList
- Backed by a doubly linked list.
- Efficient for frequent insertions and deletions, especially at the beginning or middle.
- Slower than
ArrayListfor random access.
Example 3: Using LinkedList – Fast Insert/Delete
Problem: Simulate a print queue where documents are added and printed.
Java Code:
import java.util.LinkedList;
public class PrintQueue {
public static void main(String[] args) {
LinkedList<String> printQueue = new LinkedList<>();
printQueue.add("Document1");
printQueue.add("Document2");
printQueue.add("Document3");
// Printing (removing from front)
while (!printQueue.isEmpty()) {
System.out.println("Printing: " + printQueue.removeFirst());
}
}
}
Output:
Printing: Document1
Printing: Document2
Printing: Document3
Explanation:
LinkedListis ideal for queue-like behavior (FIFO).removeFirst()efficiently removes from the front.- Great for real-time systems or messaging apps.
4. Vector
- Similar to
ArrayListbut synchronized, making it thread-safe. - Slightly slower than
ArrayListdue to synchronization overhead.
Example 4: Using Vector – Thread-Safe List
Problem: Maintain a thread-safe log of user actions using Vector.
Java Code:
import java.util.Vector;
public class UserActionLog {
public static void main(String[] args) {
Vector<String> actions = new Vector<>();
actions.add("Login");
actions.add("Upload File");
actions.add("Logout");
for (String action : actions) {
System.out.println("Action: " + action);
}
}
}
Output:
Action: Login
Action: Upload File
Action: Logout
Explanation:
Vectoris similar toArrayListbut is synchronized.- Safe to use in multi-threaded environments.
- Suitable when multiple threads access/modify the list concurrently.
Summary Table:
| Implementation | Key Feature | Best Use Case |
|---|---|---|
Stack | LIFO, Undo operations | Navigating pages, undo, backtracking |
ArrayList | Fast access | Student lists, records, UI elements |
LinkedList | Fast insertion/removal | Queues, dynamic data manipulation |
Vector | Thread-safe | Logs in multi-threaded environments |
How to Use a List in Java
Let’s go step by step.
1. Import the required classes
import java.util.List;
import java.util.ArrayList;
2. Create a List
List<String> names = new ArrayList<>();
Always use
Listas the reference type (interface) and the concrete class likeArrayListorLinkedListon the right side.
Basic List Operations with Examples
Let’s assume we have a list of names using an ArrayList:
List<String> names = new ArrayList<>();
1. Add Elements
names.add("Alice");
names.add("Bob");
names.add("Charlie");
names.add("Alice"); // duplicate allowed
What it does:
- Adds elements to the list in the order you specify.
- Duplicates are allowed in a
List.
After adding:
System.out.println(names);
Output:
[Alice, Bob, Charlie, Alice]
2. Access Elements
System.out.println(names.get(0)); // Alice
System.out.println(names.get(2)); // Charlie
What it does:
- Accesses elements by their index (position in the list).
- Index starts at
0, soget(0)returns the first element.
Output:
Alice
Charlie
3. Update Elements
names.set(1, "Bobby"); // replaces Bob with Bobby
What it does:
- Replaces the element at index
1(which is “Bob”) with “Bobby”.
After updating:
System.out.println(names);
Output:
[Alice, Bobby, Charlie, Alice]
4. Remove Elements
names.remove(2); // removes "Charlie"
What it does:
- Removes the element at index
2. - The list automatically shifts the remaining elements to fill the gap.
After removal:
System.out.println(names);
Output:
[Alice, Bobby, Alice]
5. Check for Existence
System.out.println(names.contains("Alice")); // true
System.out.println(names.contains("Tom")); // false
What it does:
- Checks if the list contains a certain element.
- Returns a boolean:
trueif present,falseotherwise.
Output:
true
false
6. Get Size
System.out.println(names.size()); // 3
What it does:
- Returns the number of elements currently in the list.
Output:
3
7. Clear All Elements
names.clear(); // removes all elements
What it does:
- Removes all elements from the list.
- After this, the list becomes empty.
After clearing:
System.out.println(names);
Output:
[]
8. Check if Empty
System.out.println(names.isEmpty()); // true
What it does:
- Returns
trueif the list contains no elements. - Useful for checking before performing operations.
Output:
true
list Operations Summary Table:
| Operation | Code Example | Description |
|---|---|---|
| Add | add("Alice") | Adds element at the end |
| Access | get(0) | Gets element at index 0 |
| Update | set(1, "Bobby") | Replaces element at index 1 |
| Remove | remove(2) | Removes element at index 2 |
| Check Existence | contains("Alice") | Returns true if “Alice” exists |
| Get Size | size() | Returns number of elements |
| Clear All | clear() | Removes all elements |
| Check if Empty | isEmpty() | Returns true if list is empty |
Iterating Over a List
Let’s say we have the following list:
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
We’ll explore four ways to loop through this list and print each name.
1. Using For Loop
for (int i = 0; i < names.size(); i++) {
System.out.println(names.get(i));
}
Explanation:
- Uses an index
ithat starts from 0. - Continues looping until
i < names.size(). - Accesses elements using
get(i).
Pros:
- Gives full control over index.
- Useful when you need to know or modify the index.
Cons:
- Slightly more verbose.
- Not ideal if you just want to read each element.
Output:
Alice
Bob
Charlie
2. Using Enhanced For Loop
for (String name : names) {
System.out.println(name);
}
Explanation:
- Simplified loop introduced in Java 5.
- Automatically loops through all elements in the list.
nameis a temporary variable representing each element.
Pros:
- Cleaner syntax.
- Best for read-only access.
- No need to worry about indexes.
Cons:
- Can’t remove elements directly from the list inside this loop.
- No index access.
Output:
Alice
Bob
Charlie
3. Using Iterator
import java.util.Iterator;
Iterator<String> it = names.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
Explanation:
Iteratoris an object that lets you traverse collections one element at a time.hasNext()checks if there’s another element.next()returns the next element.
Pros:
- Can safely remove elements during iteration using
it.remove(). - Works for any collection type (List, Set, etc.).
Cons:
- Slightly more complex syntax.
- More boilerplate code compared to enhanced for-loop.
Output:
Alice
Bob
Charlie
4. Using forEach (Java 8+)
names.forEach(System.out::println);
Explanation:
- Introduced in Java 8 with Lambda Expressions.
forEach()is a method from theIterableinterface.System.out::printlnis a method reference that prints each item.
Pros:
- Very concise and readable.
- Perfect for functional programming style.
- Can be used with streams, too.
Cons:
- Not ideal if you need index or want to break the loop.
- Not for removing elements during iteration.
Output:
Alice
Bob
Charlie
Summary Table of Iterating Over a List
| Method | Syntax Example | Supports Removal | Supports Index | Java Version |
|---|---|---|---|---|
| For Loop | for (int i = 0; i < list.size(); i++) | ❌ | ✅ | Java 1+ |
| Enhanced For Loop | for (String s : list) | ❌ | ❌ | Java 5+ |
| Iterator | while (it.hasNext()) | ✅ (via remove()) | ❌ | Java 1.2+ |
| forEach (Lambda) | list.forEach(System.out::println) | ❌ | ❌ | Java 8+ |
List Program 1: Java Program to Store and Display Student Marks Using List
Problem Statement:
Write a Java program to store the names and marks of students in two separate Lists and print each student’s name with their corresponding marks.
Java code
import java.util.*;
public class StudentMarks {
public static void main(String[] args) {
// List to store student names
List<String> studentNames = new ArrayList<>();
// List to store corresponding marks
List<Integer> studentMarks = new ArrayList<>();
// Adding data
studentNames.add("Aman");
studentMarks.add(85);
studentNames.add("Priya");
studentMarks.add(92);
studentNames.add("Ravi");
studentMarks.add(78);
// Display names and marks
System.out.println("Student Report:");
for (int i = 0; i < studentNames.size(); i++) {
System.out.println(studentNames.get(i) + " scored " + studentMarks.get(i) + " marks.");
}
}
}
Output
Student Report:
Aman scored 85 marks.
Priya scored 92 marks.
Ravi scored 78 marks.
Explanation:
- Two lists are used:
studentNamesandstudentMarks. - The
ith index in both lists refers to the same student. - The
forloop usessize()andget(i)to print data together. - This shows how parallel lists can be used to manage related information.
List Program 2: Java Program to Remove Duplicate Items from a List
Problem Statement:
Write a Java program that accepts a list of items (with possible duplicates) and removes the duplicate items, preserving the original order.
Java Code:
import java.util.*;
public class RemoveDuplicates {
public static void main(String[] args) {
// Initial list with duplicates
List<String> items = new ArrayList<>();
items.add("Pen");
items.add("Pencil");
items.add("Eraser");
items.add("Pen");
items.add("Sharpener");
items.add("Pencil");
System.out.println("Original List: " + items);
// Remove duplicates while maintaining order
List<String> uniqueItems = new ArrayList<>();
for (String item : items) {
if (!uniqueItems.contains(item)) {
uniqueItems.add(item);
}
}
System.out.println("List after removing duplicates: " + uniqueItems);
}
}
Output:
Original List: [Pen, Pencil, Eraser, Pen, Sharpener, Pencil]
List after removing duplicates: [Pen, Pencil, Eraser, Sharpener]
Explanation:
- The program starts with a list that may contain duplicate entries.
- A second list
uniqueItemsis created to hold only unique elements. - The
contains()method checks if an item already exists before adding. - This approach maintains the original insertion order.
Differences Between ArrayList vs LinkedList
| Feature | ArrayList | LinkedList |
|---|---|---|
| Backed by | Dynamic Array | Doubly Linked List |
| Access Speed | Fast (O(1)) | Slow (O(n)) |
| Insertion/Deletion | Slow (O(n)) | Fast (O(1) at ends) |
| Memory Usage | Less | More |
Common Mistakes to Avoid While Using Lists in Java
1. IndexOutOfBoundsException
What it is:
This error occurs when you try to access an index that doesn’t exist in the list.
Example:
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
System.out.println(list.get(2)); // ❌ Error! Only 0 and 1 are valid indices
🧠 Why it happens:
- List indices start from
0. - If the list size is
2, valid indices are0and1. - Accessing index
2results inIndexOutOfBoundsException.
✅ How to avoid:
- Always check the size before accessing:
if (index < list.size()) {
System.out.println(list.get(index));
}
❌ 2. ConcurrentModificationException
What it is:
This occurs when you modify the list (add/remove) while looping over it using a for-each loop or Iterator.
Example (incorrect):
List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
for (String fruit : list) {
if (fruit.equals("Banana")) {
list.remove(fruit); // ❌ throws ConcurrentModificationException
}
}
✅ Correct way using Iterator:
Iterator<String> it = list.iterator();
while (it.hasNext()) {
if (it.next().equals("Banana")) {
it.remove(); // ✅ safe removal during iteration
}
}
🧠 Why it happens:
- Internally, the iterator expects no structural changes while iterating.
- Direct list modification breaks that expectation.
❌ 3. Confusing remove(index) vs remove(Object)
In Java Lists, the remove() method is overloaded:
remove(int index)— removes the element at a given index.remove(Object o)— removes the first occurrence of the given object.
🔍 Example (confusing case):
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.remove(1); // ❗ Removes element at index 1 (i.e., value 2), not value 1
System.out.println(list);
Output:
[1, 3]
✅ Correct way to remove value 1:
list.remove(Integer.valueOf(1)); // removes the object `1` (not index 1)
🧠 Why it happens:
- When you pass a number to
remove(), Java assumes it’s an index unless you explicitly cast or useInteger.valueOf().
Summary Table
| Mistake | What It Means | Example | How to Fix |
|---|---|---|---|
IndexOutOfBoundsException | Accessing non-existent index | list.get(10) when size is 5 | Use list.size() to check bounds |
ConcurrentModificationException | Modifying list during iteration | Removing in a for-each loop | Use Iterator.remove() |
remove(index) vs remove(Object) | Misunderstanding method overloads | list.remove(1) removes index 1 | Use Integer.valueOf(1) to remove value |
When Should You Use a List in Java?
The List interface in Java is a powerful and flexible data structure that is part of the Java Collections Framework. But how do you know when it’s the right choice to use a List?
Below are the most common use cases that clearly explain when and why to use a List in your Java application:
1. When You Want to Store Data in Insertion Order
Unlike some other collections like Set or Map, a List preserves the order in which elements are inserted.
Example:
List<String> tasks = new ArrayList<>();
tasks.add("Wake up");
tasks.add("Brush teeth");
tasks.add("Go for a walk");
System.out.println(tasks);
Output:
[Wake up, Brush teeth, Go for a walk]
Why it matters:
- Useful for things like task lists, logs, playlists, and queues where order is important.
2. When You Want to Allow Duplicate Values
A List allows you to store the same value multiple times. This is helpful in scenarios where repeated entries are meaningful.
Example:
List<String> votes = new ArrayList<>();
votes.add("Alice");
votes.add("Bob");
votes.add("Alice"); // duplicate
System.out.println(votes);
Output:
Alice, Bob, Alice]
Why it matters:
- Perfect for storing items like votes, form submissions, or scores that may naturally repeat.
3. When You Need to Access Elements by Index
Lists provide zero-based indexing, meaning you can quickly get, set, or remove an element using its index.
Example:
List<String> fruits = Arrays.asList("Apple", "Banana", "Mango");
System.out.println(fruits.get(1));
Output:
Banana
Why it matters:
- Ideal for use cases like accessing specific rows in a table, elements in a UI component, or characters in a sentence list.
4. When You Want a Dynamically Resizable Collection
Unlike arrays, Lists are dynamic — they can grow or shrink as needed. You don’t need to declare the size in advance.
Example:
List<Integer> numbers = new ArrayList<>();
numbers.add(10);
numbers.add(20);
numbers.remove(0); // Remove first element
System.out.println(numbers); // Output: [20]
Why it matters:
- Saves memory and reduces complexity when you’re dealing with unpredictable or frequently changing datasets (e.g., real-time chat, shopping cart, dynamic forms).
Use List When:
- Maintaining order of data: List keeps elements in insertion order
- Allowing duplicates: List permits repeating elements
- Accessing elements by position: Use
get(index),set(index, value) - Flexible size requirements: List can grow and shrink as needed
When Not to Use a List:
- If order doesn’t matter, consider using a
Set. - If you need key-value mapping, use a
Map. - If you need constant-time lookups, and no duplicates, use
HashSet.
Practice Questions
- Write a Java program to take 5 names from the user and store them in a list.
- Write a program to count how many times a name appears in a list.
- Write a program to sort a list of integers in ascending and descending order.
- Create a to-do list app using
ArrayListwith add, remove, and display features.
Conclusion
The List interface is a foundational concept in Java that every beginner must understand thoroughly. Whether you’re working on a student attendance system, a product catalog, or a playlist app — Lists make it easy to manage ordered collections of data.
❓Frequently Asked Questions (FAQs) About List in Java
Q1. What is the difference between ArrayList and LinkedList?
Answer:
ArrayListis backed by a dynamic array, offering fast access via index but slower insertions/deletions in the middle.LinkedListis backed by a doubly-linked list, making it faster for insertions and deletions, especially in large lists.
Q2. Can a Java List contain duplicate elements?
Answer:
Yes, a List allows duplicate values. You can add the same element multiple times, and it will be stored as separate entries.
List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Alice"); // Allowed
Q3. What happens if I access an invalid index in a List?
Answer:
If you try to access an index that doesn’t exist, Java will throw an IndexOutOfBoundsException.
List<Integer> list = Arrays.asList(10, 20);
System.out.println(list.get(5)); // ❌ Error!
Q4. How do I remove a specific element from a List in Java?
Answer:
Use remove(Object o) to remove a specific value and remove(index) to remove by position. For integers, use:
list.remove(Integer.valueOf(10)); // Removes value 10
Q5. How can I iterate through a List in Java?
Answer:
You can iterate using:
- Traditional
forloop - Enhanced
for-eachloop IteratorforEach()method (Java 8+)
Example:
for (String item : list) {
System.out.println(item);
}
Q6. Can I sort a List in Java?
Answer:
Yes! Use Collections.sort(list) to sort the list in ascending order. For custom sorting, you can pass a comparator.
Collections.sort(list);
Q7. Is List thread-safe in Java?
Answer:
No, by default List implementations like ArrayList are not thread-safe. Use Collections.synchronizedList(list) or CopyOnWriteArrayList for thread-safe operations.
Q8. How do I convert an array to a List in Java?
Answer:
Use Arrays.asList() to convert an array to a fixed-size list.
String[] arr = {"A", "B", "C"};
List<String> list = Arrays.asList(arr);