Java Programming Core Packages Study Guide

Java Utility Package - Complete Guide

Master Java utility package (java.util): Learn Collections Framework, Date-Time API, utility classes, and essential tools for effective Java programming with practical examples.

Introduction to java.util

The java.util package is one of Java's most important packages, providing:

  • Collections Framework — Data structures like Lists, Sets, Maps
  • Utility Classes — Arrays, Collections, Objects
  • Date/Time — Date, Calendar (largely replaced by java.time)
  • Random Number Generation — Random, ThreadLocalRandom
  • Input/Output — Scanner, StringTokenizer
  • Event Model — EventObject, EventListener

What are Utility Classes?

Utility classes in Java provide static helper methods for common operations. They:

  • Cannot be instantiated (private constructor)
  • Contain only static methods
  • Are final to prevent inheritance
  • Provide reusable functionality across your application

Common Utility Classes in java.util

Utility ClassPurpose
CollectionsOperations on collections (sort, search, synchronize)
ArraysOperations on arrays (sort, fill, copy, stream)
ObjectsNull-safe object operations
ScannerParsing primitive types and tokens from input
RandomGenerating pseudo-random numbers
UUIDGenerating universally unique identifiers
PropertiesManaging key-value configuration
OptionalRepresenting optional values without null

Collections Framework

The Collections Framework provides a unified architecture for storing and manipulating groups of objects.

Core Interfaces Hierarchy

Hierarchy diagram
Iterable (interface)
    │
    └── Collection (interface)
            │
            ├── List (interface) - Ordered, allows duplicates
            │       ├── ArrayList
            │       ├── LinkedList
            │       └── Vector
            │
            ├── Set (interface) - No duplicates, unordered
            │       ├── HashSet
            │       ├── LinkedHashSet
            │       └── TreeSet
            │
            └── Queue (interface) - FIFO order
                    ├── PriorityQueue
                    └── Deque (interface)
                            └── ArrayDeque

Map (interface) - Key-value pairs
    ├── HashMap
    ├── LinkedHashMap
    ├── TreeMap
    └── Hashtable

Lists: ArrayList, LinkedList, Vector

ArrayList — Dynamic Array

Best for: Random access, frequent reads, fewer insertions/deletions

ArrayListDemo.java
import java.util.*;

public class ArrayListDemo {
    public static void main(String[] args) {
        // Create ArrayList
        ArrayList<String> fruits = new ArrayList<>();
        
        // Add elements
        fruits.add("Apple");
        fruits.add("Banana");
        fruits.add("Orange");
        fruits.add("Mango");
        fruits.add(2, "Grape"); // Insert at index 2
        
        System.out.println("Fruits: " + fruits);
        
        // Access elements
        String first = fruits.get(0);
        System.out.println("First fruit: " + first);
        
        // Modify elements
        fruits.set(1, "Blueberry");
        System.out.println("After modification: " + fruits);
        
        // Remove elements
        fruits.remove("Orange");      // By object
        fruits.remove(2);             // By index
        System.out.println("After removal: " + fruits);
        
        // Check existence
        boolean hasApple = fruits.contains("Apple");
        System.out.println("Contains Apple? " + hasApple);
        
        // Get index
        int index = fruits.indexOf("Mango");
        System.out.println("Mango at index: " + index);
        
        // Iteration methods
        System.out.println("\n--- For loop ---");
        for (int i = 0; i < fruits.size(); i++) {
            System.out.println(fruits.get(i));
        }
        
        System.out.println("\n--- Enhanced for loop ---");
        for (String fruit : fruits) {
            System.out.println(fruit);
        }
        
        System.out.println("\n--- Iterator ---");
        Iterator<String> iterator = fruits.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
        
        System.out.println("\n--- forEach with lambda (Java 8+) ---");
        fruits.forEach(fruit -> System.out.println(fruit));
        
        // Bulk operations
        ArrayList<String> moreFruits = new ArrayList<>();
        moreFruits.add("Kiwi");
        moreFruits.add("Pear");
        
        fruits.addAll(moreFruits);
        System.out.println("After addAll: " + fruits);
        
        // Convert to array
        String[] fruitArray = fruits.toArray(new String[0]);
        System.out.println("Array length: " + fruitArray.length);
        
        // Clear all
        fruits.clear();
        System.out.println("Is empty? " + fruits.isEmpty());
        
        // Performance: ensure capacity
        ArrayList<Integer> numbers = new ArrayList<>(100); // Initial capacity
        numbers.ensureCapacity(1000); // Ensure capacity for 1000 elements
    }
}

LinkedList — Doubly Linked List

Best for: Frequent insertions/deletions at ends or middle

LinkedListDemo.java
import java.util.*;

