Tag: hashset

  • “Which Java Collection Should I Use?”

    “Which Java Collection Should I Use?”

    Choosing the Right Data Structure for Real-World Problems

    Have you ever asked yourself which data structure you should use to store your collection of items?
    It’s a common question every Java developer faces, especially when writing scalable and maintainable code.

    Java’s Collections Framework offers a variety of implementations for lists, sets, and maps—but using the right one in the right context can make a big difference in performance, readability, and correctness.

    This post explores six commonly used collection types:
    👉 ArrayList, LinkedList, HashSet, TreeSet, HashMap, and TreeMap
    And it gives real-world examples where each shines, so you can think critically about which one fits your situation best.


    ArrayList – When Fast Access Matters

    Real-World Problem: You’re building a search suggestion dropdown that displays a list of recently typed queries.

    • Why it fits:
      ArrayList gives constant-time access by index. You can instantly show the N-th recent search. Since you’re only adding at the end or reading in order, it’s perfect.
    • Avoid if: You’re doing lots of insertions or deletions in the middle of the list.

    🔁 LinkedList – When Frequent Insertions or Deletions Are Needed

    Real-World Problem: You’re building a playlist feature where users can frequently rearrange songs (move up/down), insert between, or remove them.

    • Why it fits:
      LinkedList is a doubly-linked list. It handles frequent adds/removals from anywhere in the list faster than an ArrayList, especially for large lists.
    • Avoid if: You need random access to elements; get(index) is slow.

    🧺 HashSet – When Uniqueness Is the Only Requirement

    Real-World Problem: You’re storing a list of all email addresses that signed up for a beta program, and duplicates must be prevented.

    • Why it fits:
      HashSet automatically ensures uniqueness and gives constant-time add, remove, and contains operations. Perfect for preventing duplicate entries.
    • Avoid if: You care about insertion order or need sorted output.

    🌲 TreeSet – When You Need Sorted, Unique Data

    Real-World Problem: You’re storing a leaderboard with player scores and want to keep them in ascending or descending order, without duplicates.

    • Why it fits:
      TreeSet keeps elements sorted according to their natural order (or a custom comparator) and ensures uniqueness.
    • Avoid if: You don’t need sorting—HashSet is faster.

    🗂️ HashMap – When You Need Key-Based Fast Lookup

    Real-World Problem: You’re building a dictionary app where users type a word and you fetch its definition instantly.

    • Why it fits:
      HashMap offers constant-time retrieval for keys. It’s ideal for any key-value lookup scenario, like config values, routing tables, or caching.
    • Avoid if: You need sorted keys or order-sensitive operations.

    🧭 TreeMap – When You Need Sorted Keys

    Real-World Problem: You’re storing time-series sensor data where each data point has a timestamp as the key, and you want to retrieve them in chronological order.

    • Why it fits:
      TreeMap keeps keys sorted, making it perfect for time-based logs, ranges, or navigation systems.
    • Avoid if: Key order doesn’t matter—HashMap is more performant.

    📚 Code Examples + Performance Overview

    We’ll now walk through each collection with:

    1. 🔧 A practical Java code example
    2. ⚙️ Performance notes for common operations

    ArrayList – Fast Access, Ordered Collection

    List<String> recentSearches = new ArrayList<>();
    recentSearches.add("Java Streams");
    recentSearches.add("Spring Boot");
    recentSearches.add("Docker");
    
    // Fast access by index
    System.out.println(recentSearches.get(1)); // Output: Spring Boot
    

    ⚙️ Performance

    OperationComplexity
    add() (end)O(1)
    get(index)O(1)
    add(index)O(n)
    remove(index)O(n)

    ✅ Use for: access-heavy, append-only collections
    ⚠️ Avoid for: frequent middle inserts/removals


    🔁 LinkedList – Efficient Inserts & Deletes

    List<String> playlist = new LinkedList<>();
    playlist.add("Song A");
    playlist.add("Song B");
    playlist.add(1, "Song C"); // Insert in the middle
    
    playlist.remove("Song A");
    System.out.println(playlist); // [Song C, Song B]
    

    ⚙️ Performance

    OperationComplexity
    add()/remove (ends)O(1)
    add/remove (middle)O(n)
    get(index)O(n)

    ✅ Use for: queues, stacks, dynamic lists
    ⚠️ Avoid for: random access needs


    🧺 HashSet – Unique, Unordered Items

    Set<String> emails = new HashSet<>();
    emails.add("john@example.com");
    emails.add("john@example.com"); // Duplicate ignored
    emails.add("jane@example.com");
    
    System.out.println(emails); // [john@example.com, jane@example.com] (order not guaranteed)
    

    ⚙️ Performance

    OperationComplexity
    add()O(1)
    remove()O(1)
    contains()O(1)

    ✅ Use for: deduplication, membership checks
    ⚠️ Avoid for: ordered or sorted results


    🌲 TreeSet – Unique & Sorted

    Set<Integer> scores = new TreeSet<>();
    scores.add(300);
    scores.add(100);
    scores.add(200);
    
    System.out.println(scores); // [100, 200, 300]
    

    ⚙️ Performance

    OperationComplexity
    add()O(log n)
    remove()O(log n)
    contains()O(log n)

    ✅ Use for: sorted data, range queries
    ⚠️ Avoid for: high-volume add/remove where sorting isn’t needed


    🗂️ HashMap – Key-Based Lookup (Unordered)

    Map<String, String> dictionary = new HashMap<>();
    dictionary.put("Java", "A programming language");
    dictionary.put("Spring", "A Java framework");
    
    System.out.println(dictionary.get("Java")); // A programming language
    

    ⚙️ Performance

    OperationComplexity
    put()O(1)
    get(key)O(1)
    remove()O(1)

    ✅ Use for: fast lookups, caching, config storage
    ⚠️ Avoid for: sorted or ordered key access


    🧭 TreeMap – Sorted Keys, Navigable

    Map<Integer, String> logs = new TreeMap<>();
    logs.put(1700, "Start process");
    logs.put(1730, "Mid-point reached");
    logs.put(1800, "Process complete");
    
    System.out.println(logs); // Keys in sorted order: {1700=..., 1730=..., 1800=...}
    

    ⚙️ Performance

    OperationComplexity
    put()O(log n)
    get()O(log n)
    remove()O(log n)

    ✅ Use for: sorted maps, time-series, navigation by key
    ⚠️ Avoid for: massive inserts where sorting isn’t needed


    ArrayList or TreeMap?

    Use ArrayList + Collections.sort() if:

    • You add many elements quickly, then sort once before accessing them.
    • You don’t need automatic sorting after each insert.
    • You can tolerate O(n log n) cost only when needed.
    List<Integer> list = new ArrayList<>();
    list.add(5);
    list.add(1);
    list.add(3);
    
    Collections.sort(list); // O(n log n) when you want sorting
    

    Pros:

    • Faster inserts (O(1) per element).
    • More efficient if sorting is infrequent.

    Cons:

    • Data is not always sorted.
    • Sorting must be manually triggered.

    Use TreeMap (or TreeSet) if:

    • You need elements always kept in sorted order.
    • You frequently add, remove, and retrieve items in sorted order.
    • Sorted access (e.g., range queries or iteration in order) is frequent.
    Map<Integer, String> sortedMap = new TreeMap<>();
    sortedMap.put(5, "five");
    sortedMap.put(1, "one");
    sortedMap.put(3, "three");
    // Always sorted by keys
    

    Pros:

    • Automatically sorted.
    • Great for range-based access, floor/ceiling queries.

    Cons:

    • Slower insertions (O(log n)).
    • Slightly higher memory overhead.

    🔍 Summary Table

    FeatureArrayList + sort()TreeMap
    Insert performanceO(1)O(log n)
    Maintain sorted order❌ (manual sort)✅ (always sorted by key)
    Sorted iterationAfter sort onlyAlways sorted
    Use caseBatch sort, occasional orderContinuous ordered access

    💡 Choose TreeMap if sorting is a core requirement throughout the lifecycle.
    Choose ArrayList + sort() if you’re optimizing for bulk inserts followed by occasional sorting.

    Summary of all java collections

    CollectionTypeImplementsMain PurposeKey Characteristics
    ArrayListListRandomAccess, ListDynamic array for fast access and iterationFast random access, slow inserts/removals in the middle, ordered, allows duplicates
    LinkedListListDeque, ListDoubly-linked list for efficient insertion/deletionSlower access time than ArrayList, fast inserts/removals, ordered, allows duplicates
    VectorListRandomAccess, ListThread-safe dynamic array (legacy)Synchronized, slower than ArrayList in single-threaded contexts
    StackListVector (extends)LIFO stack implementationThread-safe, legacy class, now replaced by Deque
    HashSetSetSetStore unique elements with no orderBacked by HashMap, no duplicates, fast lookup
    LinkedHashSetSetSetStore unique elements maintaining insertion orderPreserves insertion order, slightly slower than HashSet
    TreeSetSetNavigableSetStore sorted unique elementsSorted order (natural or custom), slower than HashSet, no duplicates
    PriorityQueueQueueQueueQueue elements with priority (min-heap by default)Elements ordered by priority, not thread-safe
    ArrayDequeQueueDequeResizable array for double-ended queue (stack or queue)Faster than Stack or LinkedList for stack/queue operations
    HashMapMapMapStore key-value pairs with no specific orderAllows one null key, fast lookup, not synchronized
    LinkedHashMapMapMapKey-value pairs maintaining insertion orderPredictable iteration order, slightly slower than HashMap
    TreeMapMapNavigableMapSorted map based on keysSorted by natural or custom comparator, slower than HashMap
    HashtableMapMapThread-safe key-value store (legacy)Synchronized, slower, no null keys or values
    ConcurrentHashMapMapConcurrentMapThread-safe, high-performance concurrent mapAllows concurrent reads and controlled writes, no null keys/values
    EnumSetSetSetSpecialized set for use with enum typesFast and compact, only works with enums
    EnumMapMapMapSpecialized map for enum keysEfficient and compact, only works with enum keys
    WeakHashMapMapMapMap with weak keys for memory-sensitive cachingKeys are GC’d when no longer referenced, good for caches
    IdentityHashMapMapMapMap that uses == instead of .equals() for comparing keysNot commonly used, but useful in specific identity-based contexts