0% found this document useful (0 votes)
5 views

Java Collections From Fundamentals to Best Practices

The document provides an overview of the Java Collections Framework, detailing its core components such as Lists, Sets, and Maps, along with their functionalities and best practices. It emphasizes the advantages of using collections over arrays, including dynamic sizing, performance optimization, and improved code maintainability. Additionally, it discusses specific implementations like ArrayList and LinkedList, highlighting their use cases and performance characteristics.

Uploaded by

akshat_space
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views

Java Collections From Fundamentals to Best Practices

The document provides an overview of the Java Collections Framework, detailing its core components such as Lists, Sets, and Maps, along with their functionalities and best practices. It emphasizes the advantages of using collections over arrays, including dynamic sizing, performance optimization, and improved code maintainability. Additionally, it discusses specific implementations like ArrayList and LinkedList, highlighting their use cases and performance characteristics.

Uploaded by

akshat_space
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 79

Java Collections: From

Fundamentals to Best
Practices

By Subhash Chander Joshi


• Introduction to the Java Collections Framework

• Working with Lists (ArrayList, LinkedList )

• Working with Sets (HashSet, TreeSet, LinkedHashSet)

• Working with Maps (HashMap, TreeMap, LinkedHashMap)

• Best Practices
AGENDA

• Demo
Introduction
What is a Collection?

A Collection is like organized containers.

It's an object whose primary purpose is to hold and


manage a group of other objects, which we call
elements.

• Group multiple items together Introduction to


the Java
• Organize data Collections
Framework
• Perform operations efficiently
Why not just use arrays?

While arrays are also used to store multiple items,


Collections offer several advantages

• Dynamic Size

• Rich Functionality Introduction to


the Java
• Variety of Structures Collections
Framework

CODE DEMO
Reduced Programming Effort:
• The framework provides pre-built, well-tested, and
efficient data structures (Lists, Sets, Maps, etc.).
• You don't need to "reinvent the wheel" by
implementing these structures yourself.
• Focus on your application logic instead of low-level
data management. Benefits of Using
the Java
Collections
Framework
Increased Performance:
• Collections are implemented with performance in
mind, often using optimized algorithms.
• Choosing the right collection for the task can
significantly impact your application's speed and
efficiency (e.g., fast lookups in a HashMap).
Benefits of Using
the Java
Collections
Framework
Improved Code Reusability and Maintainability:
The framework provides a consistent and well-defined
API (interfaces like List, Set, Map).
Code becomes more readable and understandable as
you work with familiar collection types and methods.

Benefits of Using
the Java
Collections
Framework
Enhanced Flexibility and Adaptability:
• A wide variety of collection implementations are
available, each suited for different needs (e.g.,
ordered lists, unique elements, key-value pairs).
• Easily switch between different collection types if your
application's requirements change, without significant Benefits of Using
code rewrites (due to the common interfaces). the Java
Collections
Framework
Interoperability:
• Collections work seamlessly with other parts of the
Java ecosystem.
• Standardized way to handle groups of objects,
making it easier to exchange data between different
components of your application or with external
libraries. Benefits of Using
the Java
Collections
Framework
Interoperability:
• Collections work seamlessly with other parts of the
Java ecosystem.
• Standardized way to handle groups of objects,
making it easier to exchange data between different
components of your application or with external
libraries. Core Interfaces
and Classes of
the Collections
Framework
Collection:

• (The Root Interface)Represents a group of objects


(elements).

• Defines the most basic operations that all collections


support, such as adding (add()), removing (remove()),
Core Interfaces
checking size (size()), and checking if it's empty of the
(isEmpty()). Collections
Framework
• It's the parent interface for more specific collection
types like List and Set.

Key Characteristic:

• Represents a general group of elements.