public class LinkedListDemo {
    public static void main(String[] args) {
        LinkedList<String> linkedList = new LinkedList<>();
        
        // Add elements
        linkedList.add("First");
        linkedList.add("Second");
        linkedList.add("Third");
        
        // Add at specific positions
        linkedList.addFirst("Zero");     // Add at beginning
        linkedList.addLast("Fourth");     // Add at end
        linkedList.add(2, "OnePointFive"); // Add at index
        
        System.out.println("LinkedList: " + linkedList);
        
        // Queue operations
        linkedList.offer("Fifth");    // Add to end (queue)
        linkedList.offerFirst("Negative"); // Add to front
        linkedList.offerLast("Sixth");     // Add to end
        
        // Stack operations
        linkedList.push("PushMe");    // Add to front
        
        // Retrieve elements
        String first = linkedList.getFirst();
        String last = linkedList.getLast();
        String element = linkedList.get(3);
        
        System.out.println("First: " + first + ", Last: " + last);
        
        // Remove elements
        linkedList.removeFirst();
        linkedList.removeLast();
        linkedList.remove(2);
        linkedList.remove("Second");
        
        // Queue removal
        String polled = linkedList.poll();     // Remove and return first
        String polledFirst = linkedList.pollFirst();
        String polledLast = linkedList.pollLast();
        
        // Stack removal
        String popped = linkedList.pop();      // Remove and return first
        
        System.out.println("After removals: " + linkedList);
        
        // Peek without removing
        String peek = linkedList.peek();
        String peekFirst = linkedList.peekFirst();
        String peekLast = linkedList.peekLast();
        
        // Use as Queue (FIFO)
        LinkedList<Integer> queue = new LinkedList<>();
        queue.offer(1);  // Enqueue
        queue.offer(2);
        queue.offer(3);
        System.out.println("Queue poll: " + queue.poll()); // 1
        
        // Use as Stack (LIFO)
        LinkedList<Integer> stack = new LinkedList<>();
        stack.push(1);   // Push
        stack.push(2);
        stack.push(3);
        System.out.println("Stack pop: " + stack.pop());   // 3
    }
}

Vector — Legacy Thread-Safe List

VectorDemo.java
import java.util.*;

public class VectorDemo {
    public static void main(String[] args) {
        // Vector is synchronized (thread-safe but slower)
        Vector<String> vector = new Vector<>();
        
        // Add elements
        vector.add("Element 1");
        vector.add("Element 2");
        vector.addElement("Element 3"); // Legacy method
        
        // Vector-specific methods
        System.out.println("Capacity: " + vector.capacity());
        System.out.println("Size: " + vector.size());
        
        // Enumeration (legacy iteration)
        Enumeration<String> enumeration = vector.elements();
        while (enumeration.hasMoreElements()) {
            System.out.println(enumeration.nextElement());
        }
        
        // Trim capacity to size
        vector.trimToSize();
        System.out.println("Capacity after trim: " + vector.capacity());
        
        // Set initial capacity and increment
        Vector<Integer> customVector = new Vector<>(20, 5); // Initial 20, grow by 5
    }
}

Performance Comparison

ListPerformanceComparison.java
import java.util.*;

public class ListPerformanceComparison {
    public static void main(String[] args) {
        int size = 100000;
        
        // ArrayList vs LinkedList performance
        List<Integer> arrayList = new ArrayList<>();
        List<Integer> linkedList = new LinkedList<>();
        
        // 1. Add at end
        long start = System.nanoTime();
        for (int i = 0; i < size; i++) arrayList.add(i);
        long arrayListAddTime = System.nanoTime() - start;
        
        start = System.nanoTime();
        for (int i = 0; i < size; i++) linkedList.add(i);
        long linkedListAddTime = System.nanoTime() - start;
        
        System.out.println("Add at end - ArrayList: " + arrayListAddTime/1e6 + "ms");
        System.out.println("Add at end - LinkedList: " + linkedListAddTime/1e6 + "ms");
        
        // 2. Add at beginning
        start = System.nanoTime();
        for (int i = 0; i < 1000; i++) arrayList.add(0, i);
        long arrayListAddFirst = System.nanoTime() - start;
        
        start = System.nanoTime();
        for (int i = 0; i < 1000; i++) linkedList.add(0, i);
        long linkedListAddFirst = System.nanoTime() - start;
        
        System.out.println("\nAdd at beginning - ArrayList: " + arrayListAddFirst/1e6 + "ms");
        System.out.println("Add at beginning - LinkedList: " + linkedListAddFirst/1e6 + "ms");
        
        // 3. Random access
        start = System.nanoTime();
        for (int i = 0; i < 10000; i++) arrayList.get(i);
        long arrayListGet = System.nanoTime() - start;
        
        start = System.nanoTime();
        for (int i = 0; i < 10000; i++) linkedList.get(i);
        long linkedListGet = System.nanoTime() - start;
        
        System.out.println("\nRandom access - ArrayList: " + arrayListGet/1e6 + "ms");
        System.out.println("Random access - LinkedList: " + linkedListGet/1e6 + "ms");
        
        // When to use each:
        // ArrayList: Random access, iteration, adding/removing at end
        // LinkedList: Adding/removing at beginning or middle, implementing queues/stacks
    }
}

Sets: HashSet, TreeSet, LinkedHashSet

HashSet — Unordered, No Duplicates

HashSetDemo.java
import java.util.*;
import java.util.Objects;

