Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
3 views

Java Collection Framework

The Java Collection Framework (JCF) provides a unified architecture for managing groups of objects, offering interfaces, classes, and algorithms for efficient data manipulation. Key components include interfaces like Collection, List, Set, Queue, and Map, along with their implementations such as ArrayList, HashSet, and HashMap. The framework simplifies data structure management by providing reusable implementations and common algorithms for operations like sorting and searching.

Uploaded by

Jha Avinash
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views

Java Collection Framework

The Java Collection Framework (JCF) provides a unified architecture for managing groups of objects, offering interfaces, classes, and algorithms for efficient data manipulation. Key components include interfaces like Collection, List, Set, Queue, and Map, along with their implementations such as ArrayList, HashSet, and HashMap. The framework simplifies data structure management by providing reusable implementations and common algorithms for operations like sorting and searching.

Uploaded by

Jha Avinash
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 29

‭Overview of Java Collection Framework‬

‭ he‬‭Java Collection Framework‬‭is a unified architecture‬‭for managing groups of objects. It‬


T
‭provides interfaces, classes, and algorithms to manipulate and store data efficiently.‬
‭Introduced in JDK 1.2, it eliminates the need for custom data structures by providing‬
‭reusable implementations.‬

‭Key Components‬

‭1.‬ ‭Interfaces‬‭: Define the contract or blueprint for collections.‬‭Examples:‬


‭○‬ ‭
Collection‬
‭○‬ L‭ist‬
‭‬ ‭
○ Set‬
‭○‬ ‭ Queue‬
‭○‬ ‭Map‬‭(not part of the‬‭Collection‬‭hierarchy but a key‬‭component)‬
‭2.‬ ‭Classes‬‭: Implementations of the interfaces, such as:‬
‭○‬ ‭
ArrayList‬ ‭,‬‭
LinkedList‬ ‭,‬‭
Vector‬‭(implement‬‭
List‬
‭)‬
‭○‬ H‭ashSet‬‭,‬‭TreeSet‬‭,‬‭LinkedHashSet‬‭(implement‬‭
Set‬
‭)‬
‭‬ ‭
○ PriorityQueue‬ ‭,‬‭
Deque‬‭(implement‬‭
Queue‬‭)‬
‭○‬ ‭HashMap‬‭,‬‭TreeMap‬‭,‬‭LinkedHashMap‬‭(implement‬‭
Map‬‭)‬
‭3.‬ A
‭ lgorithms‬‭: Common operations like sorting and searching,‬‭implemented via utility‬
‭classes like‬‭
Collections‬‭.‬

‭Hierarchy‬

‭Here’s a simplified hierarchy of JCF:‬

‭Vbnet code‬
java.util.Collection (Interface)‬

|- List (Interface)‬

|- ArrayList, LinkedList, Vector‬

|- Set (Interface)‬

|- HashSet, LinkedHashSet, TreeSet‬

|- Queue (Interface)‬

|- PriorityQueue, ArrayDeque‬

java.util.Map (Interface)‬

|- HashMap, TreeMap, LinkedHashMap‬

‭Key Interfaces in JCF‬

‭1. Collection Interface‬

‭‬ R
● ‭ oot interface‬‭of the framework.‬
‭●‬ ‭Methods provided:‬
‭○‬ ‭add(E e)‬ ‭,‬‭
addAll(Collection<? extends E> c)‬
‭○‬ ‭remove(Object o)‬ ‭,‬‭
removeAll(Collection<?> c)‬ ‭,‬‭
clear()‬
‭○‬ ‭contains(Object o)‬ ‭,‬‭
containsAll(Collection<?> c)‬
‭○‬ ‭size()‬‭,‬‭
isEmpty()‬
‭○‬ ‭iterator()‬

‭2. List Interface‬

‭‬ A
● ‭ n ordered collection allows duplicate elements.‬
‭●‬ ‭Examples:‬‭ArrayList‬‭,‬‭LinkedList‬‭,‬‭ Vector‬
‭●‬ ‭Methods in addition to‬‭
Collection‬
‭:‬
‭○‬ g‭et(int index)‬‭,‬‭set(int index, E element)‬
‭○‬ ‭add(int index, E element)‬
‭○‬ ‭remove(int index)‬
‭○‬ ‭indexOf(Object o)‬‭,‬‭
lastIndexOf(Object o)‬
‭○‬ ‭subList(int fromIndex, int toIndex)‬

‭3. Set Interface‬

‭‬ A
● ‭ collection that does‬‭not allow duplicate elements‬‭.‬
‭●‬ ‭Examples:‬‭ HashSet‬ ‭,‬‭
LinkedHashSet‬ ‭,‬‭
TreeSet‬
‭●‬ ‭Key Characteristics:‬
‭○‬ ‭No guarantee of order in‬‭HashSet‬ ‭.‬
‭○‬ ‭Ordered in insertion sequence for‬‭
LinkedHashSet‬‭.‬
‭○‬ ‭Sorted in natural or custom order for‬‭
TreeSet‬
‭.‬

‭4. Queue Interface‬

‭‬ A
● ‭ collection for‬‭FIFO‬‭(First-In-First-Out) operations.‬
‭●‬ ‭Examples:‬‭ PriorityQueue‬‭,‬‭ ArrayDeque‬
‭●‬ ‭Key Methods:‬
‭○‬ ‭offer(E e)‬ ‭: Adds an element.‬
‭○‬p‭oll()‬‭: Retrieves and removes the head.‬
‭‬ ‭
○ peek()‬‭: Retrieves the head without removing it.‬

‭5. Map Interface‬