Working with Lists (ArrayList,
LinkedList)
List:
• Represents an ordered collection (also known as a
sequence).
• Allows duplicate elements.
• Elements can be accessed by their integer index
(position).
• Provides methods for adding, removing, and Core Interfaces
accessing elements at specific positions.
of the
Collections
Key Characteristic: Framework
• Ordered sequence
• Allows duplicates
• Indexed access.
Adding Elements:
add(E element):
• Appends the specified element to the end of the list.

add(int index, E element):


• Inserts the specified element at the specified position in
the list.
• Shifts the element currently at that position (if any) and List: Commonly
any subsequent elements to the right. Used Methods

addAll(Collection<? extends E> c):


• Appends all of the elements in the specified collection to
the end of this list, in the order that they are returned by
the specified collection's iterator.
• Returns true if the list changed.
Accessing Elements:

get(int index):

• Returns the element at the specified position in the list.

Modifying Elements:

set(int index, E element): List: Commonly


• Replaces the element at the specified position in this list
Used Methods
with the specified element.

• Returns the element previously at the specified position.


Removing Elements:
remove(int index):
• Removes the element at the specified position in this list.
Shifts any subsequent elements to the left.
• Returns the element that was removed.
remove(Object o):
• Removes the first occurrence of the specified element
from this list, if it is present.
List: Commonly
• Returns true if an element was removed. Used Methods
removeAll(Collection<?> c):
• Removes all of this list's elements that are also contained
in the specified collection.
• Returns true if the list changed.
removeIf(Predicate<? super E> filter):
• Removes all elements of this collection that satisfy the
given predicate.
Searching for Elements:
indexOf(Object o):
Returns the index of the first occurrence of the specified
element in this list, or -1 if this list does not contain the
element.
lastIndexOf(Object o):
• Returns the index of the last occurrence of the specified
element in this list, or -1 if this list does not contain the
element. List: Commonly
contains(Object o): Used Methods
• Returns true if this list contains the specified element.
containsAll(Collection<?> c):
• Returns true if this list contains all of the elements of the
specified collection.
Getting Information:

size():
• Returns the number of elements in this list.
isEmpty():
• Returns true if this list contains no elements.

Creating Sublists: List: Commonly


Used Methods
subList(int fromIndex, int toIndex):
• Returns a view of the portion of this list between the
specified fromIndex (inclusive) and toIndex (exclusive).
• Changes to the sub-list are reflected in the original list,
and vice-versa.
Iterating Over the List:

iterator():

• Returns an iterator over the elements in this list in proper


sequence.

listIterator():

• Returns a list iterator over the elements in this list (allows List: Commonly
bidirectional traversal and modification). Used Methods

listIterator(int index):

• Returns a list iterator over the elements in this list, starting


at the specified position.

Enhanced For-Loop (for-each): CODE DEMO

• Can be used to iterate through the elements in order.


Underlying Data Structure:
• Uses a dynamic array (also known as a resizable array)
to store its elements.
Initial Capacity:
• When an ArrayList is created, it has an initial capacity
(default is typically 10, but can be specified in the
constructor).
Implementing List: Dynamic Resizing:
ArrayList • When you try to add an element to a full ArrayList, it
automatically creates a new, larger array (typically 1.5
times the size of the old array).
• The elements from the old array are copied to the new
array.
Performance Characteristics (Big O Notation)

• get(index): O(1)
• set(index, element): O(1)
• add(element) (appending to the end):O(1)
• add(index, element) (inserting at a specific index):
O(n)
• remove(index): O(n)
Implementing List: • remove(Object element): O(n)
ArrayList
• contains(Object element): O(n)
• size(): O(1)
Use Cases - When to Use ArrayList

• Frequent Random Access: When you need to access


elements frequently by their index (get() operation).
• Appending Elements: When you primarily add elements to
the end of the list.
• Lists with a Relatively Stable Size: When you have a good
estimate of the list's size upfront, you can set the initial
capacity to minimize resizing overhead.
Implementing List:
Simple Lists without Frequent Mid-List Insertions/Deletions: If
ArrayList •
your application involves mostly adding to the end and
reading elements, ArrayList is a good choice.
Underlying Data Structure:
• Uses a doubly-linked list.

