The LinkedList in Java is a part of the Java Collections Framework and is present in java.util package. It is a doubly-linked list implementation of the List and Deque interfaces.
Key Points
Dynamic Sizing: Like ArrayList, LinkedList is also resizable.
Ordering: Elements in a LinkedList maintain their order.
Insertion & Deletion: Generally, faster insertion and deletion compared to ArrayList as no shift is needed. However, it depends on the position of insertion/deletion.
Performance: Slower get and set methods compared to ArrayList because of the need to traverse the list.
Memory Overhead: More memory is consumed per element in a LinkedList than an ArrayList because every element in the LinkedList has two references (next and previous) in addition to the data.
Not Synchronized: Like ArrayList, LinkedList is not synchronized by default.
Bidirectional Traversal: With its ListIterator, you can traverse the list in both forward and backward directions.
1. Create a LinkedList and Adding New Elements to it
import java.util.LinkedList;
public class LinkedListDemo {
public static void main(String[] args) {
// 1. Creating a new LinkedList of Strings
LinkedList<String> fruits = new LinkedList<>();
// 2. Adding elements to the LinkedList
fruits.add("Mango"); // Adds 'Mango' to the end of the list
fruits.add("Apple"); // Adds 'Apple' to the end of the list
fruits.addFirst("Banana"); // Adds 'Banana' to the beginning of the list
fruits.addLast("Orange"); // Adds 'Orange' to the end of the list
// 3. Printing the LinkedList
System.out.println(fruits);
}
}
Output:
[Banana, Mango, Apple, Orange]
Explanation:
1. An instance of LinkedList named fruits is created to store strings.
2. The add() method is used to add elements to the end of the list. So, "Mango" and then "Apple" are added.
3. The addFirst() method inserts the specified element at the beginning of the list. Here, "Banana" is added to the start.
4. The addLast() method appends the specified element to the end of the list. "Orange" is added after the other elements.
5. The entire list is then printed, displaying the order in which elements were added.
2. Retrieve Elements from a LinkedList
import java.util.LinkedList;
public class LinkedListRetrieveDemo {
public static void main(String[] args) {
// 1. Create a LinkedList and add some elements
LinkedList<String> fruits = new LinkedList<>();
fruits.add("Banana");
fruits.add("Mango");
fruits.add("Apple");
fruits.add("Orange");
// 2. Retrieve elements from the LinkedList
String firstElement = fruits.getFirst(); // Get the first element
String lastElement = fruits.getLast(); // Get the last element
String secondElement = fruits.get(1); // Get the element at index 1
// 3. Print the retrieved elements
System.out.println("First Element: " + firstElement);
System.out.println("Last Element: " + lastElement);
System.out.println("Element at Index 1: " + secondElement);
}
}
Output:
First Element: Banana Last Element: Orange Element at Index 1: Mango
Explanation:
1. A LinkedList named fruits is initialized and populated with four fruit names.
2. The method getFirst() is used to retrieve the first element from the list, getLast() to get the last element, and get(index) to get an element at a specified index.
3. These retrieved elements are then printed to the console to display their values.
3. Remove Elements from a LinkedList
import java.util.LinkedList;
import java.util.function.Predicate;
public class LinkedListRemoveDemo {
public static void main(String[] args) {
// 1. Initialize a LinkedList with some elements
LinkedList<String> fruits = new LinkedList<>();
fruits.add("Banana");
fruits.add("Mango");
fruits.add("Apple");
fruits.add("Orange");
fruits.add("Mango");
// 2. Remove elements from the LinkedList
fruits.removeFirst(); // Remove the first element
fruits.removeLast(); // Remove the last element
fruits.remove("Mango"); // Remove the first occurrence of "Mango"
Predicate<String> condition = fruit -> fruit.contains("Apple");
fruits.removeIf(condition); // Remove all elements that satisfy the predicate
System.out.println(fruits);
// 3. Clear the entire LinkedList
fruits.clear();
System.out.println("After clearing: " + fruits);
}
}
Output:
[Apple] After clearing: []
Explanation:
1. A LinkedList named fruits is initialized and populated with several fruit names.
2. The method removeFirst() is used to remove the first element, and removeLast() to remove the last element from the list. The remove(Object) method is used to remove the first occurrence of the specified object, in this case, "Mango". The removeIf(Predicate) method removes all of the elements of this collection that satisfy the given predicate.
3. The clear() method is called to remove all the elements in the LinkedList, making it empty.
4. Search Elements in a LinkedList
import java.util.LinkedList;
public class LinkedListSearchDemo {
public static void main(String[] args) {
// 1. Initialize a LinkedList with some elements
LinkedList<String> fruits = new LinkedList<>();
fruits.add("Banana");
fruits.add("Mango");
fruits.add("Apple");
fruits.add("Orange");
fruits.add("Mango");
// 2. Check for existence of an element
boolean exists = fruits.contains("Mango");
System.out.println("Mango exists in list: " + exists);
// 3. Find index of first and last occurrence
int firstIndex = fruits.indexOf("Mango");
System.out.println("First occurrence of Mango: " + firstIndex);
int lastIndex = fruits.lastIndexOf("Mango");
System.out.println("Last occurrence of Mango: " + lastIndex);
}
}
Output:
Mango exists in list: true First occurrence of Mango: 1 Last occurrence of Mango: 4
Explanation:
1. A LinkedList named fruits is initialized and populated with several fruit names.
2. The contains(Object) method is used to check if an element, in this case "Mango", exists in the LinkedList.
3. The indexOf(Object) method returns the index of the first occurrence of the specified element in the list, or -1 if the list does not contain the element. Similarly, the lastIndexOf(Object) method is used to find the index of the last occurrence of the specified element.
5. Iterate Over a LinkedList – Different Ways
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
public class LinkedListIterationDemo {
public static void main(String[] args) {
LinkedList<String> fruits = new LinkedList<>();
fruits.add("Banana");
fruits.add("Mango");
fruits.add("Apple");
fruits.add("Orange");
// 1. Using Java 8 forEach() with lambda
System.out.println("Using Java 8 forEach with lambda:");
fruits.forEach(fruit -> System.out.println(fruit));
// 2. Using iterator
System.out.println("\nUsing iterator:");
Iterator<String> iterator = fruits.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
// 3. Using iterator() and Java 8 forEachRemaining() method
System.out.println("\nUsing iterator with forEachRemaining method:");
iterator = fruits.iterator();
iterator.forEachRemaining(fruit -> System.out.println(fruit));
// 4. Using descendingIterator
System.out.println("\nUsing descendingIterator:");
Iterator<String> descendingIterator = fruits.descendingIterator();
while (descendingIterator.hasNext()) {
System.out.println(descendingIterator.next());
}
// 5. Using listIterator
System.out.println("\nUsing listIterator:");
ListIterator<String> listIterator = fruits.listIterator();
while (listIterator.hasNext()) {
System.out.println(listIterator.next());
}
// 6. Using simple for-each loop
System.out.println("\nUsing simple for-each loop:");
for (String fruit : fruits) {
System.out.println(fruit);
}
}
}
Output:
Using Java 8 forEach with lambda: Banana Mango Apple Orange Using iterator: Banana Mango Apple Orange Using iterator with forEachRemaining method: Banana Mango Apple Orange Using descendingIterator: Orange Apple Mango Banana Using listIterator: Banana Mango Apple Orange Using simple for-each loop: Banana Mango Apple Orange
Explanation:
1. The forEach() method from Java 8 allows us to iterate over the LinkedList using lambda expressions.
2. An Iterator is an object-oriented design pattern that provides a way to access elements of a collection sequentially without exposing the underlying structure.
3. The forEachRemaining() method from Java 8 with an Iterator behaves similarly to forEach(), but it starts from the current position of the iterator.
4. The descendingIterator() returns an iterator over the elements in this deque in reverse sequential order.
5. ListIterator is an iterator for lists that allows the programmer to traverse the list in either direction and modify the list during iteration.
6. A simple for-each loop is a traditional and straightforward method for iterating over collections.
6. Real-World Example – Student Management using LinkedList
import java.util.LinkedList;
class Student {
private int id;
private String name;
private double grade;
public Student(int id, String name, double grade) {
this.id = id;
this.name = name;
this.grade = grade;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public double getGrade() {
return grade;
}
@Override
public String toString() {
return "ID: " + id + ", Name: " + name + ", Grade: " + grade;
}
}
public class StudentManagement {
public static void main(String[] args) {
LinkedList<Student> students = new LinkedList<>();
// Adding students
students.add(new Student(1, "Ravi", 85.5));
students.add(new Student(2, "Priya", 78.4));
students.add(new Student(3, "Vijay", 90.2));
// Displaying students
System.out.println("Students List:");
for (Student student : students) {
System.out.println(student);
}
// Removing a student
Student priya = null;
for (Student student : students) {
if (student.getName().equals("Priya")) {
priya = student;
break;
}
}
if (priya != null) {
students.remove(priya);
System.out.println("\nAfter removing Priya:");
for (Student student : students) {
System.out.println(student);
}
}
}
}
Output:
Students List: ID: 1, Name: Ravi, Grade: 85.5 ID: 2, Name: Priya, Grade: 78.4 ID: 3, Name: Vijay, Grade: 90.2 After removing Priya: ID: 1, Name: Ravi, Grade: 85.5 ID: 3, Name: Vijay, Grade: 90.2
Explanation:
1. We defined a Student class with attributes id, name, and grade.
2. We created a LinkedList named students to store Student objects.
3. We added three student objects to the list using the add() method.
4. We displayed the students using a simple for-each loop.
5. We then showed how to find and remove a student named "Priya" from the list.
7. ArrayList vs LinkedList
Property | ArrayList | LinkedList |
---|---|---|
Implementation | Backed by a dynamic array. | Implemented as a doubly-linked list. |
Resizing | Automatically resized, but resizing involves array copying which can be costly. | Nodes can be easily inserted or removed without resizing or reorganization. |
Memory Consumption | Uses less memory as it stores only data. | Uses more memory due to storage of data and two pointers (next & previous) per node. |
Access Time | Constant-time (O(1)) for indexed retrieval due to array implementation. | Linear-time (O(n)) for access as it might need to traverse the list. |
Insertions/Deletions | O(n) in the worst case as elements might need to be shifted. | O(1) for insertion/deletion once the node is accessed, but finding the node takes O(n) in the worst case. |
Performance | Generally faster for indexed operations due to cache coherence and array implementation. | Performance can suffer due to non-contiguous memory allocation, especially during iteration. |
Use Cases | Best for scenarios with more frequent get/set operations and less frequent insertions/deletions. | Preferred for frequent insertions and deletions with relatively fewer get operations. |
Conclusion
In this tutorial, you learned what is a LinkedList, what are the differences between a LinkedList and an ArrayList, how to create a LinkedList, how to add, remove, and search for elements in a LinkedList, how to iterate over a LinkedList, and a simple real-world example using LinkedList.