‭‬ A
● ‭ collection for‬‭key-value pairs‬‭.‬
‭●‬ ‭Examples:‬‭ HashMap‬ ‭,‬‭
TreeMap‬
‭,‬‭
LinkedHashMap‬
‭●‬ ‭Methods:‬
‭○‬ p‭ut(K key, V value)‬‭,‬‭ putAll(Map<? extends K, ? extends V>‬
‭m)‬
‭○‬ ‭ get(Object key)‬‭,‬‭remove(Object key)‬
‭○‬ ‭ containsKey(Object key)‬‭,‬‭ containsValue(Object value)‬
‭○‬ ‭ keySet()‬
‭,‬‭
values()‬ ‭,‬‭
entrySet()‬

‭Detailed Analysis of ArrayList (Part 1: List)‬

‭Let’s start with‬‭


ArrayList‬
‭, a commonly used implementation‬‭of‬‭
List‬
‭.‬

‭Characteristics‬

‭‬
● ‭ ses a‬‭dynamic array‬‭to store elements.‬
U
‭●‬ ‭Allows‬‭random access‬‭(via index).‬
‭●‬ ‭Not synchronized‬‭(unsuitable for multithreading without‬‭external synchronization).‬
‭●‬ ‭Allows duplicate elements.‬

‭Common Use Cases‬

‭‬ S
● ‭ toring ordered data with frequent read operations.‬
‭●‬ ‭Maintaining a list of elements without worrying about duplicates.‬

‭Example Code‬
‭Java code‬
import java.util.ArrayList;‬

public class ArrayListExample {‬



public static void main(String[] args) {‬

‭// Create an ArrayList‬
‭ArrayList<String> names = new ArrayList<>();‬

/‭/ Add elements‬


‭names.add("Avinash");‬
‭names.add("Kumar");‬
‭names.add("Jha");‬

/‭/ Access elements‬


‭System.out.println("Name at index 1: " + names.get(1));‬

/‭/ Remove element‬


‭names.remove("Kumar");‬

‭// Iterate over elements‬


‭for (String name : names) {‬
‭System.out.println(name);‬
‭}‬

/‭/ Size of the ArrayList‬


‭System.out.println("Size: " + names.size());‬
}‬

}‬

‭Internal Working‬

‭1.‬ D ‭ ynamic Resizing‬‭: When the internal array is full,‬‭the size is increased by‬‭50%‬‭(in‬
‭JDK 1.8 and above).‬
‭2.‬ ‭Complexity‬‭:‬
‭○‬ ‭
add(E e)‬‭: O(1) (amortized)‬
‭○‬g‭et(int index)‬‭: O(1)‬
‭‬ ‭
○ remove(int index)‬ ‭: O(n)‬

‭LinkedList‬

LinkedList‬‭is another implementation of the‬‭


‭ List‬‭interface,‬‭but it is backed by a‬
‭ oubly-linked list‬‭rather than a dynamic array. This‬‭gives it different characteristics‬
d
‭compared to‬‭
ArrayList‬ ‭.‬

‭Characteristics‬

‭ .‬ D
1 ‭ ynamic in size‬‭: No need to resize like an array.‬
‭2.‬ ‭Efficient insertions and deletions‬‭: Especially in the middle of the list (O(1) for‬
‭adding/removing nodes).‬
‭3.‬ ‭Sequential access‬‭: No random access (O(n) for‬‭ get(int‬‭index)‬ ‭).‬

‭Key Differences: ArrayList vs. LinkedList‬


‭Feature‬ ‭ArrayList‬ ‭LinkedList‬

‭ nderlying Data‬
U ‭Dynamic Array‬ ‭Doubly Linked List‬
‭Structure‬

‭Access Time‬ ‭ (1) for‬‭


O get‬‭(random‬ ‭ (n) for‬‭
O get‬‭(sequential‬
‭access)‬ ‭access)‬

‭Insertion/Deletion‬ ‭O(n) in the middle‬ ‭O(1) in the middle‬

‭Memory Overhead‬ ‭Less (only elements)‬ ‭More (nodes + pointers)‬


‭Best Use Case‬ ‭Frequent reads‬ ‭Frequent insertions/deletions‬

‭Common Use Cases‬

‭ ‬ I‭mplementing‬‭queues or stacks‬‭.‬

‭●‬ ‭Frequent insertions or deletions at the start, middle, or end.‬

‭Example Code‬
‭Java code‬
import java.util.LinkedList;‬

public class LinkedListExample {‬



public static void main(String[] args) {‬

‭// Create a LinkedList‬
‭LinkedList<String> tasks = new LinkedList<>();‬

/‭/ Add elements‬


‭tasks.add("Complete Java Assignment");‬
‭tasks.add("Prepare for interview");‬
‭tasks.add("Read psychology book");‬

/‭/ Add element at the beginning and end‬


‭tasks.addFirst("Wake up");‬
‭tasks.addLast("Go to bed");‬

/‭/ Remove elements‬


‭tasks.removeFirst();‬
‭tasks.removeLast();‬

/‭/ Iterate over elements‬


‭for (String task : tasks) {‬
‭System.out.println(task);‬
‭}‬

/‭/ Access specific element‬


‭System.out.println("Task at index 1: " + tasks.get(1));‬

/‭/ Check if it contains an element‬


‭System.out.println("Contains 'Prepare for interview': " +‬
tasks.contains("Prepare for interview"));‬

}‬

}‬

‭Internal Working‬

‭●‬ ‭Node Structure‬‭: Each node contains three parts:‬‭


prev‬‭(pointer to the previous‬
‭ ode),‬‭
n data‬‭, and‬‭
next‬‭(pointer to the next node).‬
‭ ‬ ‭Operations:‬

‭○‬ ‭
add(E e)‬ ‭: O(1) for appending.‬
‭○‬g‭et(int index)‬‭: O(n), as it must traverse the list‬‭sequentially.‬
‭‬ ‭
○ remove(Object o)‬‭or‬‭remove(int index)‬ ‭: O(1) if at‬‭the start or end;‬
‭O(n) otherwise.‬

‭Set Interface‬