• Each element (node) in the list stores:


• The actual data.
• A reference (pointer) to the previous node in the
list.
• A reference (pointer) to the next node in the list.

No Contiguous Memory:
• Elements in a LinkedList are not stored in contiguous
Implementing List: memory locations.
LinkedList • The order is maintained by the pointers between the
nodes.

No Initial Capacity:
• LinkedList does not have a fixed initial capacity like
ArrayList.
• It grows dynamically as elements are added.
Performance Characteristics (Big O Notation)

• get(index): O(n)
• set(index, element): O(n)
• add(element) (appending to the end): O(1)
• add(index, element) (inserting at a specific index):
O(n)
• remove(index): O(n)
• remove(Object element): O(n)
• contains(Object element): O(n)
• size(): O(1)
Implementing List:
LinkedList • addFirst(element), addLast(element),
offerFirst(element), offerLast(element): O(1)

• removeFirst(), removeLast(), pollFirst(), pollLast(),


getFirst(), getLast(), peekFirst(), peekLast(): O(1)

(These are Deque interface methods also implemented


by LinkedList).
Use Cases - When to Use LinkedList

Frequent Insertions and Deletions in the Middle:


Due to the constant-time pointer manipulation once the
position is found, LinkedList is more efficient than ArrayList
for frequent insertions and deletions at arbitrary positions.

Implementing Queues and Deques: LinkedList naturally


implements the Queue and Deque interfaces efficiently,
making it a good choice for these data structures.

Implementing List: Operations at the Head and Tail: Adding and removing
LinkedList elements from the beginning or end of a LinkedList are
very fast (O(1)).

When Memory Usage is Not a Primary Concern: LinkedList


typically uses more memory per element compared to
ArrayList due to the storage of the previous and next
pointers.
When to Choose Which:

Choose ArrayList when:


• You need fast random access to elements.
• Your primary operations involve accessing elements
and appending to the end.
• Insertions and deletions in the middle are infrequent.
• Memory efficiency is a significant concern.

Choose LinkedList when:


Comparing • You have frequent insertions and deletions of elements
at arbitrary positions.
ArrayList and • You need to implement queues or deques.
LinkedList • Performance of adding/removing from the beginning
or end is critical.
• Memory overhead from pointers is acceptable.
Implementing List (for ordered sequences allowing
duplicates):

Vector (Legacy):
• Similar to ArrayList but is synchronized (thread-safe).
• Generally less performant than ArrayList in single-
threaded environments.
• Largely superseded by ArrayList

Stack (Legacy):
• Extends Vector and implements a LIFO (Last-In, First-
Legacy Classes Out) stack.
• Provides methods like push(), pop(), and peek().
• Consider using ArrayDeque for better performance in
modern applications.
Working with Sets (HashSet, TreeSet,
LinkedHashSet)
Set:
• Models the mathematical concept of a set.
• Operations include adding, removing, and checking
for the presence of elements.

Key Characteristic:
• No Duplicate Elements: Each element in a Set must be
unique. Adding a duplicate element has no effect (it's Core Interfaces
typically ignored). of the
• Unordered (Generally): The order in which elements Collections
are stored and retrieved is not necessarily predictable Framework
or consistent(unless a specific implementation like
LinkedHashSet is used).
• Null Element (Implementation Dependent): Some Set
implementations (like HashSet and LinkedHashSet)
allow one null element, while others (like TreeSet) do
not.
Adding Elements:

add(E element):
• Adds the specified element to this set if it is not
already present.
• Returns true if the set was modified (i.e., the element
was added), and false otherwise.
Set:
Commonly Used
addAll(Collection<? extends E> c):
Methods
• Adds all of the elements in the specified collection to
this set if they are not already present.
• Returns true if this set changed as a result of the call.
Removing Elements:

remove(Object o):
• Removes the specified element from this set if it is
present.
• Returns true if the set contained the element (or
equivalently, if the set was modified as a result of the
call). Set:
removeAll(Collection<?> c): Commonly Used
• Removes from this set all of its elements that are
Methods
contained in the specified collection.
• Returns true if this set changed as a result of the call.
removeIf(Predicate<? super E> filter):
• Removes all elements of this collection that satisfy the
given predicate.
Checking for Elements:

contains(Object o):
• Returns true if this set contains the specified element.
containsAll(Collection<?> c):
• Returns true if this set contains all of the elements of the
specified collection.
Set:
Commonly Used
Getting Information: Methods

size():
• Returns the number of elements in this set (its cardinality).
isEmpty():
• Returns true if this set contains no elements.
Iterating Over the Set:

iterator():

• Returns an iterator over the elements in this set.

• The elements are returned in no particular order


(unless the implementation guarantees an order).
Set:
Enhanced For-Loop (for-each): Commonly Used
Methods
• Can be used to iterate through the elements.

• The order is implementation-dependent.

CODE DEMO
Set Operations (Implemented through methods, but
conceptually important):

• Union (using addAll()): Adding all elements from


another set to the current set effectively performs a
union operation.

• Intersection (requires manual iteration or streams): Set:


Finding elements common to two sets. Commonly Used
Methods
• Difference (using removeAll()): Removing elements
from the current set that are present in another set.
Underlying Data Structure:
• Internally uses a HashMap.
• The elements of the HashSet are stored as keys in the
HashMap, and a dummy Object instance is used as the
value for all keys.

Implementing Set: No Guaranteed Order:


HashSet • HashSet does not guarantee any specific order of
elements.
• The order can change over time.
Hashing Mechanism:
Relies on the hashCode() and equals() methods of the
objects being stored to ensure uniqueness.

• When you try to add an element, its hashCode() is


calculated to determine the bucket where it should be
stored.
Implementing Set: • If another element with the same hashCode() already
HashSet exists in the bucket, the equals() method is used to
check if they are truly the same object.
• If equals() returns true, the new element is not added
(maintaining uniqueness).
Performance Characteristics (Average Case - assuming
good hashCode() distribution)

• add(element): O(1) - Constant time.


• remove(Object element): O(1) - Constant time.
• contains(Object element): O(1) - Constant time.
• size(): O(1) - Constant time.
• Iteration: O(n) - Linear time, where n is the number of
Implementing Set: elements in the set (as it needs to visit each element).
HashSet However, the order is not predictable.

Worst Case Performance (if hashCode() is poorly


implemented, leading to many collisions):
• All operations can degrade to O(n), as the HashSet
might effectively become a linked list in each bucket
Use Cases - When to Use HashSet:

Ensuring Uniqueness: When you need a collection that


stores only unique elements and the order is not
important.

Fast Lookups (contains()): When you need to quickly


check if a particular element exists in the collection.
Implementing Set:
HashSet Fast Additions and Removals: When you frequently add
and remove elements and performance is critical.

Implementing Mathematical Sets: For operations like


union, intersection, and difference (though these might
require additional logic).
Underlying Data Structure:
• Internally uses a Red-Black tree, which is a self-
balancing binary search tree.
• This data structure ensures efficient sorting and retrieval.

Sorted Order:
Elements are always maintained in a sorted order.
Implementing Set: • Natural Ordering: If the elements implement the
TreeSet Comparable interface, they are sorted according
to their compareTo() method.

• Comparator: You can provide a custom


Comparator object when creating the TreeSet to
define a specific sorting logic.
Performance Characteristics (for n elements):

• add(element): O(log n) - Logarithmic time due to the


tree traversal and balancing operations.
• remove(Object element): O(log n) - Logarithmic time
for finding and removing the element.
• contains(Object element): O(log n) - Logarithmic time
Implementing Set: for searching the element.
TreeSet • size(): O(1) - Constant time.
• Iteration: O(n) - Linear time, as it needs to visit all
elements in sorted order.
Key Methods Specific to Sorted Sets (from the SortedSet
Interface, implemented by TreeSet):

