C

Core Java tutorial for beginners

Clean • Professional

Legacy vs Modern Collections in Java – Differences, Examples & Usage

4 minute

Legacy vs Modern Collections in Java

Java collections have evolved significantly over time. Understanding the differences between legacy collections and modern collections is essential for writing efficient, maintainable, and high-performance Java applications.

This guide covers concepts, examples, differences, use-cases, advantages, and best practices, making it easy to learn and apply.


What Are Legacy Collections?

Legacy collections are the original collection classes introduced in Java 1.0 and 1.1, before the Java Collections Framework (JCF) was introduced in Java 2 (Java 1.2).

Examples:

learn code with durgesh images

  • Vector – dynamic array
  • Stack – last-in-first-out stack
  • Hashtable – key-value pairs
  • Properties – key-value configuration
  • Enumeration – interface to traverse elements

Key Characteristics:

  • Synchronized by default – thread-safe but slower in single-threaded programs
  • No common interface hierarchy – each class worked independently
  • Iteration via Enumeration – limited functionality; cannot remove elements safely during iteration
  • No Generics support – type-unsafe, required casting

Example – Vector and Enumeration:

import java.util.*;

public class LegacyExample {
    public static void main(String[] args) {
        Vector<String> vector = new Vector<>();
        vector.add("Java");
        vector.add("Python");
        vector.add("C++");

        Enumeration<String> enumeration = vector.elements();
        while (enumeration.hasMoreElements()) {
            System.out.println(enumeration.nextElement());
        }
    }
}

Output:

Java
Python
C++

Legacy collections often require extra boilerplate code and are slower due to default synchronization.


What Are Modern Collections?

Modern collections were introduced as part of the Java Collections Framework (JCF) in Java 2 (1.2+). They provide a unified architecture, better performance, and generics support for type safety.

Examples:

learn code with durgesh images

  • List: ArrayList, LinkedList, CopyOnWriteArrayList
  • Set: HashSet, LinkedHashSet, TreeSet, CopyOnWriteArraySet
  • Map: HashMap, LinkedHashMap, TreeMap, ConcurrentHashMap, WeakHashMap
  • Queue: PriorityQueue, ConcurrentLinkedQueue, BlockingQueue, ArrayBlockingQueue

Characteristics:

  • Not synchronized by default – faster performance; thread-safety can be achieved with Collections.synchronizedXXX or concurrent classes
  • Supports generics – type-safe, no casting needed
  • Enhanced iteration – supports Iterator, for-each loop, and Streams API
  • Flexible & extensible – can create custom collections and use modern utilities

Example – ArrayList with Generics:

import java.util.*;

public class ModernExample {
    public static void main(String[] args) {
        List<String> languages = new ArrayList<>();
        languages.add("Java");
        languages.add("Python");
        languages.add("C++");

        for (String lang : languages) {
            System.out.println(lang);
        }
    }
}

Output:

Java
Python
C++

Key Differences Between Legacy and Modern Collections

FeatureLegacy CollectionsModern Collections
IntroducedJava 1.0 – 1.1Java 2 (1.2+)
ExamplesVector, Stack, Hashtable, EnumerationArrayList, LinkedList, HashMap, HashSet
Generics SupportNoYes (from Java 5)
SynchronizationSynchronized by defaultNot synchronized by default (can use concurrent classes)
PerformanceSlower (default locks)Faster
IterationEnumerationIterator, for-each loop, Stream API
API FlexibilityLimitedRich and unified API
Null SupportHashtable does not allow null keys or valuesHashMap allows null keys and values
Advanced FeaturesNoneConcurrency utilities, Streams, Lambda support

Comparison Legacy vs Modern

  1. Thread Safety
  • Legacy: Default synchronization → slower for single-threaded use
  • Modern: Unsynchronized → faster; thread-safe alternatives like ConcurrentHashMap exist
  1. Iteration & Traversal
  • Legacy: Enumeration → read-only, cannot remove elements safely
  • Modern: Iterator → supports safe removal, for-each, and Streams
  1. Generics Support
  • Legacy: No generics → required casting → runtime errors possible
  • Modern: Generics → type-safe → compile-time checks
  1. Performance
  • Legacy: Slower due to synchronization overhead
  • Modern: Faster; thread-safe variants available if needed
  1. Extensibility
  • Legacy: Difficult to extend or integrate
  • Modern: Extensible, supports concurrent collections, lambdas, and Streams

Examples – Legacy vs Modern

Vector vs ArrayList

// Legacy
Vector<String> vector = new Vector<>();
vector.add("A");
vector.add("B");

// Modern
List<String> arrayList = new ArrayList<>();
arrayList.add("A");
arrayList.add("B");

—> Vector is synchronized (slower), ArrayList is faster; prefer ArrayList in modern code.


Stack vs Deque

// Legacy
Stack<Integer> stack = new Stack<>();
stack.push(1);
stack.push(2);

// Modern
Deque<Integer> deque = new ArrayDeque<>();
deque.push(1);
deque.push(2);

—> Deque is more flexible and efficient; recommended over Stack.


Hashtable vs HashMap

// Legacy
Hashtable<Integer, String> table = new Hashtable<>();
table.put(1, "One");

// Modern
Map<Integer, String> map = new HashMap<>();
map.put(1, "One");

—> HashMap supports null keys/values and is faster; Hashtable is synchronized but slower.


Advantages of Modern Collections

  • Type-safe with generics
  • Faster in most scenarios
  • Extensible and flexible
  • Supports concurrency utilities
  • Works seamlessly with Streams and lambda expressions
  • Cleaner and more maintainable code

Disadvantages of Legacy Collections

  • Slower due to default synchronization
  • No generics → runtime type errors
  • Hard to extend and maintain
  • Limited interface hierarchy and features

When to Use Legacy Collections

  • Maintaining old applications using Vector, Stack, or Hashtable
  • Rare cases where built-in synchronization is needed without wrappers
  • Otherwise, avoid in new projects

When to Use Modern Collections

  • All new projects
  • Concurrent programming → ConcurrentHashMap, BlockingQueue, ConcurrentLinkedQueue
  • Functional programming → Streams API, lambda expressions
  • Immutable data → Collections.unmodifiableXXX() or Java 9+ immutable collections

Best Practices

  • Avoid Vector, Stack, and Hashtable in new code
  • Use ArrayList, HashMap, HashSet, LinkedList
  • Use Collections.synchronizedList/Map or concurrent collections for thread safety
  • Prefer Iterator, for-each loop, or Stream API instead of Enumeration
  • Always use generics for type safety

Points to Remember

  • Legacy Collections: Old, synchronized, less flexible, type-unsafe (Vector, Stack, Hashtable, Enumeration)
  • Modern Collections: Flexible, fast, generic-based (ArrayList, HashMap, HashSet, Deque)
  • Modern collections support Java 8+ features, Streams, and Lambda expressions
  • Use modern collections for new applications; legacy only for backward compatibility

Article 0 of 0