‭ ext, let’s dive into‬‭Set‬‭, an interface designed for‬‭collections where‬‭duplicates are not‬
N
‭allowed‬‭.‬

‭Key Implementations‬

‭1.‬ ‭HashSet‬‭:‬
‭○‬ ‭Backed by a‬‭HashMap‬‭internally.‬
‭○‬ ‭No guarantee of order‬‭.‬
‭○‬ ‭Fast operations (O(1) for add, remove, and contains).‬
‭2.‬ ‭LinkedHashSet‬‭:‬
‭○‬ ‭Extends‬‭
HashSet‬‭, but maintains‬‭insertion order‬‭.‬
‭ ‬ ‭Slightly slower than‬‭
○ HashSet‬‭due to additional overhead.‬
‭3.‬ ‭TreeSet‬‭:‬
‭○‬ ‭Implements‬‭ NavigableSet‬‭.‬
‭○‬ ‭Backed by a‬‭Red-Black Tree‬‭.‬
‭○‬ ‭Maintains elements in‬‭sorted order‬‭.‬
‭○‬ ‭Operations like add, remove, and contains take‬‭O(log‬‭n)‬‭time.‬

‭Example Code for HashSet‬


‭Java code‬
import java.util.HashSet;‬

public class HashSetExample {‬



public static void main(String[] args) {‬

‭// Create a HashSet‬
‭HashSet<String> cities = new HashSet<>();‬

‭// Add elements‬


c‭ities.add("Hyderabad");‬
‭cities.add("Kolkata");‬
‭cities.add("Mumbai");‬
‭cities.add("Hyderabad"); // Duplicate, won't be added‬

/‭/ Display elements‬


‭System.out.println("Cities: " + cities);‬

/‭/ Check for an element‬


‭System.out.println("Contains 'Kolkata': " +‬
cities.contains("Kolkata"));‬

/‭/ Remove an element‬


‭cities.remove("Mumbai");‬

/‭/ Iterate over elements‬


‭for (String city : cities) {‬
‭System.out.println(city);‬
‭}‬
}‬

}‬

‭Example Code for TreeSet‬


‭Java code‬
import java.util.TreeSet;‬

public class TreeSetExample {‬



public static void main(String[] args) {‬

‭// Create a TreeSet‬
‭TreeSet<Integer> numbers = new TreeSet<>();‬

/‭/ Add elements‬


‭numbers.add(10);‬
‭numbers.add(5);‬
‭numbers.add(20);‬
‭numbers.add(15);‬

/‭/ Display elements (sorted order)‬


‭System.out.println("Numbers: " + numbers);‬

‭// Access first and last elements‬


S‭ystem.out.println("First: " + numbers.first());‬
‭System.out.println("Last: " + numbers.last());‬

/‭/ Remove an element‬


‭numbers.remove(10);‬

/‭/ Iterate over elements‬


‭for (Integer number : numbers) {‬
‭System.out.println(number);‬
‭}‬
}‬

}‬

‭Internal Working of HashSet‬

‭●‬ ‭Backed by a‬‭


HashMap‬‭.‬
‭●‬ ‭When you add an element to a‬‭
HashSet‬
‭, it is stored‬‭as a key in the underlying‬
HashMap‬‭with a constant dummy value (‬‭
‭ PRESENT‬‭).‬

‭Internal Working of TreeSet‬

‭‬ U
● ‭ ses a self-balancing‬‭Red-Black Tree‬‭.‬
‭●‬ ‭Maintains a‬‭binary search tree‬‭where the left subtree‬‭has smaller values, and the‬
‭right subtree has larger values.‬
‭●‬ ‭Ensures logarithmic time complexity for key operations.‬

‭Map Interface‬

‭A‬‭
Map‬‭represents a collection of‬‭key-value pairs‬‭where:‬

‭‬ E
● ‭ ach key is unique.‬
‭●‬ ‭A key maps to exactly one value (no duplicate keys allowed, but duplicate values are‬
‭allowed).‬

‭Key Methods in‬‭


Map‬
‭Method‬ ‭Description‬

put(K key, V value)‬


‭ ‭Adds or updates a key-value pair.‬

get(Object key)‬
‭ ‭Retrieves the value associated with the key.‬

remove(Object key)‬
‭ ‭Removes the mapping for a key.‬
containsKey(Object key)‬ ‭Checks if a key exists.‬

‭ontainsValue(Object‬
c ‭Checks if a value exists.‬
value)‬

keySet()‬
‭ ‭Returns a‬‭
Set‬‭view of all keys.‬

values()‬
‭ ‭Returns a‬‭
Collection‬‭view of all values.‬

entrySet()‬
‭ ‭Returns a‬‭
Set‬‭view of all key-value pairs‬
‭(‬‭
Map.Entry‬‭).‬

‭Implementations of Map‬

‭1. HashMap‬

‭‬ U
● ‭ ses a‬‭hash table‬‭for storing key-value pairs.‬
‭●‬ ‭Order of keys is not guaranteed‬‭.‬
‭●‬ ‭Allows one null key and multiple null values.‬

‭Example Code‬
‭Java code‬
import java.util.HashMap;‬

public class HashMapExample {‬



public static void main(String[] args) {‬

‭// Create a HashMap‬
‭HashMap<String, Integer> scores = new HashMap<>();‬

/‭/ Add key-value pairs‬


‭scores.put("Avinash", 85);‬
‭scores.put("Kumar", 92);‬
‭scores.put("Jha", 78);‬
‭scores.put(null, 50); // One null key allowed‬

/‭/ Access value‬


‭System.out.println("Score of Kumar: " +‬
scores.get("Kumar"));‬

/‭/ Remove a key-value pair‬


‭scores.remove("Jha");‬

‭// Iterate over entries‬


f‭or (HashMap.Entry<String, Integer> entry :‬
scores.entrySet()) {‬

‭System.out.println(entry.getKey() + ": " +‬
entry.getValue());‬

‭}‬

/‭/ Check for a key or value‬


‭System.out.println("Contains key 'Avinash': " +‬
scores.containsKey("Avinash"));‬

}‬

}‬