public class HashSetDemo {
    public static void main(String[] args) {
        // Create HashSet
        HashSet<String> set = new HashSet<>();
        
        // Add elements
        set.add("Apple");
        set.add("Banana");
        set.add("Orange");
        set.add("Apple"); // Duplicate - will not be added
        set.add("Mango");
        
        System.out.println("HashSet: " + set); // Order not guaranteed
        
        // Check size
        System.out.println("Size: " + set.size());
        
        // Check existence
        System.out.println("Contains Banana? " + set.contains("Banana"));
        
        // Remove element
        set.remove("Orange");
        
        // Iteration
        System.out.println("\nIterating HashSet:");
        for (String fruit : set) {
            System.out.println(fruit);
        }
        
        // HashSet with custom objects (requires hashCode() and equals())
        HashSet<Person> people = new HashSet<>();
        people.add(new Person("Alice", 25));
        people.add(new Person("Bob", 30));
        people.add(new Person("Alice", 25)); // Duplicate - won't be added
        
        System.out.println("People size: " + people.size());
        
        // Bulk operations
        HashSet<String> set1 = new HashSet<>(Arrays.asList("A", "B", "C"));
        HashSet<String> set2 = new HashSet<>(Arrays.asList("B", "C", "D"));
        
        // Union
        HashSet<String> union = new HashSet<>(set1);
        union.addAll(set2);
        System.out.println("Union: " + union);
        
        // Intersection
        HashSet<String> intersection = new HashSet<>(set1);
        intersection.retainAll(set2);
        System.out.println("Intersection: " + intersection);
        
        // Difference
        HashSet<String> difference = new HashSet<>(set1);
        difference.removeAll(set2);
        System.out.println("Difference (set1 - set2): " + difference);
        
        // Load factor and capacity
        HashSet<Integer> customSet = new HashSet<>(100, 0.75f); // Initial capacity, load factor
    }
}

class Person {
    String name;
    int age;
    
    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        Person person = (Person) obj;
        return age == person.age && Objects.equals(name, person.name);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

TreeSet — Sorted Set

TreeSetDemo.java
import java.util.*;

public class TreeSetDemo {
    public static void main(String[] args) {
        // Natural ordering (ascending)
        TreeSet<Integer> numbers = new TreeSet<>();
        numbers.add(5);
        numbers.add(2);
        numbers.add(8);
        numbers.add(1);
        numbers.add(9);
        numbers.add(3);
        
        System.out.println("TreeSet (sorted): " + numbers);
        
        // Custom ordering with Comparator
        TreeSet<String> reverseSet = new TreeSet<>(Comparator.reverseOrder());
        reverseSet.add("Apple");
        reverseSet.add("Banana");
        reverseSet.add("Orange");
        System.out.println("Reverse order: " + reverseSet);
        
        // TreeSet methods
        System.out.println("First: " + numbers.first());
        System.out.println("Last: " + numbers.last());
        System.out.println("Lower than 5: " + numbers.lower(5));   // Greatest element < 5
        System.out.println("Higher than 5: " + numbers.higher(5)); // Smallest element > 5
        System.out.println("Floor of 4: " + numbers.floor(4));     // Greatest element ≤ 4
        System.out.println("Ceiling of 6: " + numbers.ceiling(6)); // Smallest element ≥ 6
        
        // Subsets
        SortedSet<Integer> subSet = numbers.subSet(2, 8); // 2 inclusive, 8 exclusive
        System.out.println("Subset [2,8): " + subSet);
        
        SortedSet<Integer> headSet = numbers.headSet(5); // Elements < 5
        System.out.println("HeadSet (<5): " + headSet);
        
        SortedSet<Integer> tailSet = numbers.tailSet(5); // Elements ≥ 5
        System.out.println("TailSet (≥5): " + tailSet);
        
        // Polling
        System.out.println("Poll first: " + numbers.pollFirst());
        System.out.println("Poll last: " + numbers.pollLast());
        System.out.println("After polling: " + numbers);
        
        // TreeSet with custom objects (must implement Comparable)
        TreeSet<Student> students = new TreeSet<>();
        students.add(new Student("Alice", 85));
        students.add(new Student("Bob", 92));
        students.add(new Student("Charlie", 78));
        
        System.out.println("\nStudents sorted by grade:");
        for (Student s : students) {
            System.out.println(s);
        }
    }
}

class Student implements Comparable<Student> {
    String name;
    int grade;
    
    Student(String name, int grade) {
        this.name = name;
        this.grade = grade;
    }
    
    @Override
    public int compareTo(Student other) {
        return Integer.compare(this.grade, other.grade);
    }
    