first():
• Returns the first (lowest) element currently in this set.

last():
Implementing Set: • Returns the last (highest) element currently in this set.
TreeSet
headSet(E toElement):
• Returns a view of the portion of this set whose elements
are strictly less than toElement.
• The returned set is backed by this set, so changes in the
returned set are reflected in this set, and vice-versa.
Key Methods Specific to Sorted Sets (from the SortedSet
Interface, implemented by TreeSet):

tailSet(E fromElement):
• Returns a view of the portion of this set whose elements
are greater than or equal to fromElement.
• The returned set is backed by this set, so changes in the
Implementing Set: returned set are reflected in this set, and vice-versa.
TreeSet
Key Methods Specific to Sorted Sets (from the SortedSet
Interface, implemented by TreeSet):

subSet(E fromElement, E toElement):


• Returns a view of the portion of this set whose elements
range from fromElement (inclusive) to toElement
(exclusive).
Implementing Set: • The returned set is backed by this set, so changes in the
TreeSet returned set are reflected in this set, and vice-versa.

CODE DEMO
Use Cases - When to Use TreeSet:
• Maintaining Sorted Elements: When you need a
collection that automatically keeps its elements sorted.
• Efficient Retrieval of Sorted Data: When you need to
iterate through the elements in a sorted manner.
• Implementing Sorted Sets: When you need the
properties of a Set (uniqueness) along with sorted
Implementing Set: order.
TreeSet • Range Queries: The sorted nature of TreeSet makes it
efficient for operations like finding elements within a
certain range
Underlying Data Structure:
• Internally uses a HashMap for storing elements (for
efficient uniqueness checks) and a doubly-linked list to
maintain the insertion order of elements.

Uniqueness:
• Like HashSet, LinkedHashSet ensures that all elements
are unique.
• It uses the hashCode() and equals() methods of the
elements to determine uniqueness.

Implementing Set: Insertion Order:


LinkedHashSet • The key difference from HashSet is that LinkedHashSet
maintains a doubly-linked list running through all of its
entries.
• This linked list defines the iteration ordering, which is the
order in which elements were inserted into the set.

One Null Element Allowed:


• Similar to HashSet, LinkedHashSet typically allows at
most one null element.
Performance Characteristics (Average Case):

add(element): O(1) - Constant time


remove(Object element): O(1) - Constant time
contains(Object element): O(1) - Constant time
size(): O(1) - Constant time.

Iteration: O(n) - Linear time, where n is the number of


Implementing Set: elements in the set.
LinkedHashSet
Use Cases - When to Use LinkedHashSet:

Maintaining Insertion Order: When you need a set that


guarantees uniqueness but also preserves the order in
which elements were added.

Caching Mechanisms: Can be used to implement simple


caches where the order of insertion might be relevant
(e.g., for basic LRU-like behavior if you combine it with
removals).

Implementing Set: Iterating in a Predictable Order: When you need to


LinkedHashSet process the elements of a set in the sequence they were
originally added.

Building Ordered Collections with Uniqueness: As a


foundation for other data structures or algorithms that
require both uniqueness and order.
Working with Maps (HashMap,
TreeMap, LinkedHashMap)
Map:
• Represents a collection that stores elements as key-value
pairs.
• Keys must be unique within a map; values can be
duplicates.
• Provides methods for putting (adding) key-value pairs,
getting values based on their keys, and removing entries.

Core Interfaces
Note: Map is not a subtype of the Collection interface. It of the
represents a fundamentally different way of organizing Collections
data. Framework
Key Characteristic:
• Stores key-value pairs
• Unique keys
• Values Can Be Duplicates
• No Guaranteed Order (unless a specific implementation
like LinkedHashMap or TreeMap is used)
Adding Entries:

put(K key, V value):