‭Internal Working of HashMap‬

‭1.‬ ‭Bucket Structure‬‭:‬


‭○‬ ‭A‬‭ HashMap‬‭uses an array of buckets. Each bucket stores‬‭entries as a linked‬
‭list or tree (from JDK 1.8 onwards).‬
‭○‬ ‭The index for a key is determined by its hash code (‬‭ hashCode()‬‭).‬
‭2.‬ ‭Load Factor and Rehashing‬‭:‬
‭○‬ ‭When the number of entries exceeds‬‭ capacity * load‬‭
factor‬ ‭, the map‬
‭resizes (default load factor is‬‭0.75‬‭).‬
‭○‬ ‭Resizing involves creating a larger array and rehashing all keys.‬
‭3.‬ ‭Complexity‬‭:‬
‭○‬ ‭Average-case time for‬‭ get‬‭and‬‭ put‬ ‭:‬‭O(1)‬‭.‬
‭○‬ ‭Worst-case (if many hash collisions):‬‭O(n)‬‭.‬

‭2. LinkedHashMap‬

‭●‬ ‭Extends‬‭
HashMap‬‭and maintains the‬‭insertion order‬‭of keys.‬
‭ lightly slower than‬‭
‭●‬ S HashMap‬‭due to the additional‬‭overhead of maintaining the‬
‭order.‬

‭Example Code‬
‭Java code‬
import java.util.LinkedHashMap;‬

public class LinkedHashMapExample {‬



public static void main(String[] args) {‬

‭// Create a LinkedHashMap‬
‭LinkedHashMap<String, String> capitals = new‬
LinkedHashMap<>();‬

/‭/ Add key-value pairs‬
‭capitals.put("India", "New Delhi");‬
‭capitals.put("USA", "Washington DC");‬
‭capitals.put("Japan", "Tokyo");‬

/‭/ Display entries in insertion order‬


‭for (LinkedHashMap.Entry<String, String> entry :‬
capitals.entrySet()) {‬

‭System.out.println(entry.getKey() + ": " +‬
entry.getValue());‬

‭}‬
}‬

}‬

‭3. TreeMap‬

‭ ‬ I‭mplements‬‭
● NavigableMap‬‭, backed by a‬‭Red-Black Tree‬‭.‬
‭●‬ ‭Maintains keys in‬‭sorted order‬‭(natural order or as‬‭per a custom comparator).‬
‭●‬ ‭Does‬‭not allow null keys‬‭but permits null values.‬

‭Example Code‬
‭Java code‬
import java.util.TreeMap;‬

public class TreeMapExample {‬



public static void main(String[] args) {‬

‭// Create a TreeMap‬
‭TreeMap<String, Integer> marks = new TreeMap<>();‬

/‭/ Add key-value pairs‬


‭marks.put("Physics", 88);‬
‭marks.put("Math", 95);‬
‭marks.put("Chemistry", 72);‬

/‭/ Display entries in sorted order of keys‬


‭for (TreeMap.Entry<String, Integer> entry :‬
marks.entrySet()) {‬

‭System.out.println(entry.getKey() + ": " +‬
entry.getValue());‬

‭}‬
/‭/ Access first and last keys‬
‭System.out.println("First Subject: " + marks.firstKey());‬
‭System.out.println("Last Subject: " + marks.lastKey());‬
}‬

}‬

‭Internal Working of TreeMap‬

‭1.‬ ‭Red-Black Tree‬‭:‬


‭○‬ ‭Self-balancing binary search tree.‬
‭○‬ ‭Ensures‬‭O(log n)‬‭time complexity for operations.‬
‭2.‬ ‭Key Ordering‬‭:‬
‭○‬ ‭By default, uses the‬‭natural order‬‭of keys (requires‬‭
Comparable‬
‭implementation).‬
‭○‬ ‭A custom comparator can be provided during TreeMap construction.‬

‭Difference Between HashMap, LinkedHashMap, and TreeMap‬


‭Feature‬ ‭HashMap‬ ‭LinkedHashMap‬ ‭TreeMap‬

‭Ordering‬ ‭No order‬ ‭ aintains insertion‬


M ‭Sorted by key‬
‭order‬

‭Null Keys‬ ‭Allows one null key‬ ‭Allows one null key‬ ‭Does not allow null keys‬

‭ erformanc‬ O
P ‭ (1) for most‬ ‭ (1) for most‬
O ‭ (log n) for all‬
O
‭e‬ ‭operations‬ ‭operations‬ ‭operations‬

‭Use Case‬ ‭ ast lookup and‬


F ‭ redictable iteration‬
P ‭ orted data or range‬
S
‭insertion‬ ‭order‬ ‭queries‬

‭NavigableMap and Its Features‬

‭ ‬‭
A NavigableMap‬‭is a subinterface of‬‭
SortedMap‬‭and provides methods to navigate‬
‭through the keys in a map.‬

‭Key Methods‬
‭Method‬ ‭Description‬

firstEntry()‬
‭ ‭Retrieves the first key-value pair.‬

lastEntry()‬
‭ ‭Retrieves the last key-value pair.‬

lowerKey(K key)‬
‭ ‭Returns the greatest key strictly less than‬‭
key‬‭.‬
higherKey(K key)‬
‭ ‭Returns the smallest key strictly greater than‬
‭key‬‭.‬

‭ubMap(K fromKey, K‬
s ‭Returns a view of the map within a key range.‬
toKey)‬

‭Example‬
‭Java code‬
import java.util.TreeMap;‬