    @Override
    public String toString() {
        return name + ": " + grade;
    }
}

LinkedHashSet — Maintains Insertion Order

LinkedHashSetDemo.java
import java.util.*;

public class LinkedHashSetDemo {
    public static void main(String[] args) {
        // Maintains insertion order
        LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();
        
        linkedHashSet.add("Third");
        linkedHashSet.add("First");
        linkedHashSet.add("Second");
        linkedHashSet.add("Fourth");
        
        System.out.println("LinkedHashSet (insertion order): " + linkedHashSet);
        
        // Compare with HashSet
        HashSet<String> hashSet = new HashSet<>(linkedHashSet);
        System.out.println("HashSet (no order): " + hashSet);
        
        // TreeSet (sorted order)
        TreeSet<String> treeSet = new TreeSet<>(linkedHashSet);
        System.out.println("TreeSet (sorted): " + treeSet);
        
        // When to use LinkedHashSet: When you need unique elements AND insertion order
    }
}

Maps: HashMap, TreeMap, LinkedHashMap

HashMap — Key-Value Pairs

HashMapDemo.java
import java.util.*;

public class HashMapDemo {
    public static void main(String[] args) {
        // Create HashMap
        HashMap<String, Integer> ages = new HashMap<>();
        
        // Put key-value pairs
        ages.put("Alice", 25);
        ages.put("Bob", 30);
        ages.put("Charlie", 35);
        ages.put("Alice", 26); // Overwrites previous value
        
        System.out.println("HashMap: " + ages);
        
        // Get values
        Integer aliceAge = ages.get("Alice");
        System.out.println("Alice's age: " + aliceAge);
        
        // Get with default
        Integer davidAge = ages.getOrDefault("David", 0);
        System.out.println("David's age (default): " + davidAge);
        
        // Check existence
        System.out.println("Contains Bob? " + ages.containsKey("Bob"));
        System.out.println("Contains age 30? " + ages.containsValue(30));
        
        // Remove
        ages.remove("Charlie");
        System.out.println("After removal: " + ages);
        
        // Iterate through entries
        System.out.println("\nIterating through HashMap:");
        for (Map.Entry<String, Integer> entry : ages.entrySet()) {
            System.out.println(entry.getKey() + " -> " + entry.getValue());
        }
        
        // Iterate through keys
        System.out.println("\nKeys: " + ages.keySet());
        
        // Iterate through values
        System.out.println("Values: " + ages.values());
        
        // Compute methods
        ages.putIfAbsent("Eve", 28);
        ages.compute("Alice", (k, v) -> v + 1); // Increment age
        ages.computeIfAbsent("Frank", k -> 40); // Add if absent
        ages.computeIfPresent("Bob", (k, v) -> v + 5); // Modify if present
        
        System.out.println("After compute operations: " + ages);
        
        // Merge
        ages.merge("Alice", 30, Integer::sum);
        System.out.println("After merge: " + ages);
        
        // Replace
        ages.replace("Bob", 35);
        ages.replace("Eve", 28, 29); // Replace only if current value is 28
        
        // Get all entries
        Set<Map.Entry<String, Integer>> entries = ages.entrySet();
        
        // Create HashMap from another map
        HashMap<String, Integer> copy = new HashMap<>(ages);
        
        // Performance: initial capacity and load factor
        HashMap<String, String> optimized = new HashMap<>(100, 0.9f);
    }
}

TreeMap — Sorted Map

TreeMapDemo.java
import java.util.*;

public class TreeMapDemo {
    public static void main(String[] args) {
        // Natural ordering
        TreeMap<String, Integer> scores = new TreeMap<>();
        scores.put("Charlie", 85);
        scores.put("Alice", 95);
        scores.put("Bob", 78);
        scores.put("David", 92);
        
        System.out.println("TreeMap (sorted by key): " + scores);
        
        // Custom ordering (reverse alphabetical)
        TreeMap<String, Integer> reverseMap = new TreeMap<>(Comparator.reverseOrder());
        reverseMap.putAll(scores);
        System.out.println("Reverse order: " + reverseMap);
        
        // Navigation methods
        System.out.println("First key: " + scores.firstKey());
        System.out.println("Last key: " + scores.lastKey());
        System.out.println("Lower key than C: " + scores.lowerKey("Charlie"));
        System.out.println("Higher key than C: " + scores.higherKey("Charlie"));
        System.out.println("Floor key (≤ B): " + scores.floorKey("Bob"));
        System.out.println("Ceiling key (≥ B): " + scores.ceilingKey("Bob"));
        
        // Submaps
        SortedMap<String, Integer> subMap = scores.subMap("B", "D"); // B inclusive, D exclusive
        System.out.println("Submap [B,D): " + subMap);
        
        SortedMap<String, Integer> headMap = scores.headMap("C"); // Keys < C
        System.out.println("HeadMap (<C): " + headMap);
        
        SortedMap<String, Integer> tailMap = scores.tailMap("C"); // Keys ≥ C
        System.out.println("TailMap (≥C): " + tailMap);
        
        // Poll entries
        Map.Entry<String, Integer> firstEntry = scores.pollFirstEntry();
        Map.Entry<String, Integer> lastEntry = scores.pollLastEntry();
        System.out.println("Removed first: " + firstEntry);
        System.out.println("Removed last: " + lastEntry);
        System.out.println("After polling: " + scores);
        
        // TreeMap with custom comparator for values
        TreeMap<Integer, String> ageToName = new TreeMap<>();
        ageToName.put(25, "Alice");
        ageToName.put(30, "Bob");
        ageToName.put(22, "Charlie");
        
        // Get nearest keys
        System.out.println("Nearest age to 28: " + ageToName.ceilingKey(28));
        System.out.println("Nearest age to 28 (lower): " + ageToName.floorKey(28));
    }
}

LinkedHashMap — Maintains Insertion or Access Order

LinkedHashMapDemo.java
import java.util.*;

public class LinkedHashMapDemo {
    public static void main(String[] args) {
        // Insertion order (default)
        LinkedHashMap<String, Integer> insertionOrder = new LinkedHashMap<>();
        insertionOrder.put("Third", 3);
        insertionOrder.put("First", 1);
        insertionOrder.put("Second", 2);
        
        System.out.println("Insertion order: " + insertionOrder);
        
        // Access order (LRU cache)
        LinkedHashMap<String, Integer> accessOrder = new LinkedHashMap<>(16, 0.75f, true);
        accessOrder.put("A", 1);
        accessOrder.put("B", 2);
        accessOrder.put("C", 3);
        
        System.out.println("Initial access order: " + accessOrder);
        
        accessOrder.get("A");
        System.out.println("After accessing A: " + accessOrder); // A moves to end
        
        accessOrder.get("B");
        System.out.println("After accessing B: " + accessOrder);
        
        // Simple LRU Cache implementation
        class LRUCache<K, V> extends LinkedHashMap<K, V> {
            private final int maxSize;
            
            LRUCache(int maxSize) {
                super(16, 0.75f, true);
                this.maxSize = maxSize;
            }
            
            @Override
            protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
                return size() > maxSize;
            }
        }
        
