Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Mastering Java Collections: From Fundamentals to Implementation Details

Tech 1

Java Collection Hierarchy

The Java Collections Framework is divided into two primary branches to address different use cases:

  • Single-column collections: Store individual elements.
  • Double-column collections (Maps): Store key-value pairs.

Collection Interface Fundamentals

Key Interfaces and Implementations

  • List Interface: Ordered, allows duplicates, and provides indexed access.
    • Common Implementations: ArrayList, LinkedList
  • Set Interface: No duplicates, no index.
    • Common Implementations: HashSet, LinkedHashSet, TreeSet

Characteristics of Collection Types

Collection Type Order Duplicates Indexed
ArrayList / LinkedList Maintained Alllowed Yes
HashSet Not Guaranteed Not Allowed No
LinkedHashSet Maintained Not Allowed No
TreeSet Sorted (Asc) Not Allowed No

Common Methods in Collection

Since Collection is the root interface for all single-column collections, understanding its methods is crucial for using List and Set.

import java.util.ArrayDeque;
import java.util.Collection;
import java.util.HashSet;
import java.util.Arrays;

public class CollectionBasics {
    public static void main(String[] args) {
        // Using HashSet to demonstrate generic Collection methods
        Collection<String> toolkit = new HashSet<>();

        // 1. Add elements
        toolkit.add("Hammer");
        toolkit.add("Wrench");
        toolkit.add("Hammer"); // Duplicate, will not be added in Set
        toolkit.add("Screwdriver");
        System.out.println("Current tools: " + toolkit);

        // 2. Check size and emptiness
        System.out.println("Size: " + toolkit.size());
        System.out.println("Is empty? " + toolkit.isEmpty());

        // 3. Check existence
        System.out.println("Has Wrench? " + toolkit.contains("Wrench"));

        // 4. Remove element
        toolkit.remove("Wrench");
        System.out.println("After removal: " + toolkit);

        // 5. Convert to Array
        String[] toolArray = toolkit.toArray(new String[0]);
        System.out.println("Array version: " + Arrays.toString(toolArray));

        // 6. Merge collections
        Collection<String> extraTools = new HashSet<>();
        extraTools.add("Pliers");
        extraTools.add("Drill");
        toolkit.addAll(extraTools);
        System.out.println("Merged tools: " + toolkit);

        // 7. Clear
        // toolkit.clear();
    }
}

Traversing Collections

1. Using Iterator

The Iterator is a universal way to traverse collections.

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class IteratorDemo {
    public static void main(String[] args) {
        Collection<String> fruits = new ArrayList<>();
        fruits.add("Apple");
        fruits.add("Banana");
        fruits.add("Cherry");

        Iterator<String> iter = fruits.iterator();
        while (iter.hasNext()) {
            String fruit = iter.next();
            System.out.println(fruit);
        }
    }
}

2. Enhanced For Loop (For-Each)

A simplified syntax that works for any Iterable object.

Collection<String> colors = new ArrayList<>();
colors.add("Red");
colors.add("Green");
colors.add("Blue");

for (String color : colors) {
    System.out.println(color);
}

String[] colorArray = {"Yellow", "Purple"};
for (String c : colorArray) {
    System.out.println(c);
}

3. Lambda Expressions (forEach)

Available since Java 8, allowing functional-style iteration.

import java.util.ArrayList;
import java.util.Collection;

public class LambdaTraverse {
    public static void main(String[] args) {
        Collection<String> names = new ArrayList<>();
        names.add("Alice");
        names.add("Bob");
        names.add("Charlie");

        // Standard Lambda
        names.forEach(name -> System.out.println(name));

        // Method Reference (Most concise)
        names.forEach(System.out::println);
    }
}

Practical Example: Managing Media Items

Define a Film class to store data.

public class Film {
    private String title;
    private double rating;
    private String director;

    public Film(String title, double rating, String director) {
        this.title = title;
        this.rating = rating;
        this.director = director;
    }

    @Override
    public String toString() {
        return "Film{title='" + title + "', rating=" + rating + ", director='" + director + "'}";
    }
    
    // Getters and Setters...
}

Usage with Collection:

import java.util.ArrayList;
import java.util.Collection;

public class MediaDemo {
    public static void main(String[] args) {
        Collection<Film> library = new ArrayList<>();
        library.add(new Film("The Godfather", 9.2, "Coppola"));
        library.add(new Film("Pulp Fiction", 8.9, "Tarantino"));

        for (Film f : library) {
            System.out.println(f);
        }
    }
}

List Interface Details

Specific List Methods

List implementations allow operations based on element position.

import java.util.LinkedList;
import java.util.List;

public class ListManipulation {
    public static void main(String[] args) {
        List<String> crew = new LinkedList<>();
        crew.add("Scout");
        crew.add("Soldier");
        crew.add("Medic");

        // Insert at specific index
        crew.add(1, "Engineer");

        // Replace element
        crew.set(0, "Sniper");

        // Get element
        System.out.println("Index 2: " + crew.get(2));

        // Remove by index
        crew.remove(3);
        
        System.out.println(crew);
    }
}