public class NavigableMapExample {‬



public static void main(String[] args) {‬

‭TreeMap<Integer, String> grades = new TreeMap<>();‬

g‭rades.put(60, "Pass");‬
‭grades.put(75, "Good");‬
‭grades.put(90, "Excellent");‬

S‭ystem.out.println("Lower Key (80): " +‬


grades.lowerKey(80));‬

‭System.out.println("Higher Key (80): " +‬
grades.higherKey(80));‬

‭System.out.println("SubMap (60 to 90): " + grades.subMap(60,‬
90));‬

}‬

}‬

‭Synchronization in Collections‬

‭ y default, most classes in the Java Collection Framework are‬‭not thread-safe‬‭. This means‬
B
‭multiple threads modifying or accessing a collection concurrently can lead to unexpected‬
‭behavior.‬

‭Why Synchronization Is Needed‬

‭When multiple threads interact with a collection:‬

‭ .‬ D
1 ‭ ata Corruption‬‭: Simultaneous updates to the collection can corrupt its state.‬
‭2.‬ ‭Concurrent Modification Exception‬‭: If one thread modifies‬‭a collection while‬
‭another is iterating over it, this exception is thrown.‬
‭Thread-Safe Collections‬

‭Java provides multiple ways to make collections thread-safe.‬

‭1. Synchronized Wrappers (Legacy Approach)‬

‭ he‬‭
T Collections‬‭utility class provides static methods‬‭to create synchronized (thread-safe)‬
‭versions of collections.‬

‭Example Code‬
‭Java code‬
import java.util.*;‬

public class SynchronizedCollectionExample {‬



public static void main(String[] args) {‬

‭// Create a non-synchronized list‬
‭List<String> names = new ArrayList<>();‬
‭names.add("Avinash");‬
‭names.add("Kumar");‬

/‭/ Create a synchronized version of the list‬


‭List<String> synchronizedNames =‬
Collections.synchronizedList(names);‬

/‭/ Synchronized block for iteration‬


‭synchronized (synchronizedNames) {‬
‭for (String name : synchronizedNames) {‬
‭System.out.println(name);‬
‭}‬
‭}‬
}‬

}‬

‭Methods to Create Synchronized Collections‬

‭Method‬ ‭Description‬

‭ollections.synchronizedList(L‬ R
C ‭ eturns a synchronized‬
ist)‬
‭ List‬‭.‬

‭ollections.synchronizedSet(Se‬ ‭Returns a synchronized‬‭


C Set‬‭.‬
t)‬

‭ollections.synchronizedMap(Ma‬ ‭Returns a synchronized‬‭
C Map‬‭.‬
p)‬

‭Limitations‬

‭●‬ P ‭ erformance Overhead‬‭: Synchronization affects performance, as it locks the entire‬


‭collection.‬
‭●‬ ‭Iteration‬‭: Must use explicit synchronization when‬‭iterating over synchronized‬
‭collections.‬

‭2. Concurrent Collections (Modern Approach)‬

I‭ntroduced in Java 5 as part of the‬‭


java.util.concurrent‬‭package, these classes are‬
‭designed for high-performance concurrent access.‬

‭Key Classes‬

‭Class‬ ‭Description‬

ConcurrentHashMap‬
‭ ‭Thread-safe, highly efficient implementation of‬‭
Map‬‭.‬

‭opyOnWriteArrayLis‬ ‭Thread-safe implementation of‬‭


C List‬‭.‬
t‬

CopyOnWriteArraySet‬ ‭Thread-safe implementation of‬‭


‭ Set‬‭.‬

‭oncurrentLinkedQue‬ ‭Thread-safe, non-blocking queue.‬


C
ue‬

BlockingQueue‬
‭ ‭ ueue with blocking methods (‬‭
Q LinkedBlockingQueue‬
‭,‬
‭(Interface)‬ ‭etc.).‬

‭ConcurrentHashMap‬

‭1.‬ ‭How It Works‬‭:‬


‭○‬ ‭Divides the map into segments (buckets) to reduce contention.‬
‭○‬ ‭Only locks a specific segment during updates instead of the whole map.‬
‭○‬ ‭Operations like‬‭
get()‬‭are non-blocking.‬
‭2.‬ ‭Key Methods‬‭:‬
‭○‬ ‭putIfAbsent(K key, V value)‬‭: Adds a value only if the key is not‬
‭already mapped.‬
‭○‬ ‭compute(K key, BiFunction)‬ ‭: Updates the value atomically.‬
‭‬ ‭
○ forEach()‬ ‭: Parallel traversal.‬
‭3.‬ ‭Example Code‬‭:‬
‭Java code‬
import java.util.concurrent.ConcurrentHashMap;‬

public class ConcurrentHashMapExample {‬



public static void main(String[] args) {‬

‭// Create a ConcurrentHashMap‬
‭ConcurrentHashMap<String, Integer> scores = new‬
ConcurrentHashMap<>();‬

/‭/ Add elements‬


‭scores.put("Java", 90);‬
‭scores.put("Python", 85);‬

/‭/ Perform atomic operations‬


‭scores.putIfAbsent("C++", 80); // Add only if absent‬
‭scores.compute("Java", (key, val) -> val + 10); // Increment‬
score of Java‬

/‭/ Iterate‬
‭scores.forEach((key, value) -> {‬
‭System.out.println(key + ": " + value);‬
‭});‬
}‬

}‬

‭CopyOnWriteArrayList‬

‭1.‬ ‭How It Works‬‭:‬


‭○‬ ‭Every modification (add/remove) creates a new copy of the underlying array.‬
‭○‬ ‭Ideal for scenarios with‬‭frequent reads‬‭and‬‭infrequent‬‭writes‬‭.‬
‭2.‬ ‭Example Code‬‭:‬

‭Java code‬
import java.util.concurrent.CopyOnWriteArrayList;‬