        LRUCache<String, Integer> cache = new LRUCache<>(3);
        cache.put("One", 1);
        cache.put("Two", 2);
        cache.put("Three", 3);
        System.out.println("Cache: " + cache);
        
        cache.put("Four", 4); // Removes eldest (One)
        System.out.println("After adding Four: " + cache);
        
        cache.get("Two");
        cache.put("Five", 5); // Removes Three (least recently used)
        System.out.println("Final cache: " + cache);
    }
}

Queues and Deques

Queue Interface

QueueDemo.java
import java.util.*;

public class QueueDemo {
    public static void main(String[] args) {
        // PriorityQueue - elements ordered by priority
        PriorityQueue<Integer> pq = new PriorityQueue<>();
        
        // Add elements
        pq.add(5);
        pq.add(2);
        pq.add(8);
        pq.add(1);
        pq.add(9);
        
        System.out.println("PriorityQueue: " + pq);
        System.out.println("Head (peek): " + pq.peek());
        
        // Remove elements (always smallest first)
        System.out.println("Poll: " + pq.poll());
        System.out.println("After poll: " + pq);
        
        // PriorityQueue with custom comparator
        PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Comparator.reverseOrder());
        maxHeap.addAll(Arrays.asList(5, 2, 8, 1, 9));
        System.out.println("Max heap: " + maxHeap);
        System.out.println("Max heap poll: " + maxHeap.poll());
        
        // PriorityQueue with custom objects
        PriorityQueue<Task> taskQueue = new PriorityQueue<>((t1, t2) -> 
            Integer.compare(t2.priority, t1.priority)); // Higher priority first
        
        taskQueue.add(new Task("Low priority", 1));
        taskQueue.add(new Task("High priority", 10));
        taskQueue.add(new Task("Medium priority", 5));
        
        System.out.println("\nProcessing tasks by priority:");
        while (!taskQueue.isEmpty()) {
            System.out.println(taskQueue.poll());
        }
        
        // ArrayDeque as Queue (FIFO)
        Queue<String> arrayDequeQueue = new ArrayDeque<>();
        arrayDequeQueue.offer("First");
        arrayDequeQueue.offer("Second");
        arrayDequeQueue.offer("Third");
        
        System.out.println("\nArrayDeque as Queue:");
        System.out.println("Poll: " + arrayDequeQueue.poll());
        System.out.println("Poll: " + arrayDequeQueue.poll());
    }
    
    static class Task {
        String name;
        int priority;
        
        Task(String name, int priority) {
            this.name = name;
            this.priority = priority;
        }
        
        @Override
        public String toString() {
            return name + " (priority: " + priority + ")";
        }
    }
}

Deque Interface — Double Ended Queue

DequeDemo.java
import java.util.*;

public class DequeDemo {
    public static void main(String[] args) {
        // ArrayDeque - resizable array implementation
        ArrayDeque<String> deque = new ArrayDeque<>();
        
        // Add at both ends
        deque.addFirst("First");
        deque.addLast("Last");
        deque.offerFirst("New First");
        deque.offerLast("New Last");
        
        System.out.println("Deque: " + deque);
        
        // Peek at both ends
        System.out.println("Peek First: " + deque.peekFirst());
        System.out.println("Peek Last: " + deque.peekLast());
        
        // Remove from both ends
        System.out.println("Remove First: " + deque.removeFirst());
        System.out.println("Remove Last: " + deque.removeLast());
        System.out.println("After removals: " + deque);
        
        // Stack operations (LIFO)
        ArrayDeque<Integer> stack = new ArrayDeque<>();
        stack.push(1);  // push at front
        stack.push(2);
        stack.push(3);
        
        System.out.println("\nStack (LIFO):");
        System.out.println("Pop: " + stack.pop()); // 3
        System.out.println("Pop: " + stack.pop()); // 2
        
        // Queue operations (FIFO)
        ArrayDeque<Integer> queue = new ArrayDeque<>();
        queue.add(1);   // add at end
        queue.add(2);
        queue.add(3);
        
        System.out.println("\nQueue (FIFO):");
        System.out.println("Remove: " + queue.remove()); // 1
        System.out.println("Remove: " + queue.remove()); // 2
        
        // Performance: ArrayList vs LinkedList vs ArrayDeque
        int size = 100000;
        
        // Test as Queue
        Queue<Integer> arrayDequeQueue = new ArrayDeque<>();
        Queue<Integer> linkedListQueue = new LinkedList<>();
        
        long start = System.nanoTime();
        for (int i = 0; i < size; i++) arrayDequeQueue.offer(i);
        for (int i = 0; i < size; i++) arrayDequeQueue.poll();
        long arrayDequeTime = System.nanoTime() - start;
        
        start = System.nanoTime();
        for (int i = 0; i < size; i++) linkedListQueue.offer(i);
        for (int i = 0; i < size; i++) linkedListQueue.poll();
        long linkedListTime = System.nanoTime() - start;
        
        System.out.println("\nQueue Performance (offer + poll " + size + " items):");
        System.out.println("ArrayDeque: " + arrayDequeTime/1e6 + "ms");
        System.out.println("LinkedList: " + linkedListTime/1e6 + "ms");
        
        // Use ArrayDeque when you need:
        // - Fast add/remove at both ends
        // - No null elements
        // - Better performance than LinkedList
        // - Stack or Queue implementation
    }
}