• Associates the specified value with the specified key
in this map.
• If the map previously contained a mapping for the
key, the old value is replaced by the specified value.
• Returns the previous value associated with the key, or Map Interface:
null if the key was not previously mapped. Common
Methods
putAll(Map<? extends K, ? extends V> m):
• Copies all of the mappings from the specified map to
this map.
• These mappings will replace any mappings that this
map had for any of the keys currently in the specified
map.
Updating Entries:

putIfAbsent(K key, V value):

• Associates the specified value with the specified key if


the key is not already associated with a value.

• Returns the previous value associated with the key, or


Map Interface:
null if there was no mapping. Common
Methods
Retrieving Values:

get(Object key):

• Returns the value to which the specified key is


mapped, or null if this map contains no mapping for
the key.
Map Interface:
Common
Methods
getOrDefault(Object key, V defaultValue):

• Returns the value to which the specified key is


mapped, or the defaultValue if this map contains no
mapping for the key.
Removing Entries:

remove(Object key):
• Removes the mapping for the specified key from this
map if it is present.
• Returns the value that was previously associated with
the key, or null if the map contained no mapping for
the key. Map Interface:
Common
remove(Object key, Object value): Methods
• Removes the entry for the specified key only if it is
currently mapped to the specified value.
• Returns true if removed, false otherwise.

clear():
• Removes all of the mappings from this map.
Checking for Keys or Values:

containsKey(Object key):
• Returns true if this map contains a mapping for the
specified key.
containsValue(Object value):
• Returns true if this map maps one or more keys to the
specified value. Map Interface:
Common
Methods
Getting Information:
size():
• Returns the number of key-value mappings in this
map.
isEmpty():
• Returns true if this map contains no key-value
mappings.
Getting Views of the Map's Contents:

keySet():
• Returns a Set view of the keys contained in this map.
• The set is backed by the map, so changes to the map
are reflected in the set, and vice-versa

values():
Map Interface:
Common
• Returns a Collection view of the values contained in Methods
this map.
• The collection is backed by the map, so changes to
the map are reflected in the collection, and vice-
versa.
Getting Views of the Map's Contents:

entrySet():
• Returns a Set view of the mappings contained in this
map. Each element in the set is a Map.
• Entry object, which represents a key-value pair.
• The set is backed by the map, so changes to the map
are reflected in the set, and vice-versa. Map Interface:
The order of the set is implementation-dependent. Common
Methods
Iterating Over the Map:

Iterating over keySet():


• Get the set of keys and iterate over it to access values
using get(key).
Iterating over values():
• Get the collection of values and iterate over them
(note that you lose the association with the keys). Map Interface:
Iterating over entrySet(): Common
Methods
• Get the set of Map.Entry objects, which allows you to
access both keys and values for each entry.
• This is the most common and efficient way to iterate
over key-value pairs.

CODE DEMO
Underlying Data Structure:

• Internally uses a hash table (an array of buckets).


• Each bucket can contain a linked list (or a tree in later
Java versions for very large buckets) of key-value pairs
(entries).

Hashing Mechanism:
• When you put a key-value pair into a HashMap, the
hashCode() method of the key is used to determine the
Implementing Map: bucket where the entry should be stored.
HashMap • If multiple keys have the same hashCode() (a collision), they
are placed in the same bucket (typically in a linked list).
• When you get a value based on a key, the hashCode() of
the key is again used to find the correct bucket, and then
the equals() method is used to find the specific key-value
pair within that bucket.
Uniqueness of Keys:
• HashMap ensures that all keys are unique.
• If you try to put a key that already exists, the old value
associated with that key is overwritten.

Null Keys and Values:


• HashMap allows one null key and multiple null values.
Implementing Map:
HashMap No Guaranteed Order:
• HashMap does not guarantee any specific order of its
entries.
• The order can change over time.
Performance Characteristics (Average Case - assuming
good hashCode() distribution):

• put(key, value): O(1) - Constant time.