public class CopyOnWriteArrayListExample {‬



public static void main(String[] args) {‬

‭// Create a CopyOnWriteArrayList‬
‭CopyOnWriteArrayList<String> items = new‬
CopyOnWriteArrayList<>();‬

/‭/ Add elements‬
‭items.add("Java");‬
‭items.add("Python");‬

/‭/ Modify list while iterating‬


‭for (String item : items) {‬
‭System.out.println(item);‬
‭items.add("C++"); // No ConcurrentModificationException‬
‭}‬

/‭/ Display updated list‬


‭System.out.println("Final List: " + items);‬
}‬

}‬

‭BlockingQueue‬

‭1.‬ ‭How It Works‬‭:‬


‭○‬ ‭Designed for producer-consumer scenarios.‬
‭○‬ ‭Blocks a thread if the queue is full or empty.‬
‭2.‬ ‭Common Implementations‬‭:‬
‭○‬ ‭
ArrayBlockingQueue‬ ‭: Fixed-size queue.‬
‭○‬L‭inkedBlockingQueue‬‭: Linked list-based queue.‬
‭‬ ‭
○ PriorityBlockingQueue‬ ‭: Priority-based queue.‬
‭3.‬ ‭Example Code‬‭:‬

‭Java code‬
import java.util.concurrent.ArrayBlockingQueue;‬

public class BlockingQueueExample {‬



public static void main(String[] args) throws‬

InterruptedException {‬

‭// Create a blocking queue with capacity 2‬
‭ArrayBlockingQueue<String> queue = new‬
ArrayBlockingQueue<>(2);‬

/‭/ Producer thread‬


‭new Thread(() -> {‬
‭try {‬
‭queue.put("Task 1");‬
‭System.out.println("Added Task 1");‬
q‭ueue.put("Task 2");‬
‭System.out.println("Added Task 2");‬
‭} catch (InterruptedException e) {‬
‭e.printStackTrace();‬
‭}‬
‭}).start();‬

/‭/ Consumer thread‬


‭new Thread(() -> {‬
‭try {‬
‭Thread.sleep(1000); // Simulate processing delay‬
‭System.out.println("Removed: " + queue.take());‬
‭System.out.println("Removed: " + queue.take());‬
‭} catch (InterruptedException e) {‬
‭e.printStackTrace();‬
‭}‬
‭}).start();‬
}‬

}‬

‭When to Use Which Approach‬


‭Scenario‬ ‭Best Choice‬

‭Frequent updates to a collection‬ ConcurrentHashMap‬



‭Frequent reads, infrequent writes‬ CopyOnWriteArrayList/Set‬

‭Producer-consumer pattern‬ BlockingQueue‬

‭implementations‬

‭ mall applications with single-threaded‬


S ‭Synchronized wrappers‬
‭use‬

‭Custom Comparators in Java‬

‭ ‬‭
A Comparator‬‭is an interface used to define custom‬‭sorting logic for objects. It is typically‬
‭used when:‬

‭●‬ ‭You need a sorting order different from the natural order defined by‬‭
Comparable‬
‭.‬
‭●‬ ‭The objects being compared do not implement‬‭
Comparable‬
‭.‬
‭Key Points About Comparator‬
‭ unctional Interface‬‭: Introduced in Java 8,‬‭
F Comparator‬‭is a functional interface with a‬
‭single abstract method:‬
‭Java code‬
int compare(T o1, T o2);‬

‭1.‬
‭‬ R
○ ‭ eturns a negative value if‬‭
o1‬‭is less than‬‭
o2‬
‭.‬
‭○‬ ‭Returns zero if they are equal.‬
‭○‬ ‭Returns a positive value if‬‭
o1‬‭is greater than‬‭
o2‬ ‭.‬
‭2.‬ ‭Default Methods‬‭:‬‭
Comparator‬‭has several default methods‬‭introduced in Java 8:‬
‭○‬r‭eversed()‬
‭: Reverses the sorting order.‬
‭‬ ‭
○ thenComparing()‬‭: Chains multiple comparators for complex‬‭sorting.‬

‭Implementing Comparator‬

‭Example 1: Sorting Based on a Custom Field‬

‭Suppose we have a‬‭


Person‬‭class with fields‬‭
name‬‭and‬‭
age‬‭:‬

‭Java code‬
class Person {‬

String name;‬

int age;‬

‭/ Constructor‬
/
public Person(String name, int age) {‬

‭this.name = name;‬
‭this.age = age;‬
}‬

‭Override‬
@
public String toString() {‬

‭return name + " (" + age + ")";‬
}‬

}‬

‭We can create a custom comparator to sort people by age:‬

‭Comparator Implementation‬
‭Java code‬
import java.util.*;‬

public class CustomComparatorExample {‬



public static void main(String[] args) {‬

‭// List of persons‬
‭List<Person> people = Arrays.asList(‬
‭new Person("Avinash", 30),‬
‭new Person("Kumar", 25),‬
‭new Person("Jha", 35)‬
‭);‬

/‭/ Sort by age‬


‭Collections.sort(people, new Comparator<Person>() {‬
‭@Override‬
‭public int compare(Person p1, Person p2) {‬
‭return Integer.compare(p1.age, p2.age); // Compare‬
ages‬

}‭‬
‭});‬

/‭/ Display sorted list‬


‭System.out.println("Sorted by age: " + people);‬
}‬

}‬

‭Example 2: Using a Lambda Expression‬

‭In Java 8+, we can simplify the above code using a lambda expression:‬

‭Java code‬
‭ollections.sort(people, (p1, p2) -> Integer.compare(p1.age,‬
C
p2.age));‬

‭Or, using the‬‭


List.sort()‬‭method:‬

‭Java code‬
people.sort((p1, p2) -> Integer.compare(p1.age, p2.age));‬

‭Example 3: Sorting with‬‭
thenComparing‬

‭If we want to sort people by age and, for people with the same age, by name alphabetically:‬

‭Java code‬
import java.util.*;‬