Quick Reference Card

Collection Ordering Duplicates Nulls Thread-Safe Best For
ArrayListInsertionYesYesNoRandom access, iteration
LinkedListInsertionYesYesNoFrequent insert/delete
HashSetNoneNoOne nullNoUnique elements, fast lookup
TreeSetSortedNoNoNoSorted unique elements
LinkedHashSetInsertionNoOne nullNoUnique + insertion order
HashMapNoneKeys:No, Values:YesYesNoFast key-value lookup
TreeMapSorted by keyKeys:NoNoNoSorted key-value pairs
LinkedHashMapInsertion/AccessKeys:NoYesNoOrdered key-value pairs
PriorityQueuePriorityYesNoNoPriority-based processing
ArrayDequeFIFO/LIFOYesNoNoStack/Queue operations

java.util.Collections

The Collections class provides static methods for operating on collections.

Basic Operations

CollectionsBasicDemo.java
import java.util.*;

public class CollectionsBasicDemo {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        Collections.addAll(list, 5, 2, 8, 1, 9, 3, 7, 4, 6);
        System.out.println("Original: " + list);
        Collections.sort(list);
        System.out.println("Sorted: " + list);
        Collections.sort(list, Comparator.reverseOrder());
        System.out.println("Reverse sorted: " + list);
        Collections.sort(list);
        int index = Collections.binarySearch(list, 5);
        System.out.println("Index of 5: " + index);
        Collections.reverse(list);
        System.out.println("Reversed: " + list);
        Collections.shuffle(list);
        System.out.println("Shuffled: " + list);
        Collections.rotate(list, 2);
        System.out.println("Rotated by 2: " + list);
        Collections.swap(list, 0, list.size() - 1);
        System.out.println("Swapped first and last: " + list);
        Collections.replaceAll(list, 5, 99);
        System.out.println("Replaced 5 with 99: " + list);
        Collections.fill(list, 0);
        System.out.println("Filled with zeros: " + list);
    }
}

Min, Max, Frequency

CollectionsStatsDemo.java
import java.util.*;

public class CollectionsStatsDemo {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 9, 2, 7, 2, 6);
        int min = Collections.min(numbers);
        int max = Collections.max(numbers);
        System.out.println("Min: " + min + ", Max: " + max);
        List<String> words = Arrays.asList("apple", "banana", "cherry", "date");
        String shortest = Collections.min(words, Comparator.comparingInt(String::length));
        String longest = Collections.max(words, Comparator.comparingInt(String::length));
        System.out.println("Shortest: " + shortest + ", Longest: " + longest);
        int frequency = Collections.frequency(numbers, 2);
        System.out.println("Frequency of 2: " + frequency);
        List<Integer> list1 = Arrays.asList(1, 2, 3);
        List<Integer> list2 = Arrays.asList(4, 5, 6);
        List<Integer> list3 = Arrays.asList(3, 4, 5);
        System.out.println("list1 & list2 disjoint? " + Collections.disjoint(list1, list2));
        System.out.println("list1 & list3 disjoint? " + Collections.disjoint(list1, list3));
    }
}

Creating Special Collections

CollectionsFactoryDemo.java
import java.util.*;

public class CollectionsFactoryDemo {
    public static void main(String[] args) {
        List<String> modifiable = new ArrayList<>(Arrays.asList("a", "b", "c"));
        List<String> unmodifiable = Collections.unmodifiableList(modifiable);
        List<String> synced = Collections.synchronizedList(modifiable);
        System.out.println("Empty list: " + Collections.emptyList());
        System.out.println("Singleton: " + Collections.singletonList("only"));
        System.out.println("Empty set: " + Collections.emptySet());
        System.out.println("Empty map: " + Collections.emptyMap());
        System.out.println("Checked list: " + Collections.checkedList(modifiable, String.class));
        System.out.println("Unmodifiable copy: " + unmodifiable);
        System.out.println("Synchronized list: " + synced);
    }
}

Custom Sorting with Collections

CollectionsSortingDemo.java
import java.util.*;

class Person {
    private final String name;
    private final int age;

    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    String getName() { return name; }
    int getAge() { return age; }

    @Override
    public String toString() {
        return name + " (" + age + ")";
    }
}

public class CollectionsSortingDemo {
    public static void main(String[] args) {
        List<Person> people = new ArrayList<>();
        people.add(new Person("Charlie", 30));
        people.add(new Person("Alice", 25));
        people.add(new Person("Bob", 28));
        Collections.sort(people, Comparator.comparing(Person::getName));
        System.out.println("By name: " + people);
        Collections.sort(people, Comparator.comparingInt(Person::getAge));
        System.out.println("By age: " + people);
    }
}

java.util.Arrays

The Arrays class contains static methods for array manipulation and comparison.

Basic Array Operations

ArraysBasicDemo.java
import java.util.Arrays;

public class ArraysBasicDemo {
    public static void main(String[] args) {
        int[] nums = {5, 2, 8, 1, 9};
        System.out.println("As list: " + Arrays.toString(nums));
        Arrays.sort(nums);
        System.out.println("Sorted: " + Arrays.toString(nums));
        System.out.println("Binary search 8: " + Arrays.binarySearch(nums, 8));
        int[] filled = new int[5];
        Arrays.fill(filled, 7);
        System.out.println("Filled: " + Arrays.toString(filled));
        int[] copy = Arrays.copyOf(nums, nums.length);
        System.out.println("Copy: " + Arrays.toString(copy));
        System.out.println("Equals: " + Arrays.equals(nums, copy));
    }
}