List Traversal Methods

  1. Standard For Loop: Uses get(index).
  2. Iterator / For-Each / Lambda: As described in the Collection section.

ArrayList vs. LinkedList

ArrayList

  • Structure: Dynamic Array.
  • Pros: Fast random access (get is O(1)).
  • Cons: Slow insertion/deletion in the middle (requires shifting).
  • Growth: Defaults to 10, grows by 50% when full.

LinkedList

  • Structure: Doubly Linked List.
  • Pros: Fast insertion/deletion at ends (Good for Queues/Stacks).
  • Cons: Slow search (O(n)).

Implementing a Queue with LinkedList

import java.util.LinkedList;

public class QueueExample {
    public static void main(String[] args) {
        LinkedList<String> queue = new LinkedList<>();
        
        // Enqueue
        queue.addLast("Customer A");
        queue.addLast("Customer B");
        
        // Dequeue
        while (!queue.isEmpty()) {
            System.out.println("Serving: " + queue.removeFirst());
        }
    }
}

Implementing a Stack with LinkedList

import java.util.LinkedList;

public class StackExample {
    public static void main(String[] args) {
        LinkedList<String> stack = new LinkedList<>();
        
        // Push
        stack.push("Plate 1");
        stack.push("Plate 2");
        
        // Pop
        System.out.println("Removed: " + stack.pop());
        System.out.println("Removed: " + stack.pop());
    }
}

Set Interface Details

HashSet

  • Order: Unpredictable.
  • Mechanism: Hash Table (Array + Linked List/Tree).
import java.util.HashSet;
import java.util.Set;

public class HashSetDemo {
    public static void main(String[] args) {
        Set<Integer> uniqueNumbers = new HashSet<>();
        uniqueNumbers.add(10);
        uniqueNumbers.add(20);
        uniqueNumbers.add(10); // Ignored
        
        System.out.println(uniqueNumbers); // e.g., [20, 10]
    }
}

LinkedHashSet

  • Order: Insertion Order.
  • Mechanism: Hash Table + Doubly Linked List.
import java.util.LinkedHashSet;
import java.util.Set;

public class LinkedHashSetDemo {
    public static void main(String[] args) {
        Set<String> orderedSet = new LinkedHashSet<>();
        orderedSet.add("First");
        orderedSet.add("Second");
        orderedSet.add("Third");
        
        System.out.println(orderedSet); // [First, Second, Third]
    }
}

TreeSet

  • Order: Sorted (Natural or Custom).
  • Mechanism: Red-Black Tree.
import java.util.Set;
import java.util.TreeSet;

public class TreeSetDemo {
    public static void main(String[] args) {
        Set<String> sortedSet = new TreeSet<>();
        sortedSet.add("Zebra");
        sortedSet.add("Apple");
        sortedSet.add("Monkey");
        
        System.out.println(sortedSet); // [Apple, Monkey, Zebra]
    }
}

Hashing and HashSet Mechanics

Hash Codes

Every object has a hashCode(). In a HashSet, the hash code determines the bucket location.

public class HashDemo {
    public static void main(String[] args) {
        String text1 = new String("Java");
        String text2 = new String("Java");
        
        // Same content usually yields same hashcode
        System.out.println(text1.hashCode() == text2.hashCode()); // true
    }
}

Handling Duplicates in Custom Objects

To make HashSet or TreeSet work correctly with custom objects (like removing duplicate Student objects), you must override equals() and hashCode() for HashSet, or implement Comparable for TreeSet.

import java.util.Objects;

public class Trainee {
    private String name;
    private int id;

    public Trainee(String name, int id) {
        this.name = name;
        this.id = id;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Trainee trainee = (Trainee) o;
        return id == trainee.id;
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}

Sorting with TreeSet

1. Implementing Comparable (Natural Order)

public class Product implements Comparable<Product> {
    private String name;
    private double price;

    public Product(String name, double price) {
        this.name = name;
        this.price = price;
    }

    @Override
    public int compareTo(Product other) {
        // Sort by price ascending
        return Double.compare(this.price, other.price);
    }
    
    @Override
    public String toString() {
        return name + ": $" + price;
    }
}

2. Using Comparator (Custom Order)

import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;

public class ComparatorDemo {
    public static void main(String[] args) {
        // Sort by name length
        Set<String> words = new TreeSet<>(Comparator.comparingInt(String::length));
        words.add("Java");
        words.add("Python");
        words.add("C");
        
        System.out.println(words); // [C, Java, Python]
    }
}

Selection Guide

Requirement Recommended Collection
Indexed, Duplicates, Fast Read ArrayList
Indexed, Duplicates, Fast Add/Remove at ends LinkedList
No Duplicates, Fast General Ops, No Order HashSet
No Duplicates, Fast Ops, Keep Insert Order LinkedHashSet
No Duplicates, Sorted Order TreeSet

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.