public class MultiComparatorExample {‬



public static void main(String[] args) {‬

‭List<Person> people = Arrays.asList(‬
‭new Person("Avinash", 30),‬
‭new Person("Kumar", 25),‬
‭new Person("Jha", 30)‬
‭);‬

/‭/ Multi-level sorting‬


‭people.sort(‬
‭Comparator.comparingInt((Person p) -> p.age)‬
‭.thenComparing(p -> p.name)‬
‭);‬

‭System.out.println("Sorted by age, then name: " + people);‬


}‬

}‬

‭Example 4: Reverse Sorting‬

‭To sort the list in descending order of age:‬

‭Java code‬
‭eople.sort(Comparator.comparingInt((Person p) ->‬
p
p.age).reversed());‬

‭Advanced Customization with‬‭


TreeMap‬‭or‬‭
TreeSet‬
‭ hen using‬‭
W TreeMap‬‭or‬‭TreeSet‬
‭, you can pass a custom‬‭comparator in their constructors‬
‭for automatic sorting.‬

‭Example: TreeMap with Custom Comparator‬


‭Java code‬
import java.util.*;‬

public class TreeMapComparatorExample {‬

public static void main(String[] args) {‬

‭// TreeMap with custom comparator (sort by descending key)‬
‭TreeMap<Integer, String> map = new‬
TreeMap<>(Comparator.reverseOrder());‬

m‭ap.put(1, "One");‬
‭map.put(3, "Three");‬
‭map.put(2, "Two");‬

‭System.out.println("Descending Order: " + map);‬


}‬

}‬

‭Advanced Topics: Iterators‬

‭ n‬‭Iterator‬‭is an object used to traverse collections. It is part of the‬‭


A java.util‬‭package‬
‭and is preferred for iterating over collections when:‬

‭‬ W
● ‭ e need to remove elements during iteration.‬
‭●‬ ‭We want to traverse elements without exposing the underlying structure.‬

‭Types of Iterators‬

‭1.‬ ‭Iterator (Universal Iterator)‬‭:‬


‭○‬ ‭Available for all‬‭ Collection‬‭implementations.‬
‭○‬ ‭Allows element removal during iteration.‬
‭2.‬ ‭ListIterator‬‭(Only for‬‭ List‬‭):‬
‭○‬ ‭Bi-directional iteration.‬
‭○‬ ‭Allows adding, modifying, and removing elements during traversal.‬
‭3.‬ ‭Spliterator‬‭(Introduced in Java 8):‬
‭○‬ ‭Designed for parallel traversal of collections.‬

‭Iterator Example‬
‭Java code‬
import java.util.*;‬

public class IteratorExample {‬



public static void main(String[] args) {‬

‭List<String> names = new‬
ArrayList<>(Arrays.asList("Avinash", "Kumar", "Jha"));‬

/‭/ Create an iterator‬


‭Iterator<String> iterator = names.iterator();‬

/‭/ Traverse the list‬


‭while (iterator.hasNext()) {‬
‭String name = iterator.next();‬
‭System.out.println(name);‬

/‭/ Remove an element during iteration‬


‭if (name.equals("Kumar")) {‬
‭iterator.remove();‬
‭}‬
‭}‬

‭System.out.println("After removal: " + names);‬


}‬

}‬

‭ListIterator Example‬
‭Java code‬
import java.util.*;‬

public class ListIteratorExample {‬



public static void main(String[] args) {‬

‭List<String> names = new ArrayList<>(Arrays.asList("Java",‬
"Python", "C++"));‬

/‭/ Create a ListIterator‬


‭ListIterator<String> listIterator = names.listIterator();‬

/‭/ Forward traversal‬


‭while (listIterator.hasNext()) {‬
‭System.out.println(listIterator.next());‬
‭}‬

‭// Backward traversal‬


‭while (listIterator.hasPrevious()) {‬
‭System.out.println(listIterator.previous());‬
‭}‬
}‬

}‬

‭Spliterator Example‬

‭The‬‭
Spliterator‬‭splits the collection into parts for parallel processing. Example:‬

‭Java code‬
import java.util.*;‬

public class SpliteratorExample {‬



public static void main(String[] args) {‬

‭List<String> languages = Arrays.asList("Java", "Python",‬
"C++", "Ruby");‬

/‭/ Create a Spliterator‬


‭Spliterator<String> spliterator = languages.spliterator();‬

/‭/ Try splitting the list‬


‭Spliterator<String> secondHalf = spliterator.trySplit();‬

/‭/ Traverse the first half‬


‭spliterator.forEachRemaining(System.out::println);‬

/‭/ Traverse the second half‬


‭System.out.println("Second Half:");‬
‭secondHalf.forEachRemaining(System.out::println);‬
}‬

}‬

‭What Are Streams?‬

‭A‬‭stream‬‭is a sequence of elements that supports:‬

‭ .‬ F
1 ‭ unctional-style operations‬‭(like‬‭
map‬
‭,‬‭
filter‬
‭, and‬‭
reduce‬‭).‬
‭2.‬ ‭Lazy evaluation‬‭, meaning intermediate operations are not executed until a terminal‬
‭operation is invoked.‬
‭3.‬ ‭Pipeline processing‬‭, where data flows through a series‬‭of operations.‬

‭Streams do not store data; they process data from collections or other sources.‬

‭Why Use Streams?‬

‭‬ S
● ‭ implifies complex collection operations (like filtering or mapping).‬
‭●‬ ‭Enables parallel processing with minimal effort.‬
‭●‬ ‭Enhances readability and maintainability.‬

‭Stream Operations‬

‭Stream operations are divided into two categories:‬

‭1.‬ ‭Intermediate Operations‬‭: Return a new stream (lazy‬‭evaluation). Examples:‬