Multidimensional Arrays

ArraysMultiDimDemo.java
import java.util.Arrays;

public class ArraysMultiDimDemo {
    public static void main(String[] args) {
        int[][] matrix = {{1, 2}, {3, 4}};
        System.out.println("deepToString: " + Arrays.deepToString(matrix));
        int[][] other = {{1, 2}, {3, 4}};
        System.out.println("deepEquals: " + Arrays.deepEquals(matrix, other));
        System.out.println("deepHashCode: " + Arrays.deepHashCode(matrix));
    }
}

Parallel Sort

ArraysParallelDemo.java
import java.util.Arrays;

public class ArraysParallelDemo {
    public static void main(String[] args) {
        int[] data = {9, 1, 8, 2, 7, 3, 6, 4, 5};
        Arrays.parallelSort(data);
        System.out.println("parallelSort: " + Arrays.toString(data));
    }
}

Arrays and Streams

ArraysStreamDemo.java
import java.util.Arrays;

public class ArraysStreamDemo {
    public static void main(String[] args) {
        int[] nums = {1, 2, 3, 4, 5};
        int sum = Arrays.stream(nums).sum();
        System.out.println("Sum via stream: " + sum);
        Arrays.stream(nums).forEach(n -> System.out.print(n + " "));
        System.out.println();
    }
}

java.util.Objects

The Objects class offers null-safe helpers introduced in Java 7.

Null-Safe Object Utilities

ObjectsBasicDemo.java
import java.util.Objects;

public class ObjectsBasicDemo {
    public static void main(String[] args) {
        String a = "Java";
        String b = null;
        System.out.println("equals: " + Objects.equals(a, b));
        System.out.println("hash: " + Objects.hash(a, "util"));
        System.out.println("toString: " + Objects.toString(b, "default"));
        System.out.println("isNull: " + Objects.isNull(b));
        System.out.println("nonNull: " + Objects.nonNull(a));
        System.out.println("compare: " + Objects.compare(10, 20, Integer::compareTo));
        try {
            Objects.requireNonNull(b, "value required");
        } catch (NullPointerException ex) {
            System.out.println("requireNonNull: " + ex.getMessage());
        }
    }
}

java.util.Scanner

Scanner breaks input into tokens using a delimiter pattern (default: whitespace).

Basic Scanner Usage

ScannerBasicDemo.java
import java.util.Scanner;

public class ScannerBasicDemo {
    public static void main(String[] args) {
        String input = "42 Hello";
        Scanner scanner = new Scanner(input);
        int num = scanner.nextInt();
        String word = scanner.next();
        System.out.println("Number: " + num);
        System.out.println("Word: " + word);
        System.out.println("Has next: " + scanner.hasNext());
        scanner.close();
    }
}

Reading Primitive Types

ScannerTypesDemo.java
import java.util.Scanner;

public class ScannerTypesDemo {
    public static void main(String[] args) {
        String data = "100 3.14 true 25";
        Scanner sc = new Scanner(data);
        int i = sc.nextInt();
        double d = sc.nextDouble();
        boolean b = sc.nextBoolean();
        long l = sc.nextLong();
        System.out.println(i + ", " + d + ", " + b + ", " + l);
        sc.close();
    }
}

Custom Delimiters

ScannerDelimiterDemo.java
import java.util.Scanner;

public class ScannerDelimiterDemo {
    public static void main(String[] args) {
        String csv = "one,two,three,four";
        Scanner sc = new Scanner(csv).useDelimiter(",");
        while (sc.hasNext()) {
            System.out.println(sc.next());
        }
        sc.close();
    }
}

Input Sources

ScannerSourcesDemo.java
import java.io.*;
import java.util.Scanner;

public class ScannerSourcesDemo {
    public static void main(String[] args) throws IOException {
        Scanner fromString = new Scanner("alpha beta");
        System.out.println("String source: " + fromString.next());
        fromString.close();

        StringReader reader = new StringReader("line1\nline2");
        Scanner fromReader = new Scanner(reader);
        System.out.println("Reader line: " + fromReader.nextLine());
        fromReader.close();
    }
}

Pattern Matching

ScannerPatternDemo.java
import java.util.Scanner;
import java.util.regex.MatchResult;

public class ScannerPatternDemo {
    public static void main(String[] args) {
        String text = "Order ID: 12345 Amount: 99.50";
        Scanner sc = new Scanner(text);
        if (sc.findInLine("ID: (\d+)") != null) {
            MatchResult mr = sc.match();
            System.out.println("ID token: " + mr.group(1));
        }
        sc.close();
    }
}

Try-With-Resources

ScannerTryWithResources.java
import java.util.Scanner;

public class ScannerTryWithResources {
    public static void main(String[] args) {
        try (Scanner sc = new Scanner("auto close demo")) {
            System.out.println(sc.nextLine());
        }
    }
}

java.util.Random & ThreadLocalRandom

Generate pseudo-random numbers for simulations, games, and sampling.

Basic Random Usage

RandomBasicDemo.java
import java.util.Random;