• get(key): O(1) - Constant time.
• remove(key): O(1) - Constant time.
• containsKey(key): O(1) - Constant time.
• containsValue(value): O(n) - Linear time in the worst
Implementing Map: case, as it might need to iterate through all entries.
HashMap • size(): O(1) - Constant time.
• Iteration (over keys, values, or entries): O(n) - Linear
time, where n is the number of entries in the map
Worst Case Performance (if hashCode() is poorly
implemented, leading to many collisions):

• All operations can degrade to O(n), as the HashMap


might effectively become a long linked list in a single
bucket.
• Java 8 and later versions mitigate this by replacing
long linked lists with balanced trees in buckets with
Implementing Map: many collisions, improving the worst-case
HashMap
performance to O(log n) in those scenarios.
Use Cases - When to Use HashMap:

Fast Lookups: When you need to quickly retrieve values


based on their keys.

General-Purpose Key-Value Storage: For storing and


managing data where you have unique identifiers (keys)
for each piece of information (values).

Caching: Implementing simple caches where fast key-


based access is crucial.
Implementing Map:
HashMap Indexing: Creating indexes for data based on certain
attributes.

Frequency Counting: Counting the occurrences of items


in a collection.
Underlying Data Structure:
• Internally uses a Red-Black tree, which is a self-
balancing binary search tree.

Sorted Keys:
• Entries are always maintained in a sorted order based
on their keys.

Natural Ordering:
• If the keys implement the Comparable interface, they
are sorted according to their compareTo() method.
Implementing Map:
TreeMap Uniqueness of Keys:
• Like all Map implementations, TreeMap enforces
unique keys.
• If you try to put a key that already exists, the old value
is overwritten.

Comparator: You can provide a custom Comparator


object when creating the TreeMap to define a specific
sorting logic for the keys.
Performance Characteristics (for n entries):

• put(key, value): O(log n) - Logarithmic time due to the


tree traversal and balancing operations.
• get(key): O(log n) - Logarithmic time for searching the
key.
• remove(key): O(log n) - Logarithmic time for finding
and removing the entry.
Implementing Map: • containsKey(key): O(log n) - Logarithmic time for
TreeMap searching the key.
• containsValue(value): O(n) - Linear time in the worst
case, as it might need to traverse all entries.
• size(): O(1) - Constant time.
• Iteration (over keys, values, or entries): O(n) - Linear
time, as it needs to visit all entries in sorted key order.
Key Methods Specific to Sorted Maps (from the
SortedMap Interface, implemented by TreeMap):

firstKey():
• Returns the first (lowest) key currently in this map.

lastKey():
• Returns the last (highest) key currently in this map.

Implementing Map:
TreeMap headMap(K toKey):
• Returns a view of the portion of this map whose keys
are strictly less than toKey.
• The returned map is backed by this map, so changes
in the returned map are reflected in this map, and
vice-versa.
Key Methods Specific to Sorted Maps (from the
SortedMap Interface, implemented by TreeMap):

tailMap(K fromKey):
• Returns a view of the portion of this map whose keys
are greater than or equal to fromKey.
• The returned map is backed by this map, so changes
in the returned map are reflected in this map, and

Implementing Map: vice-versa.


TreeMap subMap(K fromKey, K toKey):
• Returns a view of the portion of this map whose keys
range from fromKey (inclusive) to toKey (exclusive).
• The returned map is backed by this map, so changes
in the returned map are reflected in this map, and
vice-versa.
Use Cases - When to Use TreeMap:

Maintaining Sorted Entries by Key: When you need a


map where the entries are always kept sorted according
to their keys.

Efficient Retrieval of Sorted Data: When you need to


iterate through the map's keys or entries in a sorted order.

Range Queries on Keys: The sorted nature of TreeMap


makes it efficient for operations like finding entries within
Implementing Map: a certain key range (using methods like subMap(),
headMap(), tailMap()).
TreeMap
Implementing Sorted Dictionaries or Lookups: When you
need a dictionary-like structure where the keys are
naturally ordered or need custom ordering.
Underlying Data Structure:

• Internally uses a HashMap for storing entries (for


efficient key-based lookups) and a doubly-linked list to
maintain the ordering of entries.

Uniqueness of Keys:

Implementing Map: • Like HashMap, LinkedHashMap ensures that all keys


LinkedHashMap are unique.

Null Keys and Values:


• Allows one null key and multiple null values, similar to
HashMap
Order Maintenance:

• Insertion Order (Default): Iteration through the


LinkedHashMap will return entries in the order they
were inserted.
• Access Order (Optional): Can be configured at the
time of creation.
• In access order, the linked list is updated whenever
Implementing Map: a key is accessed (via get() or put()).
LinkedHashMap • This makes it suitable for implementing LRU caches.
LinkedHashMap(int initialCapacity, float loadFactor,
boolean accessOrder):
The accessOrder parameter (boolean) determines the
ordering. Set to true for access-order, false (default) for
insertion-order.
Performance Characteristics (Average Case):

• put(key, value): O(1) - Constant time


• get(key): O(1) - Constant time
• remove(key): O(1) - Constant time
• containsKey(key): O(1) - Constant time
containsValue(value): O(n) - Linear time in the worst
case (similar to HashMap).
Implementing Map: • size(): O(1) - Constant time.
LinkedHashMap • Iteration (over keys, values, or entries): O(n) - Linear
time, where n is the number of entries in the map.
Use Cases - When to Use LinkedHashMap:
Maintaining Insertion Order:
• When you need a map where the order of iteration is
the same as the order in which keys were inserted.
• This is useful for scenarios where the order has
semantic meaning or for producing predictable
output.
Implementing LRU Caches:
Implementing Map:
• When configured for access order, LinkedHashMap
LinkedHashMap
makes it easy to implement LRU caches.
• The least recently used entries will naturally move to
the beginning of the iteration order.
• You can override the removeEldestEntry() method to
automatically remove the oldest entry when the
cache reaches a certain size.
Use Cases - When to Use LinkedHashMap:

Caching with Predictable Eviction:


• Even in insertion order mode, if you need a simple
cache with a predictable eviction policy (e.g., FIFO-
like based on insertion), LinkedHashMap can be useful.

Implementing Map: Preserving Order from Input Data:


LinkedHashMap • When you need to process data in the same order it
was read or received, while also benefiting from the
fast lookups of a hash map.
BEST PRACTICES
Ask Yourself:
Do you need to store individual elements or key-value
pairs?
(Collection vs. Map)

Are duplicate elements allowed?


(List, Map values) vs. (Set keys) Choosing the
right collection
type
Is the order of elements important?
• Insertion order? (List, LinkedHashSet,
LinkedHashMap)
• Sorted order? (SortedSet / TreeSet, SortedMap /
TreeMap)
• Any order is fine? (HashSet, HashMap)
Interoperability:
• Collections work seamlessly with other parts of the
Java ecosystem.
• Standardized way to handle groups of objects,
making it easier to exchange data between different
components of your application or with external
libraries. Core Interfaces
and Classes of
the Collections
Framework
Ask Yourself:

Do you need indexed access?


(List - ArrayList, LinkedList, etc.)

Are you performing frequent insertions/deletions in the


middle?
(LinkedList might be better)

Do you need fast lookups by key? Choosing the


(HashMap, TreeMap, LinkedHashMap) right collection
type
What are the performance trade-offs for common
operations?
(O(1), O(log n), O(n))

Memory usage considerations?


• Ordered list with frequent random access: ArrayList
• Ordered list with frequent insertions/deletions:
LinkedList
• Unique elements, order not important, fast lookups:
HashSet
• Unique elements, maintain insertion order:
LinkedHashSet Quick Guide -
• Unique elements, maintain sorted order: TreeSet Common Scenarios
• Key-value pairs, fast lookups, order not important:
HashMap
• Key-value pairs, maintain insertion order:
LinkedHashMap
• Key-value pairs, maintain sorted order by key:
TreeMap
THANK YOU!

You might also like