filter()‬
‭ ‭,‬‭
map()‬‭,‬‭sorted()‬ ‭.‬
‭2.‬ ‭Terminal Operations‬‭: Produce a result or side-effect‬‭(eager evaluation). Examples:‬
collect()‬
‭ ‭,‬‭
forEach()‬ ‭,‬‭
reduce()‬
‭.‬

‭1. Creating Streams‬

‭Streams can be created from various data sources, such as:‬

‭ ollections‬‭:‬
C
‭Java code‬
‭ist<String> names = List.of("Java", "Python", "C++");‬
L
Stream<String> stream = names.stream();‬

‭ rrays‬‭:‬
A
‭Java code‬
‭tring[] languages = {"Java", "Python", "C++"};‬
S
Stream<String> stream = Arrays.stream(languages);‬

‭ tatic Methods‬‭:‬
S
‭Java code‬
Stream<Integer> numbers = Stream.of(1, 2, 3, 4, 5);‬

‭2. Intermediate Operations‬

‭filter()‬

‭Filters elements based on a predicate.‬

‭Java code‬
‭ist<String> names = List.of("Avinash", "Kumar", "Jha", "Java");‬
L
names.stream()‬

.filter(name -> name.startsWith("J"))‬

.forEach(System.out::println); // Output: Jha, Java‬

‭map()‬

‭Transforms each element using a function.‬

‭Java code‬
‭ist<String> names = List.of("Avinash", "Kumar");‬
L
names.stream()‬

.map(String::toUpperCase)‬

.forEach(System.out::println); // Output: AVINASH, KUMAR‬

‭sorted()‬

‭Sorts elements in natural or custom order.‬

‭Java code‬
‭ist<Integer> numbers = List.of(5, 3, 8, 1);‬
L
numbers.stream()‬

.sorted()‬

.forEach(System.out::println); // Output: 1, 3, 5, 8‬

‭distinct()‬

‭Removes duplicate elements.‬

‭Java code‬
‭ist<Integer> numbers = List.of(1, 2, 2, 3, 4, 4);‬
L
numbers.stream()‬

.distinct()‬

.forEach(System.out::println); // Output: 1, 2, 3, 4‬

‭limit() and skip()‬


‭●‬ ‭limit(n)‬‭: Limits the stream to the first‬‭
n‬‭elements.‬
‭●‬ ‭skip(n)‬‭: Skips the first‬‭
n‬‭elements.‬

‭Java code‬
‭tream<Integer> stream = Stream.of(1, 2, 3, 4, 5);‬
S
stream.limit(3).forEach(System.out::println); // Output: 1, 2, 3‬

stream.skip(2).forEach(System.out::println); // Output: 3, 4, 5‬

‭3. Terminal Operations‬

‭forEach()‬

‭Performs an action for each element.‬

‭Java code‬
‭ist<String> names = List.of("Java", "Python");‬
L
names.stream().forEach(System.out::println);‬

‭collect()‬

‭Converts the stream into a collection or another structure.‬

‭Java code‬
‭ist<String> names = List.of("Java", "Python");‬
L
List<String> upperCaseNames = names.stream()‬

.map(String::toUpperCase)‬

.collect(Collectors.toList());‬

System.out.println(upperCaseNames); // Output: [JAVA, PYTHON]‬

‭reduce()‬

‭Aggregates elements into a single result.‬

‭Java code‬
‭ist<Integer> numbers = List.of(1, 2, 3, 4);‬
L
int sum = numbers.stream()‬

‭.reduce(0, Integer::sum); // Initial value is 0‬
System.out.println(sum); // Output: 10‬

‭count()‬

‭Counts the number of elements in the stream.‬


‭Java code‬
‭ong count = List.of("Java", "Python", "C++").stream().count();‬
l
System.out.println(count); // Output: 3‬

‭anyMatch(), allMatch(), noneMatch()‬

‭●‬ ‭nyMatch()‬
a ‭: Returns‬‭ true‬‭if any element matches the‬‭predicate.‬
‭‬ ‭
● allMatch()‬‭: Returns‬‭true‬‭if all elements match the‬‭predicate.‬
‭●‬ ‭
noneMatch()‬ ‭: Returns‬‭
true‬‭if no elements match the‬‭predicate.‬

‭Example:‬

‭Java code‬
‭ist<Integer> numbers = List.of(2, 4, 6, 8);‬
L
boolean allEven = numbers.stream().allMatch(n -> n % 2 == 0);‬

System.out.println(allEven); // Output: true‬

‭4. Parallel Streams‬

‭For large datasets, streams can be processed in parallel to improve performance:‬

‭Java code‬
‭ist<Integer> numbers = List.of(1, 2, 3, 4, 5);‬
L
numbers.parallelStream()‬

.map(n -> n * n)‬

.forEach(System.out::println); // Order is not guaranteed‬

‭Practical Examples‬

‭Example 1: Filtering and Collecting‬


‭Java code‬
‭ist<String> names = List.of("Java", "Python", "C++", "JavaScript");‬
L
List<String> longNames = names.stream()‬

.filter(name -> name.length() > 4)‬

.collect(Collectors.toList());‬

System.out.println(longNames); // Output: [Python, JavaScript]‬

‭Example 2: Grouping Data‬

‭Using‬‭
Collectors.groupingBy()‬‭:‬
‭Java code‬
‭ist<String> items = List.of("Apple", "Banana", "Cherry",‬
L
"Avocado");‬

Map<Character, List<String>> groupedByFirstLetter = items.stream()‬

.collect(Collectors.groupingBy(item -> item.charAt(0)));‬

System.out.println(groupedByFirstLetter);‬

// Output: {A=[Apple, Avocado], B=[Banana], C=[Cherry]}‬

‭Example 3: Finding Max/Min‬


‭Java code‬
‭ist<Integer> numbers = List.of(10, 20, 30, 40);‬
L
int max = numbers.stream()‬

‭.max(Integer::compareTo)‬
‭.orElseThrow(); // Output: 40‬

You might also like