public class RandomBasicDemo {
    public static void main(String[] args) {
        Random random = new Random();
        System.out.println("nextInt: " + random.nextInt(100));
        System.out.println("nextDouble: " + random.nextDouble());
        System.out.println("nextBoolean: " + random.nextBoolean());
        System.out.println("nextGaussian: " + random.nextGaussian());
    }
}

Seeded Random

RandomSeededDemo.java
import java.util.Random;

public class RandomSeededDemo {
    public static void main(String[] args) {
        Random r1 = new Random(42L);
        Random r2 = new Random(42L);
        System.out.println("Same seed r1: " + r1.nextInt(1000));
        System.out.println("Same seed r2: " + r2.nextInt(1000));
    }
}

Random Selection

RandomSelectionDemo.java
import java.util.*;

public class RandomSelectionDemo {
    public static void main(String[] args) {
        List<String> items = new ArrayList<>(Arrays.asList("A", "B", "C", "D"));
        Random random = new Random();
        String pick = items.get(random.nextInt(items.size()));
        System.out.println("Random pick: " + pick);
        Collections.shuffle(items, random);
        System.out.println("Shuffled: " + items);
    }
}

Random Streams (Java 8+)

RandomStreamsDemo.java
import java.util.Random;

public class RandomStreamsDemo {
    public static void main(String[] args) {
        Random random = new Random();
        random.ints(5, 1, 10).forEach(n -> System.out.print(n + " "));
        System.out.println();
        random.doubles(3, 0.0, 1.0).forEach(d -> System.out.printf("%.3f ", d));
        System.out.println();
    }
}

ThreadLocalRandom

ThreadLocalRandomDemo.java
import java.util.concurrent.ThreadLocalRandom;

public class ThreadLocalRandomDemo {
    public static void main(String[] args) {
        ThreadLocalRandom tlr = ThreadLocalRandom.current();
        System.out.println("nextInt: " + tlr.nextInt(1, 101));
        System.out.println("nextDouble: " + tlr.nextDouble(0.0, 1.0));
        System.out.println("nextLong: " + tlr.nextLong());
    }
}

java.util.UUID

Universally unique identifiers for entities, sessions, and database keys.

UUID Basics

UUIDBasicDemo.java
import java.util.UUID;

public class UUIDBasicDemo {
    public static void main(String[] args) {
        UUID random = UUID.randomUUID();
        System.out.println("randomUUID: " + random);
        UUID parsed = UUID.fromString(random.toString());
        System.out.println("fromString: " + parsed);
        UUID nameBased = UUID.nameUUIDFromBytes("nikhil-learnhub".getBytes());
        System.out.println("nameUUIDFromBytes: " + nameBased);
    }
}

java.util.Properties

Key-value configuration maps, often loaded from .properties files.

Properties Basics

PropertiesBasicDemo.java
import java.io.*;
import java.util.Properties;

public class PropertiesBasicDemo {
    public static void main(String[] args) throws IOException {
        Properties props = new Properties();
        props.setProperty("app.name", "LearnHub");
        props.setProperty("app.version", "1.0");
        System.out.println("getProperty: " + props.getProperty("app.name"));
        StringWriter writer = new StringWriter();
        props.store(writer, "Demo Properties");
        System.out.println(writer);
        Properties loaded = new Properties();
        loaded.load(new StringReader("key=value\n"));
        System.out.println("loaded: " + loaded.getProperty("key"));
    }
}

java.util.StringTokenizer

Legacy tokenizer for splitting strings (prefer String.split or Scanner in new code).

StringTokenizer Demo

StringTokenizerDemo.java
import java.util.StringTokenizer;

public class StringTokenizerDemo {
    public static void main(String[] args) {
        String data = "Java:is:powerful";
        StringTokenizer st = new StringTokenizer(data, ":");
        while (st.hasMoreTokens()) {
            System.out.println(st.nextToken());
        }
        StringTokenizer st2 = new StringTokenizer("one two three");
        System.out.println("countTokens: " + st2.countTokens());
    }
}

java.util.Optional (Java 8+)

Optional reduces null checks by modeling values that may be absent.

Optional Basics

OptionalBasicDemo.java
import java.util.Optional;

public class OptionalBasicDemo {
    public static void main(String[] args) {
        Optional<String> present = Optional.of("Java");
        Optional<String> empty = Optional.empty();
        System.out.println("orElse: " + empty.orElse("fallback"));
        Optional<String> mapped = present.map(String::toUpperCase);
        System.out.println("map: " + mapped.orElse(""));
        Optional<String> filtered = present.filter(s -> s.length() > 3);
        filtered.ifPresent(v -> System.out.println("ifPresent: " + v));
        System.out.println("orElseGet: " + empty.orElseGet(() -> "generated"));
    }
}

Complete Examples

Combine Scanner, Properties, Collections, and Optional in one workflow.

Integrated Utility Example

CompleteExamplesDemo.java
import java.io.*;
import java.util.*;

public class CompleteExamplesDemo {
    public static void main(String[] args) throws IOException {
        String config = "theme=dark\nlang=en";
        Properties props = new Properties();
        props.load(new StringReader(config));

        String input = "42 admin";
        try (Scanner sc = new Scanner(input)) {
            int id = sc.nextInt();
            String role = sc.next();
            List<String> roles = new ArrayList<>(Arrays.asList(role, "guest"));
            Collections.sort(roles);
            Optional<String> theme = Optional.ofNullable(props.getProperty("theme"));
            System.out.println("User " + id + " roles=" + roles + " theme=" + theme.orElse("default"));
        }
    }
}