The Ultimate Guide to Java Collections

/

Java Collections Framework is a powerful set of interfaces and classes that provide efficient ways to store, retrieve, and manipulate data. Understanding the nuances of different collection types is crucial for writing optimized and performant Java applications. In this article, we’ll explore the core Java collections, their usage, performance characteristics, and common use cases.

Overview of Java Collections

Java collections are broadly classified into three categories:

  1. List – Ordered collection of elements.
  2. Set – Unordered collection of unique elements.
  3. Queue – FIFO (First-In-First-Out) principle.
  4. Map – Key-value pairs.

Using Java Collections

List

A List maintains the insertion order and allows duplicate elements.

Common Implementations

  • ArrayList: Backed by a dynamic array, good for random access.
  • LinkedList: Doubly linked list, better for frequent insertions/deletions.
  • Vector: Synchronized version of ArrayList.
import java.util.*;

public class ListExample {
    public static void main(String[] args) {
        List<String> arrayList = new ArrayList<>();
        arrayList.add("Apple");
        arrayList.add("Banana");
        arrayList.add("Apple"); // Allows duplicates

        System.out.println("ArrayList: " + arrayList);

        List<String> fruits = new LinkedList<>();
        fruits.add("Apple");
        fruits.add("Banana");
        fruits.add("Orange");
        fruits.add(1, "Mango"); // Add "Mango" at index 1
    }
}

Set

A Set ensures no duplicate elements.

Common Implementations

  • HashSet: Uses hash table, no guaranteed order. HashSet provides fast lookups and is suitable when you need to ensure uniqueness of elements.
  • LinkedHashSet: LinkedHashSet maintains insertion order while ensuring uniqueness. LinkedHashSet is useful when you need both uniqueness and predictable iteration order.
  • TreeSet: Sorted in natural order.
import java.util.*;

public class SetExample {
    public static void main(String[] args) {

        Set<String> fruits = new HashSet<>();
        fruits.add("Apple");
        fruits.add("Banana");
        fruits.add("Orange");
        boolean contains = fruits.contains("Apple"); // Check if "Apple" is present        

        Set<String> treeSet = new TreeSet<>();
        treeSet.add("Dog");
        treeSet.add("Cat");
        treeSet.add("Dog"); // Ignored

        System.out.println("TreeSet: " + treeSet);
    }
}

Queue

A Queue is used for FIFO (First-In-First-Out) order.

Common Implementations

  • PriorityQueue: Elements are ordered by priority. PriorityQueue is useful for implementing priority-based tasks.
  • ArrayDeque: Double-ended queue that allows adding and removing elements from both ends. ArrayDeque is efficient for implementing queues and stacks.
import java.util.*;

public class QueueExample {
    public static void main(String[] args) {
        Queue<Integer> priorityQueue = new PriorityQueue<>();
        priorityQueue.add(10);
        priorityQueue.add(20);
        priorityQueue.add(5);

        System.out.println("PriorityQueue: " + priorityQueue);
    }
}

Map

A Map stores key-value pairs.

Common Implementations

  • HashMap: Unordered, fast lookup.
  • LinkedHashMap: Maintains insertion order.
  • TreeMap: Sorted by keys.
import java.util.*;

public class MapExample {
    public static void main(String[] args) {
        Map<Integer, String> hashMap = new HashMap<>();
        hashMap.put(1, "One");
        hashMap.put(2, "Two");
        hashMap.put(1, "Uno"); // Overwrites key 1

        System.out.println("HashMap: " + hashMap);
    }
}

When to Use Which Collection?

ScenarioRecommended Collection
Fast random accessArrayList
Frequent insertions/deletionsLinkedList
Unique elements without orderHashSet
Unique elements with insertion orderLinkedHashSet
Unique elements sortedTreeSet
Key-value pairs without orderHashMap
Key-value pairs with insertion orderLinkedHashMap
Key-value pairs sorted by keysTreeMap
Priority-based processingPriorityQueue

Performance Comparison

CollectionTime Complexity (Insert)Time Complexity (Search)OrderedThread-Safe
ArrayListO(1)O(1)YesNo
LinkedListO(1) (at ends)O(n)YesNo
HashSetO(1)O(1)NoNo
TreeSetO(log n)O(log n)YesNo
HashMapO(1)O(1)NoNo
TreeMapO(log n)O(log n)YesNo
PriorityQueueO(log n)O(1) (peek)NoNo

Conclusion

The Java Collections Framework offers a rich set of tools for managing data efficiently. By understanding the characteristics of different collection types, you can choose the most appropriate one for your specific needs and write high-performance Java applications.

Frequently Asked Questions

What is the difference between ArrayList and LinkedList?

ArrayList is backed by a dynamic array, better for random access. LinkedList is backed by a doubly linked list, better for frequent insertions and deletions.

When should I use TreeMap over HashMap?

Use TreeMap when you need sorted key-value pairs.

When should I use a Set instead of a List?

Use a Set when you need to ensure uniqueness of elements and don’t need to maintain insertion order.

How do I iterate over a Map?

Use the entrySet() method to iterate over the key-value pairs.

Can I use Java Collections Framework with multithreading?

Yes, but you need to use the synchronized collections or use a thread-safe implementation like ConcurrentHashMap.

How do I sort a List?

Use the Collections.sort() method or use a SortedSet implementation like TreeSet.

What is the difference between Iterator and ListIterator?

Iterator is a general-purpose iterator that can be used with any collection, while ListIterator is a specialized iterator that can be used with lists.

Leave a Reply