0% found this document useful (0 votes)
3 views62 pages

Java

The document provides an overview of Java Core Basics, covering essential topics such as Java fundamentals, control flow statements, methods, and arrays. It explains the Java architecture (JVM, JRE, JDK), the compilation and execution process, data types, control flow statements, and object-oriented programming principles. Key concepts include variable declaration, method overloading, recursion, and array manipulation techniques.

Uploaded by

mandarp1110
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)
3 views62 pages

Java

The document provides an overview of Java Core Basics, covering essential topics such as Java fundamentals, control flow statements, methods, and arrays. It explains the Java architecture (JVM, JRE, JDK), the compilation and execution process, data types, control flow statements, and object-oriented programming principles. Key concepts include variable declaration, method overloading, recursion, and array manipulation techniques.

Uploaded by

mandarp1110
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

01_Java_Core_Basics

Module 1: Java Core Basics

This module covers Java Fundamentals, Control Flow Statements, Methods, and Arrays.

1. Java Fundamentals

Java Architecture (JVM, JRE, JDK)

Java uses a write-once, run-anywhere (WORA) model, powered by three core components:

JVM (Java Virtual Machine): An abstract machine that executes compiled Java bytecode. It is
platform-dependent (different JVMs exist for Windows, macOS, Linux) but enables platform
independence for the application bytecode.

JRE (Java Runtime Environment): Package that bundles the JVM, core class libraries, and
supporting files. It is sufficient for running Java applications but does not contain development tools
like compilers.

JDK (Java Development Kit): A full-featured software development kit containing the JRE,
compiler ( javac ), archiver ( jar ), debugger ( jdb ), and other development utilities.

+--------------------------------------------------------+
| JDK (Development) |
| +----------------------------------------------+ |
| | JRE (Execution) | |
| | +------------------+ +-----------------+ | |
| | | JVM (Engine) | | Library Classes | | |
| | +------------------+ +-----------------+ | |
| +----------------------------------------------+ |
| Development Tools (javac, jar, javadoc, etc.) |
+--------------------------------------------------------+

Compilation and Execution Process

1. Source Code: Programmers write code in .java files (e.g., [Link] ).

2. Compilation: The Java compiler ( javac ) compiles source code into intermediate bytecode saved
in .class files (e.g., [Link] ).

3. Execution: The JVM's ClassLoader loads the .class files, the Bytecode Verifier checks for safety,
and the Execution Engine (Interpreter + Just-In-Time [JIT] Compiler) translates bytecode to machine
code.
[[Link]] --(javac [Link])--> [[Link] (Bytecode)] --(java App)--> [JVM
ClassLoader] --> [Execution Engine] --> [Machine Code]

Structure of a Java Program & The Main Method

Every Java program must have at least one class definition. The entry point of execution is the main
method.

public class HelloWorld {


public static void main(String[] args) {
[Link]("Hello, World!");
}
}

Main Method Breakdown

public : Access modifier making the method accessible from outside the class (specifically by the
JVM).
static : Allows the JVM to call the method without instantiating the class.

void : Return type indicating the method does not return any value.

main : The name of the method recognized by the JVM as the entry point.

String[] args : Array of String arguments passed via command-line execution.

Variables

A variable is a container that holds data during execution. In Java, variables must be declared with a
data type.

Local Variables: Declared inside a method, constructor, or block. Must be initialized before use;
they do not have default values.

Instance (Object) Variables: Declared inside a class but outside methods. Initialized automatically
to defaults ( 0 , null , false ).

Static (Class) Variables: Declared with the static keyword inside a class. Shared across all
instances of that class.

Data Types

Java is a statically-typed language. Types are divided into two main categories:

Data Types
/ \
Primitive Types Non-Primitive Types (References)
/ \ |
Numeric Non-Numeric +-- String, Arrays, Classes,
/ \ | Interfaces, Enums
Integer Floating-Point char, boolean
(byte, (float, double)
short,
int, long)

Primitive Data Types

Primitives are stored directly on the stack and represent single values:

Size Default
Type Range
(Bytes) Value

byte 1 0 -128 to 127

short 2 0 -32,768 to 32,767

int 4 0 −231 to 231 − 1

long 8 0L
−263 to 263 − 1 (suffix L required:
10000000000L )

float 4 0.0f ≈ ±3.4 × 1038 (suffix f required: 3.14f )

double 8 0.0d ≈ ±1.7 × 10308 (default for decimals)


char 2 \u0000 Single 16-bit Unicode character (e.g., 'A' )

boolean 1 (approx) false true or false

Non-Primitive (Reference) Types

Refer to objects or arrays. They store the memory address of the actual object (allocated on the heap).
Examples include classes, arrays, interfaces, and strings.

Type Casting

Converts a value from one data type to another.

1. Implicit (Widening) Casting

Happens automatically when converting a smaller type size to a larger type size. No data loss occurs.

byte → short → char → int → long → float → double

int myInt = 9;
double myDouble = myInt; // Implicit casting: 9.0

2. Explicit (Narrowing) Casting

Must be done manually by placing the type in parentheses in front of the value. Can result in data loss
or truncation.

double → float → long → int → char → short → byte


double myDouble = 9.78d;
int myInt = (int) myDouble; // Explicit casting: 9 (decimal values truncated)

Operators

Category Operators Description / Example

Arithmetic +, -, *, /, % Standard math; % yields remainder ( 7 % 3 = 1 ).

== , != , > , < , >= ,


Relational Returns boolean based on comparison.
<=

Logical && , || , ! Short-circuit logical AND, OR, and logical NOT.

& , | , ^ , ~ , << ,
Bitwise Bitwise operations and binary bit-shifting.
>> , >>>

= , += , -= , *= ,
Assignment Assigns and modifies variables.
/= , %=

Ternary ? : Short-hand if-else: variable = (condition) ?


value_if_true : value_if_false

Input/Output

Java provides multiple ways to capture user inputs:

1. Scanner (Utility Package)

Easy to parse primitives and lines using regex. Slow because of parser overhead. Not thread-safe.

import [Link];
Scanner sc = new Scanner([Link]);
int age = [Link]();
String name = [Link](); // or nextLine()

2. BufferedReader (I/O Package)

Reads character streams with buffering. Fast read speeds (recommended for competitive
programming/DSA). Needs explicit exception handling ( IOException ).

import [Link];
import [Link];
import [Link];

BufferedReader reader = new BufferedReader(new InputStreamReader([Link]));


String line = [Link](); // Reads entire line as String
int num = [Link]([Link]()); // Manual parsing required

Comments, Keywords & Identifiers

Comments: Documentation ignored by compiler.


// - Single-line comment.

/* ... */ - Multi-line comment.

/** ... */ - Javadoc comments (used to generate HTML documentation).

Keywords: Reserved words with specific meanings in Java (e.g., class , public , new , this ).
They cannot be used as identifiers.

Identifiers: Names given to classes, methods, and variables. Must start with a letter, $ , or _ .
Case-sensitive. Cannot contain spaces or match reserved keywords.

2. Control Flow Statements

These statements control the execution path of a program.

Decision Making
1. if , if-else , Nested if , and else-if Ladder

int score = 85;


if (score >= 90) {
[Link]("Grade A");
} else if (score >= 80) {
[Link]("Grade B"); // Prints Grade B
} else {
[Link]("Grade C");
}

2. Classic switch Statement

Selects one of many code blocks to execute based on an expression ( byte , short , char , int ,
String , or enum ).

int day = 3;
switch (day) {
case 1: [Link]("Monday"); break;
case 2: [Link]("Tuesday"); break;
case 3: [Link]("Wednesday"); break; // Matches
default: [Link]("Weekend");
}

[!WARNING]
Forgetting a break statement causes code execution to "fall through" into subsequent cases,
executing them regardless of whether they match.

3. Modern switch Expressions (Java 14+)

Uses the arrow ( -> ) syntax. Eliminates fall-through (no break needed) and can return values directly.
String status = switch (errorCode) {
case 404 -> "Not Found";
case 500, 503 -> "Server Error";
default -> {
[Link]("Logging unknown error...");
yield "Unknown Error"; // 'yield' is used in multi-line switch blocks to
return a value
};
};

Loops

Used to execute a block of code repeatedly as long as a specified condition is met.

// 1. for loop: when iterations are known beforehand


for (int i = 0; i < 5; i++) {
[Link](i + " "); // Prints: 0 1 2 3 4
}

// 2. while loop: condition checked before entering the body


int count = 0;
while (count < 3) {
[Link](count + " "); // Prints: 0 1 2
count++;
}

// 3. do-while loop: body executed at least once, condition checked at the end
int x = 10;
do {
[Link]("Runs once");
x++;
} while (x < 10);

// 4. Enhanced for-loop (for-each): used to iterate through arrays or collections


int[] nums = {10, 20, 30};
for (int num : nums) {
[Link](num + " "); // Prints: 10 20 30
}

Jump Statements

Used to transfer control to another part of the program:

break : Exits the innermost loop or switch block immediately.

continue : Skips the current iteration of the loop and proceeds to the next iteration.
return : Terminates the execution of a method and optionally returns a value to the caller.

3. Methods

A method is a block of code containing statements that runs only when called.

modifier returnType methodName(parameters) {


// Method Body
return value;
}

Method Overloading

Declaring multiple methods in the same class with the same name but different parameter lists. It is
compile-time polymorphism.
Rules for overloading:

Must change the number of parameters, or

Must change the data types of parameters, or

Must change the order of parameters.

[!IMPORTANT]
Changing the return type alone or the access modifier alone is not valid method overloading
and will trigger a compile-time error.

public class Calculator {


public int add(int a, int b) { return a + b; }
public double add(double a, double b) { return a + b; } // Overloaded by
parameter type
public int add(int a, int b, int c) { return a + b + c; } // Overloaded by
parameter count
}

Variable-Length Arguments (varargs)

Allows a method to accept zero or more arguments of a specified type. Represented by three dots
( ... ).

public void printNumbers(int... numbers) {


for (int num : numbers) {
[Link](num + " ");
}
}

[!WARNING]
A method can have only one varargs parameter, and it must be the last parameter in the
signature (e.g., public void printInfo(String label, int... nums) ).

Pass By Value in Java

Java is strictly Pass By Value.

For Primitives: A copy of the value is passed. Modifying the parameter inside the method does not
affect the original variable.

For Objects: A copy of the reference (memory address) is passed. The reference copy points to the
same object on the heap. Thus:

Modifying fields of the object inside the method will affect the caller's object.

Reassigning the reference variable inside the method to a new object will not change the caller's
reference.

class Dog { String name; Dog(String n) { [Link] = n; } }

public class Test {


public static void modify(int x, Dog d) {
x = 100; // Copy of value changed; original remains unchanged
[Link] = "Max"; // Modifies field of shared heap object
d = new Dog("Buddy"); // Copy of reference reassigned; caller's pointer is
unaffected
}
}

Recursion

A process in which a method calls itself. Requires a base case to terminate recursion, otherwise it
triggers a StackOverflowError due to exhaustively consuming call stack memory frames.

// Factorial Example: n! = n * (n-1)!


public int factorial(int n) {
if (n <= 1) return 1; // Base case
return n * factorial(n - 1); // Recursive call
}

4. Arrays

An array is a fixed-size, homogeneous container that holds elements of the same data type.

1D Arrays

// Declaration & Instantiation


int[] arr = new int[5]; // Allocated with default values of 0
int[] primes = {2, 3, 5, 7, 11}; // Literal shorthand
2D and Multidimensional Arrays

Arrays of arrays. Elements are stored as references to other arrays.

int[][] matrix = new int[3][4]; // 3 rows, 4 columns


int[][] initializedMatrix = {
{1, 2, 3},
{4, 5, 6}
};

Jagged Arrays

An array of arrays where the member arrays can have different sizes.

int[][] jagged = new int[3][]; // Define row count first


jagged[0] = new int[2]; // Row 0 has 2 columns
jagged[1] = new int[4]; // Row 1 has 4 columns
jagged[2] = new int[1]; // Row 2 has 1 column

Array Traversal

int[] data = {10, 20, 30};

// Standard for loop (provides index access)


for (int i = 0; i < [Link]; i++) {
[Link]("Index " + i + ": " + data[i]);
}

// Enhanced for loop (cleaner read-only loop)


for (int val : data) {
[Link](val);
}

Array Searching and Sorting

Linear Search

Compares each element sequentially. O(N ) time complexity.

public int linearSearch(int[] arr, int target) {


for (int i = 0; i < [Link]; i++) {
if (arr[i] == target) return i;
}
return -1;
}

Binary Search
Finds target in a sorted array by repeatedly dividing the search space in half. O(log N ) time
complexity.

public int binarySearch(int[] arr, int target) {


int low = 0, high = [Link] - 1;
while (low <= high) {
int mid = low + (high - low) / 2; // Prevents integer overflow: (low +
high) / 2
if (arr[mid] == target) return mid;
else if (arr[mid] < target) low = mid + 1;
else high = mid - 1;
}
return -1;
}

Arrays Utility Class ( [Link] )

The Arrays class provides static helper methods to manipulate arrays:

[Link](arr) : Sorts the array into ascending order (uses Dual-Pivot Quicksort for primitives,
Timsort for objects). Time complexity: O(N log N ).
[Link](arr, key) : Searches sorted array for key . Returns index if found, else
negative insertion point reference.

[Link](arr) / [Link](multiArr) : Returns string representations of array


contents.
[Link](arr, newLength) : Copies array, padding with defaults or truncating to fit
newLength .

[Link](arr1, arr2) : Compares contents and lengths of arrays.


02_Object_Oriented_Programming

Module 2: Object-Oriented Programming (OOP)

Object-Oriented Programming is a paradigm centered around objects rather than actions, and data
rather than logic. It enables modularity, reusability, and scalability.

1. Classes and Objects


Class: A user-defined blueprint, template, or prototype from which objects are created. It represents
the set of properties (fields) and behaviors (methods) common to all objects of that type. A class
does not occupy memory space until instantiated.
Object: A physical and logical instance of a class. It has state (stored in fields), behavior (defined by
methods), and identity (unique address in memory). Objects occupy memory in the Heap.

public class Car {


// Fields (State)
String brand;
int speed;

// Methods (Behavior)
void accelerate() {
speed += 10;
}
}

2. Constructors

A constructor is a special block of code initialized when an object is created.

It has the same name as the class.

It has no return type (not even void ).

It is invoked automatically using the new keyword.

Types of Constructors

1. Default Constructor

If no constructor is defined in a class, the Java compiler automatically inserts a public default
constructor with no arguments. It initializes instance variables to their default values.
[!WARNING]
If you write any custom constructor (parameterized or no-arg), the compiler does not generate
the default constructor automatically. You must define it manually if you still need it.

2. Parameterized Constructor

Used to initialize objects with custom state values.

public class Student {


String name;
int age;

// Parameterized constructor
public Student(String name, int age) {
[Link] = name;
[Link] = age;
}
}

Constructor Overloading

Having multiple constructors with different parameter lists (type, count, or sequence) in the same class.

Constructor Chaining

The process of calling one constructor from another constructor in the same class (using this() ) or
from the parent class (using super() ).

this() : Calls another constructor within the same class.

super() : Calls the constructor of the immediate parent class.

[!IMPORTANT]
The call to this() or super() must be the very first statement in the constructor. You cannot
use both in the same constructor.

public class Device {


String type;
int serialNo;

// Constructor 1 (Chained)
public Device() {
this("Generic"); // Calls Constructor 2
}

// Constructor 2 (Chained)
public Device(String type) {
this(type, 0); // Calls Constructor 3
}

// Constructor 3 (Final Initialization)


public Device(String type, int serialNo) {
[Link] = type;
[Link] = serialNo;
}
}

3. Encapsulation

Encapsulation is the practice of bundling data (variables) and code (methods) together into a single unit
(class) and restricting direct access to some components (data hiding).

Implementation: Mark instance fields as private .

Expose: Provide public getter and setter methods to inspect and modify values. This allows
verification and write-protection logic to execute before data modifications occur.

public class BankAccount {


private double balance; // Private variable (Data Hiding)

public double getBalance() {


return balance;
}

public void deposit(double amount) {


if (amount > 0) { // Encapsulated business logic / validation
balance += amount;
}
}
}

4. Inheritance

The mechanism by which one class acquires the properties and behaviors of another class using the
extends keyword. It facilitates code reusability and creates an "IS-A" relationship.

Super/Parent/Base Class: The class whose properties are inherited.

Sub/Child/Derived Class: The class that inherits the properties.

Types of Inheritance in Java

1. Single 2. Multilevel 3. Hierarchical


[Parent] [Grandparent] [Parent]
| | / \
[Child] [Parent] [Child1] [Child2]
|
[Child]

Single: A class inherits from a single parent class.

Multilevel: A class inherits from a parent, which itself inherits from another parent class (e.g., C
extends B, B extends A).
Hierarchical: Multiple child classes inherit from a single parent class.

[!CAUTION]
Multiple Inheritance is NOT supported in Java using classes. A class cannot extend more
than one class (e.g., class C extends A, B is illegal). This avoids the Diamond Problem
(ambiguity in which method implementation to inherit from A and B).

5. Polymorphism

Polymorphism ("many forms") allows us to perform a single action in different ways.

Polymorphism
/ \
Compile-Time Run-Time
(Overloading) (Overriding)

Compile-Time Polymorphism (Static Binding)

Resolved during compilation. Achieved via Method Overloading (same method name, different
signatures in the same class).

Run-Time Polymorphism (Dynamic Binding)

Resolved during execution. Achieved via Method Overriding (subclass provides a specific
implementation of a method declared in its parent class).

Rules for Method Overriding:

1. Must have the same name and parameter list.

2. The return type must be the same or a covariant return type (a subclass of the parent's return
type).

3. The access modifier cannot be more restrictive than the parent's (e.g., a protected method cannot
be overridden as private ).

4. Cannot override methods declared as static , final , or private .

5. Cannot throw broader checked exceptions than the overridden method.


class Animal {
void makeSound() {
[Link]("Animal makes a sound");
}
}

class Dog extends Animal {


@Override // Annotation to verify correct overriding
void makeSound() {
[Link]("Dog barks");
}
}

public class Main {


public static void main(String[] args) {
Animal myAnimal = new Dog(); // Upcasting
[Link](); // Prints "Dog barks" (Dynamic method dispatch)
}
}

6. Abstraction

Abstraction is the process of hiding implementation details and showing only key features to the user. It
is achieved using Abstract Classes and Interfaces.

1. Abstract Classes

Declared with the abstract keyword.

Cannot be instantiated (cannot do new AbstractClass() ).

Can have both abstract methods (no body) and concrete methods (with body).

Can have instance variables, constants, static variables, and constructors.

abstract class Vehicle {


String color;

Vehicle(String color) { [Link] = color; } // Constructor allowed


abstract void accelerate(); // Abstract method (no body)

void turnOnHeadlights() { // Concrete method


[Link]("Headlights turned on.");
}
}

2. Interfaces
An interface is a blueprint of a class that contains static constants and abstract methods (before Java
8). It represents a contract and enables Multiple Inheritance and loose coupling.

Interface Rules:

Declared using the interface keyword.

All variables declared are implicitly public static final .

All abstract methods are implicitly public abstract .

Classes implement interfaces using the implements keyword.

A class can implement multiple interfaces (e.g., class A implements Interface1, Interface2 ).

Interface Additions (Java 8+):

Default Methods: Methods with bodies using the default keyword to allow interface evolution
without breaking implementation classes.

Static Methods: Utility methods belonging directly to the interface.

Private Methods (Java 9+): Used to share code between default methods.

interface Flyable {
void fly(); // implicitly public abstract

default void land() { // default method


[Link]("Landing safely...");
}
}

Comparison: Abstract Class vs Interface

Feature Abstract Class Interface (Modern Java)

Instantiation Cannot be instantiated. Cannot be instantiated.

Single class inheritance Multiple interface implementation


Inheritance
( extends ). ( implements ).

Can have instance (non-static) All variables are implicitly public


Variables
variables. static final .

Can have abstract, concrete, Can have abstract, default (Java 8),
Methods
static, final methods. static, and private methods.

Constructor Can define constructors. Cannot define constructors.

Access Members can be private , Members are implicitly public (private


Modifiers protected , public , or default. allowed for helper methods).

7. Association: Aggregation and Composition


Association defines the relationship between two separate classes through their objects. It establishes a
"HAS-A" relationship.

Association
/ \
Aggregation Composition
(Weak HAS-A) (Strong HAS-A)

1. Aggregation (Weak Association)

The child object can exist independently of the parent object.

If the parent object is destroyed, the child object survives.

Example: A Department has a Teacher . If the department is closed, the teachers still exist.

class Teacher { String name; }

class Department {
private List<Teacher> teachers; // Reference to teachers
Department(List<Teacher> teachers) {
[Link] = teachers;
}
}

2. Composition (Strong Association)

The child object cannot exist independently of the parent object.

The life cycle of the child is entirely managed by the parent.

Example: A House has a Room . If the house is demolished, the room is destroyed.

class Room { String type; Room(String t) { [Link] = t; } }

class House {
private Room studyRoom; // Room created and destroyed with House
House() {
[Link] = new Room("Study");
}
}
03_Advanced_OOP_and_Packages

Module 3: Advanced OOP, Access Modifiers, and Strings

This module covers keywords, package scopes, access level security, and Java String handling.

1. Advanced OOP Concepts & Keywords

The this Keyword

this is a reference variable that refers to the current object instance.

Resolve Name Ambiguity: Differentiate instance variables from parameters.


Invoke Constructors: Call constructor within another constructor using this() .

Pass as Argument: Pass the current instance to other methods or constructors.

public class User {


private String username;

public User(String username) {


[Link] = username; // '[Link]' is the instance field,
'username' is the constructor parameter
}
}

The super Keyword

super is a reference variable used to refer to the immediate parent class object.

Access Parent Variables: Resolve shadowing when parent and child share field names.

Invoke Parent Methods: Invoke parent overridden methods.

Invoke Parent Constructors: Call parent constructors using super() (must be the first statement
of the child constructor).

class Parent {
void show() { [Link]("Parent Show"); }
}
class Child extends Parent {
void show() {
[Link](); // Calls parent's show method
[Link]("Child Show");
}
}

The final Keyword

Used to restrict entity customization.

Applied
Behavior Example
To

Creates constants. Value cannot be modified


Variables final double PI = 3.14159;
once initialized.

public final void log() {


Methods Prevents method overriding by subclasses. ... }

Prevents inheritance (cannot be extended, public final class


Classes MathUtils { ... }
e.g., String class).

The static Keyword

Used for memory management. Members marked static belong to the class itself rather than
instances.

Static Variables: Shared single copy among all instances of the class. Initialized when the class is
loaded.
Static Methods: Can be invoked without creating an instance. Can only access static variables and
call static methods directly (cannot use this or super ).

Static Blocks: Executed once when the class is loaded into JVM memory. Used to initialize static
variables.

Static Nested Classes: Nested classes that do not require an outer class instance reference.

public class Tracker {


static int count = 0; // Static variable

static { // Static initialization block


[Link]("Tracker class loaded in memory.");
}

static void increment() { // Static method


count++;
}
}

The Object Class

The root class of the Java hierarchy. Every class implicitly inherits from [Link] .
Crucial inherited methods:
String toString() : Returns string representation of object (defaults to ClassName@hashCode ).

boolean equals(Object obj) : Checks references equality by default. Often overridden for value
comparison.
int hashCode() : Returns integer hash representation. Must be overridden if equals() is
overridden.
Object clone() : Creates copy of object (requires implementing Cloneable interface).

Class<?> getClass() : Returns runtime representation of the class.

instanceof Operator and Dynamic Method Dispatch

instanceof : Tests whether an object is an instance of a specific class or subclass.

Dynamic Method Dispatch: The mechanism by which a call to an overridden method is resolved at
runtime (rather than compile-time). This is the foundation of runtime polymorphism.

Covariant Return Type

An overriding method in a subclass can declare a return type that is a subclass (derived type) of the
return type declared in the parent method.

class Producer {
Producer get() { return this; }
}
class SubProducer extends Producer {
@Override
SubProducer get() { return this; } // Covariant return type (SubProducer
instead of Producer)
}

2. Packages

Packages group related classes, interfaces, and subpackages. They resolve naming conflicts and
control directory structures.

Built-in Packages: Bundled with JDK (e.g., [Link] [implicitly imported], [Link] , [Link] ,
[Link] ).

User-defined Packages: Declared via the package statement at the top of the file:

package [Link];

Importing:

import [Link]; - Imports a single class.

import [Link].*; - Wildcard import (imports all public classes in package; does not
import subpackages).
import static [Link].*; - Static import (allows calling static fields/methods directly
without class name).

3. Access Modifiers

Java provides access control levels to restrict visibility of classes, constructors, variables, and methods.

Inside Inside Outside Package by Outside


Modifier
Class Package Subclass Only Package

private Yes No No No

default (no
Yes Yes No No
modifier)

protected Yes Yes Yes No

public Yes Yes Yes Yes

4. Strings in Java

The String Class

Represents a read-only, immutable sequence of characters.

1. Immutability & Why Strings are Immutable:

Once created, a String object's content cannot be changed. Modification creates a new String
object.

String Pool (Space Efficiency): Reuses string literals, saving Heap space.

Security: Databases, usernames, and file paths are passed as strings. Immutability prevents values
from changing mid-execution.

Thread Safety: Safely shared across multiple threads without synchronization.

Hashcode Caching: The hashcode is computed once and cached, making Strings fast keys for
HashMap .

2. The String Pool

A special memory storage area inside the Java Heap.

When creating strings using Literals ( String s = "Java" ), Java checks the pool first. If it exists,
the existing reference is shared.

When using the new Keyword ( String s = new String("Java") ), Java bypasses the pool and
allocates a new object in the normal Heap.

Heap Memory
+-----------------------------------------+
| [String Object] (Normal Heap) |
| Ref: s2 --------------------+ |
| | |
| +--------------------------+ | |
| | String Pool | | |
| | | | |
| | "Java" <----+ s1 | | |
| | <----+ intern() | | |
| +--------------------------+ | |
+-----------------------------------------+

StringBuilder vs StringBuffer

When extensive string manipulations (concatenations, inserts, deletes) are required, using String is
inefficient due to object recreation. Use mutable alternatives instead:

StringBuilder (Java 5):

Mutable char array sequence.


Not Thread-safe (no synchronized methods).

Fast execution speed (recommended for single-thread scenarios).

StringBuffer (Java 1):

Mutable char array sequence.

Thread-safe (methods are synchronized).

Slower execution speed due to thread-synchronization overhead.

Important String Comparisons & Concepts

== Operator: Compares reference equality (checks if both variables point to the exact same
memory address).

equals(Object obj) : Compares character-by-character value equality.

compareTo(String other) : Lexicographically compares two strings character by character. Returns


0 if equal, negative if current is smaller, positive if current is larger.

intern() Method: Invoked on a String object. If the string is already in the String Pool, its
reference is returned. If not, the string is added to the pool and the pool reference is returned.

String s1 = "Hello";
String s2 = "Hello";
String s3 = new String("Hello");
String s4 = [Link](); // Fetch pool reference

[Link](s1 == s2); // true (same literal pool address)


[Link](s1 == s3); // false (s3 is on general Heap)
[Link]([Link](s3)); // true (same values)
[Link](s1 == s4); // true (s4 refers to pool literal returned by
intern())
04_Exceptions_Wrapper_Generics

Module 4: Exception Handling, Wrapper Classes, and Generics

This module covers Java Exception safety, Type encapsulation using wrappers, and compile-time type-
safety with Generics.

1. Exception Handling
An exception is an unwanted or unexpected event that occurs during the execution of a program (at
runtime) that disrupts the normal flow of instruction execution.

Exception Hierarchy

All exception and error types are subclasses of the Throwable class, which is the root of the hierarchy.

Throwable
/ \
Exception Error
/ \ \
(Checked) RuntimeException (StackOverflowError,
(Unchecked) OutOfMemoryError, etc.)

Error : Indicates serious, non-recoverable problems that a reasonable application should not try to
catch (e.g., OutOfMemoryError , StackOverflowError , VirtualMachineError ).

Exception : Indicates conditions that a reasonable application might want to catch.

Checked Exceptions: Classes that extend Exception but do not inherit from
RuntimeException . They are checked at compile-time. The program must handle them or
declare them, otherwise the code won't compile (e.g., IOException , SQLException ,
FileNotFoundException ).

Unchecked Exceptions (Runtime Exceptions): Classes that extend RuntimeException . They


are checked at runtime. Handling is optional at compile-time (e.g., NullPointerException ,
ArithmeticException , ArrayIndexOutOfBoundsException , IllegalArgumentException ).

Keywords in Exception Handling

try : Wraps a block of code where an exception might occur. Must be followed by at least one
catch block or a finally block.

catch : Used to handle exceptions thrown in the associated try block. Multiple catch blocks are
evaluated sequentially from specific to general.

Multi-catch (Java 7+): Catch multiple unrelated exceptions in a single block using | .
catch (ArithmeticException | NullPointerException e) { ... }

finally : Executed regardless of whether an exception is thrown, caught, or if the block returns
early. Ideal for resource cleanup (closing connections, files).

Exceptions: finally will not execute if [Link]() is invoked, if the JVM crashes, or
during infinite loops.

throw : Used to explicitly throw a single instance of an exception (e.g., throw new
ArithmeticException("Divide by zero"); ).

throws : Used in a method signature to declare that the method may propagate specific checked
exceptions to its caller.

public void readFile(String path) throws IOException { // Declares checked


exception
if (path == null) {
throw new IllegalArgumentException("Path cannot be null"); // Throws
unchecked exception
}
// FileReader operations...
}

Try-With-Resources (Java 7+)

A try statement that declares one or more resources (objects implementing


[Link] ). It ensures that each resource is closed at the end of the statement,
eliminating the need for explicit finally cleanup.

try (BufferedReader br = new BufferedReader(new FileReader("[Link]"))) {


[Link]([Link]());
} catch (IOException e) {
[Link]();
} // br is closed automatically here

Custom (User-Defined) Exceptions

Used to represent specific domain errors.

Extend Exception to create a checked exception.

Extend RuntimeException to create an unchecked exception.

public class InsufficientFundsException extends Exception {


public InsufficientFundsException(String message) {
super(message); // Pass message to Parent Exception class
}
}
2. Wrapper Classes

Wrapper classes provide a way to use primitive data types as objects. They are located in the
[Link] package.

Primitive Wrapper Class

byte Byte

short Short

int Integer

long Long

float Float

double Double

char Character

boolean Boolean

Autoboxing and Unboxing

Autoboxing: The automatic conversion that the Java compiler makes between the primitive types
and their corresponding object wrapper classes (e.g., converting an int to an Integer ).

Unboxing: The automatic conversion of wrapper class objects back to their corresponding primitive
values (e.g., converting an Integer to an int ).

// Autoboxing
Integer obj = 100; // Compiler runs: [Link](100)

// Unboxing
int primitive = obj; // Compiler runs: [Link]()

3. Generics

Generics add type safety to Java. They allow classes, interfaces, and methods to take types as
parameters, enabling code reuse with strict compile-time checking (eliminating runtime
ClassCastException hazards).

Generic Classes and Methods

// Generic Class
public class Box<T> { // T is a type parameter
private T value;
public void set(T value) { [Link] = value; }
public T get() { return value; }
}
// Generic Method
public static <E> void printArray(E[] elements) {
for (E element : elements) {
[Link](element + " ");
}
[Link]();
}

Bounded Type Parameters

Limits the types that can be passed to a type parameter. Use extends for upper bounding.

public class NumericBox<T extends Number> { // Accepts Integer, Double, Float, etc.
private T value;
public double doubleValue() {
return [Link]();
}
}

Wildcards ( ? )

Used to represent an unknown type.

1. Unbounded Wildcard ( ? ): Represents any type. Useful when a method uses only functionality
found in the Object class.

public void printList(List<?> list) { ... }

2. Upper Bounded Wildcard ( ? extends T ): Restricts the unknown type to be a specific type T or its
subclasses. Represents covariance. Useful for reading from a structure.

public static double sumOfList(List<? extends Number> list) { ... }

3. Lower Bounded Wildcard ( ? super T ): Restricts the unknown type to be a specific type T or its
superclasses. Represents contravariance. Useful for writing to a structure.

public static void addIntegers(List<? super Integer> list) {


[Link](10); // Allowed because list is of Integer or its parent type
}

The PECS Rule (Producer Extends, Consumer Super)

Producer ( extends ): If you are reading data from a collection, it acts as a producer. Use ? extends
T.

Consumer ( super ): If you are writing data into a collection, it acts as a consumer. Use ? super T .

Type Erasure
Java implements generics using type erasure to ensure backward compatibility with older Java versions
that did not support generics.

During compilation, the compiler replaces all type parameters in generic types with their bounds (or
Object if unbounded).

The compiler inserts necessary type casts to ensure type safety.


As a result, generic type information is not available at runtime. (e.g., List<Integer> and
List<String> both compile down to the raw type List ).
05_Collections_Framework

Module 5: Java Collections Framework

The Java Collections Framework (JCF) is a unified architecture for representing and manipulating
collections of data.

1. JCF Hierarchy Overview

Iterable
|
Collection
/ | \
List Queue Set
| | |
ArrayList Priority- HashSet
LinkedList Queue LinkedHashSet
Vector | |
Stack Deque TreeSet
|
ArrayDeque

Map (Standalone Interface)


/ \
HashMap SortedMap
| |
LinkedHashMap TreeMap

2. List Interface

An ordered collection (sequence) that allows duplicate elements and positional access.

ArrayList :

Underlying Structure: Resizable array.


Features: Direct index-based random access is extremely fast (O(1)). Resizing incurs
overhead (creates a new array of 1.5x capacity and copies elements). Insertion/deletion in the
middle is slow (O(N )) due to element shifting.

LinkedList :
Underlying Structure: Doubly linked list.

Features: Implements both List and Deque . Fast insertions/deletions at endpoints (O(1)) but
slow search/random access (O(N )) because it must traverse node by node. High memory
overhead due to pointer storage.
Vector (Legacy):

Dynamic array similar to ArrayList but thread-safe (methods are synchronized). Slower than
ArrayList due to locking overhead.

Stack (Legacy):

Extends Vector (hence thread-safe). Implements LIFO (Last-In-First-Out).

Note: In modern Java, ArrayDeque is preferred for stack operations.

3. Queue & Deque Interfaces

Collections designed for holding elements prior to processing.

PriorityQueue :

Underlying Structure: Min-Heap / Binary Heap.

Features: Elements are ordered based on natural ordering or a custom Comparator . Head of
the queue is always the smallest element. Does not allow null elements. O(log N ) for
insertion and extraction.

Deque / ArrayDeque (Double Ended Queue):

Underlying Structure: Resizable circular array.

Features: Elements can be added/removed from both ends. Faster than Stack (when used as
a stack) and LinkedList (when used as a queue). Does not allow null .

4. Set Interface

A collection that contains no duplicate elements.

HashSet :

Underlying Structure: Backed internally by a HashMap instance.

Features: Unordered and unsorted. Allows at most one null element. O(1) average time
complexity for basic operations ( add , remove , contains ).

LinkedHashSet :

Underlying Structure: Hash table with a doubly-linked list running through its elements.
Features: Maintains insertion order. Slightly slower than HashSet due to maintaining the
linked list.
TreeSet :

Underlying Structure: Backed internally by a Red-Black Tree ( TreeMap ).

Features: Elements are stored in a sorted order (natural order or custom Comparator ). Does
not allow null . Time complexity for basic operations is O(log N ).

5. Map Interface

An object that maps keys to values. A map cannot contain duplicate keys; each key can map to at most
one value.

HashMap :

Underlying Structure: Hash table (array of buckets containing Linked Lists/Red-Black Trees).
Features: Unordered and unsorted. Allows one null key and multiple null values. O(1)
average performance for insertions and retrieval.

LinkedHashMap :

Extends HashMap . Maintains insertion order (or access-order) using a doubly-linked list.

TreeMap :

Implements NavigableMap (backed by a Red-Black Tree). Keys are stored in sorted order.
Does not allow null keys. O(log N ) time complexity for lookup/insertion.

Hashtable (Legacy):

Synchronized (thread-safe) version of HashMap . Does not allow any null key or value.

6. HashMap Internals (Crucial for Interviews)

Internal Data Structure

A HashMap consists of an array of Node objects (called buckets). Each node contains:

1. int hash (hash code of the key)

2. K key

3. V value

4. Node<K,V> next (pointer to the next node in case of collisions)

Buckets Array (Index = hash & (n-1))


[0] -> Null
[1] -> Node(K1, V1) -> Node(K2, V2) (Linked List due to collision)
[2] -> Node(K3, V3) (Treeified if bucket size >= 8)

Key Operations
1. How put(key, value) works:
1. Hash Calculation: Calls the key's hashCode() and applies an internal defensive hash function to
spread bits.
2. Index Calculation: Calculates the index bucket using index = hash & (n - 1) (where n is the
array length, always a power of 2).

3. Collision Handling:

If the bucket is empty, a new Node is created and inserted at the index.

If a collision occurs (same bucket index), Java traverses the bucket:

If the key already exists (checked via hashCode() and equals() ), the old value is
overwritten.

If the key is new, the Node is appended to the linked list.

4. Treeification: If a bucket's linked list size exceeds 8 and the total HashMap capacity is at least 64,
the linked list is converted into a Red-Black Tree to improve search time from O(N ) to O(log N ).
If size falls below 6 during resizing, it is converted back to a linked list.

5. Resize check: If size exceeds the threshold (Capacity × Load Factor [default = 0.75]), the map
doubles its capacity and rehashes all elements.

2. How get(key) works:

1. Calculates key's hash and bucket index.

2. Goes to the bucket array index and compares the key in the first node using equals() .

3. If it matches, returns the value.

4. If not, traverses the Linked List or Red-Black Tree calling equals() on each node.

7. Iterators

An Iterator is an object that can be used to loop through collections.

Iterator vs ListIterator

Feature Iterator ListIterator

Any Collection (List, Set,


Applicability Only List implementations
Queue)

Direction Forward only Bidirectional (Forward and Backward)

Read-only traversal,
Operations Supports read, remove() , set() , add()
supports remove()

Key hasNext() , next() , hasNext() , next() , hasPrevious() ,


Methods remove() previous() , add() , set()

Fail-Fast vs Fail-Safe Iterators


Fail-Fast Iterators:

Throw ConcurrentModificationException immediately if the collection is structurally modified


(adding or removing elements directly, not through the iterator's own methods) while iterating.
Mechanism: Uses an internal modification counter ( modCount ).

Examples: Iterators of ArrayList , HashSet , HashMap .

Fail-Safe (Non-Fail-Fast) Iterators:

Do not throw exceptions if the collection is modified during iteration.

Mechanism: They operate on a clone or copy of the collection (e.g., CopyOnWriteArrayList ) or


allow concurrent modifications in a thread-safe structure (e.g., ConcurrentHashMap ).

Examples: Iterators of ConcurrentHashMap , CopyOnWriteArrayList .

8. Sorting Collections: Comparable vs Comparator

To sort user-defined objects, Java needs to know how to compare them.

Comparable

Located in [Link] package.

Implemented by the class itself to define its natural ordering (e.g., sorting Students by Roll
Number).
Overrides a single method: int compareTo(T o) .

Returns negative if this < o

Returns zero if this == o

Returns positive if this > o

public class Student implements Comparable<Student> {


int rollNo;
public int compareTo(Student other) {
return [Link] - [Link];
}
}
// Sorts automatically using: [Link](studentList)

Comparator

Located in [Link] package.

Implemented in separate external helper classes or inline lambdas to define custom/multiple


ordering sequences (e.g., sorting Students by Age, Name, or Grade).
Overrides method: int compare(T o1, T o2) .
import [Link];
// Sorting by Name
Comparator<Student> nameComparator = (s1, s2) -> [Link]([Link]);

// Sorts using: [Link](studentList, nameComparator)

9. Quick Comparison Matrix

Time
Allows Allows
Collection Ordered Sorted Complexity
Duplicates Nulls
(Search)

Yes O(N ) (index


ArrayList No Yes Yes
(Insertion) lookup is O(1))

Yes
LinkedList
(Insertion)
No Yes Yes O(N )

Yes
HashSet No No No
(max 1)
O(1) average

Yes Yes
LinkedHashSet
(Insertion)
No No
(max 1)
O(1) average

Yes
TreeSet
(Sorted)
Yes No No O(log N )

Keys: No; One Null


HashMap No No
Values: Yes Key
O(1) average

Yes (Sorted Yes Keys: No; No Null


TreeMap
Keys) (Keys) Values: Yes Key
O(log N )
06_Memory_Management_and_JVM

Module 6: Java Memory Management and JVM Internals

This module covers JVM runtime memory areas, Object lifecycle tracking, Garbage Collection
mechanisms, Class Loading, and performance tuning configurations.

1. JVM Runtime Memory Areas


The JVM allocates memory dynamically during execution. Memory is split into five main regions:

+-----------------------------------------------------------------------+
| JVM Memory |
| |
| [ Shared across all threads ] |
| +--------------------------+ +-------------------------------+ |
| | Heap | | Method Area | |
| | (Objects & Arrays) | | (Class Metadata/Constants) | |
| +--------------------------+ +-------------------------------+ |
| |
| [ Thread-Local (Private to each thread) ] |
| +------------------+ +------------------+ +---------------+ |
| | JVM Stack | | PC Register | | Native Stack | |
| | (Frames/Locals) | | (Current Instruct) | | (C/C++ Calls) | |
| +------------------+ +------------------+ +---------------+ |
+-----------------------------------------------------------------------+

1. Stack Memory

Scope: Thread-local (each thread has its own stack).

Content: Method execution frames. Inside a frame, it stores local variables, primitive data values,
and reference addresses pointing to objects on the Heap.

Behavior: LIFO (Last-In-First-Out). Allocation/deallocation happens automatically when methods


enter and exit.

Error: Exceeding stack limit triggers StackOverflowError .

2. Heap Memory

Scope: Shared across all threads.

Content: All objects and their instance variables, arrays.


Behavior: Dynamically allocated. Managed by the Garbage Collector (GC).
Error: Exceeding heap limit triggers OutOfMemoryError: Java heap space .

3. Method Area & Metaspace

Method Area: Stores class structure definitions, field details, method data, code for
methods/constructors, and the runtime constant pool.

PermGen (Permanent Generation): The legacy implementation of the Method Area up to Java 7. It
had a fixed maximum size, leading to frequent OutOfMemoryError: PermGen space .

Metaspace (Java 8+): Replaced PermGen. It stores class metadata but is allocated out of Native
Memory (local system RAM) rather than Java Heap. It resizes dynamically, lowering the risk of
running out of class metadata space.

2. Object Life Cycle & Reference Types

Object Creation Process

When you run User u = new User() :

1. Class Loading: JVM checks if the User class is loaded. If not, ClassLoader loads metadata into
Metaspace.
2. Heap Allocation: JVM allocates space for the User object in the Heap.

3. Initialization: Default values are set, instance blocks execute, and the User constructor runs.

4. Stack Reference: The reference variable u is stored on the calling thread's stack frame, containing
the heap memory address of the newly created object.

Java Reference Types

To control how objects are garbage collected, Java provides four reference levels in [Link] :

1. Strong Reference (Default):

Example: User u = new User();

An object with a active strong reference is never eligible for garbage collection.

2. Soft Reference:

Example: SoftReference<User> soft = new SoftReference<>(u);

GC only reclaims soft-referenced objects if the JVM is running out of memory (great for building
memory-sensitive caches).

3. Weak Reference:

Example: WeakReference<User> weak = new WeakReference<>(u);

Reclaimed during the very next GC cycle, regardless of whether memory is full (used in
WeakHashMap ).

4. Phantom Reference:
Example: PhantomReference<User> phantom = new PhantomReference<>(u, queue);

Used to track when the object is physically removed from memory. Requires a reference queue.

3. Garbage Collection (GC)

Garbage Collection is the process of automatically identifying and deleting unreachable objects from the
Heap, freeing up space for new allocations.

Generational Garbage Collection Theory

Most objects are short-lived. To optimize collection passes, the Heap is divided into distinct generations:

+--------------------------------------------------------+-------------------+
| Young Generation | Old Generation |
| +------------------+ +---------------------------+ | (Tenured Space) |
| | Eden Space | | Survivor Spaces | | |
| | | | [ S0 ] | [ S1 ] | | |
| +------------------+ +---------------------------+ | |
+--------------------------------------------------------+-------------------+

1. Young Generation:

Eden Space: New objects are allocated here.


Survivor Spaces (S0 / S1): When Eden fills up, a Minor GC occurs. Survived objects are
moved to one of the survivor spaces with their age incremented.

2. Old (Tenured) Generation:

If objects survive multiple Minor GC runs (exceeding the aging threshold, e.g., default 15), they
are "promoted" to the Old Generation.
When the Old Generation fills up, a Major GC occurs (often causing a Stop-The-World pause).

Garbage Collection Algorithms

Mark and Sweep: Traces references from GC Roots (threads, static variables, local stack refs) to
mark active objects, then sweeps unmarked objects.

Mark-Sweep-Compact: Same as above but slides all surviving objects to one side of the heap to
prevent memory fragmentation.
Copying: Splits memory in half, marks active objects, and copies them to the other half, cleanly
freeing the entire source space (used in Young Gen).

Modern Garbage Collectors

Serial GC: Single-threaded collector. Freezes application threads (Stop-The-World) during


collections. Suitable for small CLI applications.
Parallel GC (Throughput Collector): Uses multiple threads to perform young collection, minimizing
GC time.
G1 (Garbage-First) GC: Splits heap into equal regions. It estimates which regions contain the most
garbage and cleans those first, meeting target pause times (default collector in modern Java).

ZGC (Zero Garbage Collector): An ultra-low latency collector designed to handle massive heaps
(terabytes) with pauses not exceeding a few milliseconds.

4. JVM Internals

+---------------------------------------------+
| ClassLoader Subsystem |
| Loading ---> Linking ---> Initialize |
+---------------------------------------------+
|
+---------------------------------------------+
| Runtime Data Areas |
| Heap | Stack | Metaspace | PC | Native |
+---------------------------------------------+
|
+---------------------------------------------+
| Execution Engine |
| Interpreter | JIT Compiler | GC Engine |
+---------------------------------------------+

ClassLoader Subsystem

Loads compiled .class files into JVM memory. It operates in three phases:

1. Loading: Locates and reads .class binary data. Uses delegation pattern:

Bootstrap ClassLoader: Loads core libraries ( [Link] / [Link] module).

Platform/Extension ClassLoader: Loads platform/extension libraries.

Application ClassLoader: Loads classes from the system class path.

2. Linking:

Verification: Validates bytecode syntax against JVM security rules.

Preparation: Allocates memory for static fields and assigns default values.

Resolution: Translates symbolic reference paths into direct memory pointers.

3. Initialization: Executes static blocks and assigns initial values to static variables.

The Execution Engine

Interpreter: Reads bytecode instructions one by one and executes them. It is fast to startup but
slower during loops and repetitive execution.
JIT (Just-In-Time) Compiler: Monitors code execution. If a block of code is executed frequently
("Hotspot"), JIT compiles that bytecode into native machine code directly executed by the CPU,
bypassing interpretation.

Includes compilers like C1 (client compiler) for fast compilation and C2 (server compiler) for
heavily optimized code.

5. Performance Tuning Basics

Critical JVM Arguments

JVM parameters are configured via command-line flags when starting the application:

-Xms<size> : Sets the initial heap size (e.g., -Xms2g for 2 Gigabytes).

-Xmx<size> : Sets the maximum heap size (e.g., -Xmx4g for 4 Gigabytes). Prevents heap
exhaustion errors.

-Xss<size> : Sets the stack size per thread (e.g., -Xss512k to fit more threads).

-XX:MetaspaceSize=<size> : Initial threshold of class metadata allocation before GC triggers.

-XX:MaxMetaspaceSize=<size> : Maximum allowed memory for Metaspace class loading.

-XX:+UseG1GC : Instructs JVM to use the Garbage-First Collector.

-XX:+UseZGC : Instructs JVM to use the Z Garbage Collector (for low latency).

-XX:NewRatio=2 : Ratio of Old Gen to Young Gen size (2 means Old Gen is twice the size of Young
Gen).
07_Multithreading_Concurrency

Module 7: Multithreading and Concurrency

Multithreading is a Java feature that allows concurrent execution of two or more parts of a program for
maximum utilization of CPU.

1. Thread Creation
Java provides three primary mechanisms for defining and running concurrent threads:

1. Extending the Thread Class

Override the run() method. Invoke execution via .start() .

class MyThread extends Thread {


public void run() {
[Link]("Thread running: " + [Link]().getName());
}
}
// Execution: new MyThread().start();

2. Implementing the Runnable Interface

Define task logic by implementing Runnable . Exposes better design practices (allows subclassing other
classes).

class MyRunnable implements Runnable {


public void run() {
[Link]("Runnable running: " +
[Link]().getName());
}
}
// Execution: new Thread(new MyRunnable()).start();

3. Implementing the Callable Interface (Java 5+)

Similar to Runnable , but can return a value and throw checked exceptions. It returns a Future
object to inspect results.

import [Link];
import [Link];
class MyCallable implements Callable<Integer> {
public Integer call() throws Exception {
return 42; // Returns value
}
}
// Execution:
// FutureTask<Integer> task = new FutureTask<>(new MyCallable());
// new Thread(task).start();
// int result = [Link](); // Blocks until result is ready

2. Thread Lifecycle (States)

A thread can exist in one of six states, defined by the [Link] enum:

[ NEW ] --(start)--> [ RUNNABLE ] <===============> [ BLOCKED ]


| \ (Waiting for Lock)
| \--(wait/join)--> [ WAITING ]
| --(sleep/join)--> [ TIMED_WAITING ]
v
[ TERMINATED ]

1. NEW: Thread created but not yet started (before start() ).

2. RUNNABLE: Thread is running or ready to run in JVM (waiting for CPU allocation).
3. BLOCKED: Thread is waiting to acquire a monitor lock to enter a synchronized block/method.

4. WAITING: Thread is waiting indefinitely for another thread to perform a specific action (e.g.,
[Link]() , [Link]() ).

5. TIMED_WAITING: Thread is waiting for a specified time (e.g., [Link](ms) ,


[Link](ms) ).

6. TERMINATED: Thread has completed execution (its run() method completed).

3. Synchronization & Thread Safety

When multiple threads access shared mutable data, a Race Condition can occur, causing corrupted
data. Thread-safety prevents this.

The synchronized Keyword

Guarantees mutual exclusion: only one thread can execute the protected code block at a time.

Instance Synchronized Method: Locks on the calling object instance ( this ).

public synchronized void add(int val) { [Link] += val; }

Static Synchronized Method: Locks on the Class object.


public static synchronized void log(String msg) { ... }

Synchronized Block: Locks on a specific object monitor, allowing smaller critical sections.

public void add(int val) {


synchronized(this) { // Locks on specific monitor
[Link] += val;
}
}

The volatile Keyword

Used to mark a Java variable as "being stored in main memory".

Every read of a volatile variable will be read from the computer's Main Memory, not from the CPU
cache.
Every write to a volatile variable will be written to Main Memory, not just the CPU cache.

It ensures Visibility of variables across threads. It does not solve atomicity (e.g., count++ is not
thread-safe even if count is volatile).

Prevents instruction reordering compiler optimizations.

Explicit Locks ( [Link] )

Introduced in Java 5 to offer more control than standard synchronized blocks.

ReentrantLock :

Features: Allows lock polling ( tryLock() ), interruptible lock waits, and fairness policies
(granting lock to longest-waiting thread).

private final ReentrantLock lock = new ReentrantLock();

public void doWork() {


[Link](); // Explicitly lock
try {
// Critical section
} finally {
[Link](); // Always release lock in finally block to prevent
deadlock
}
}

4. Thread Communication ( wait , notify , notifyAll )

Used to coordinate work between cooperating threads.

These methods belong to the Object class (not Thread ).


Must be invoked inside a synchronized context (the thread must hold the object monitor).

wait() : Causes the current thread to release its monitor lock and go to sleep until another thread
wakes it up.

notify() : Wakes up a single thread waiting on the object's monitor.

notifyAll() : Wakes up all threads waiting on the object's monitor.

// Classic Producer-Consumer Guarded Block Pattern


public class SharedBuffer {
private final Queue<Integer> queue = new LinkedList<>();
private final int CAPACITY = 5;

public synchronized void produce(int item) throws InterruptedException {


while ([Link]() == CAPACITY) { // Check condition in a loop to handle
spurious wakeups
wait(); // Release lock and wait
}
[Link](item);
notifyAll(); // Wake up consuming threads
}

public synchronized int consume() throws InterruptedException {


while ([Link]()) {
wait(); // Release lock and wait
}
int item = [Link]();
notifyAll(); // Wake up producing threads
return item;
}
}

5. Executors Framework and Thread Pools (Java 5+)

Managing thread creation ( new Thread() ) manually is expensive and inefficient. The Executors
Framework separates task submission from execution details.

Executor (Interface)
|
ExecutorService (Interface)
/ \
ThreadPoolExecutor ScheduledThreadPoolExecutor

Types of Thread Pools (via Executors Factory Class)


1. FixedThreadPool :

Creates a pool with a fixed number of threads. Uncompleted tasks queue up in an unbounded
queue ( LinkedBlockingQueue ).

ExecutorService executor = [Link](4);

2. CachedThreadPool :

Creates a thread pool that creates new threads as needed, but will reuse previously constructed
threads when they are available.

Unused threads are terminated after 60 seconds of inactivity. Good for short-lived asynchronous
tasks.

3. SingleThreadExecutor :

Uses a single worker thread to execute tasks sequentially. Ensures execution order.

4. ScheduledThreadPool :

Can schedule commands to run after a given delay, or to execute periodically.

5. WorkStealingPool (Java 8+):

Uses a ForkJoinPool working stealing algorithm. Threads steal pending tasks from other
threads' queues when their own queue is empty.

Submission & Shutdown Methods

execute(Runnable) : Submits a task for execution. Returns nothing.

submit(Runnable) / submit(Callable) : Submits a task and returns a Future reference


representation.
shutdown() : Initiates an orderly shutdown. Existing tasks are completed, but no new tasks are
accepted.
shutdownNow() : Attempts to stop all actively executing tasks and halts processing of waiting tasks.
08_Java8_and_Modern_Java

Module 8: Java 8 Features and Modern Java (9–21)

This module covers the functional programming paradigm introduced in Java 8 and the rapid evolution
of the language up to LTS version 21.

1. Java 8 Features
Released in 2014, Java 8 was a massive shift that introduced functional programming constructs,
improving code conciseness and enabling parallel processing.

Lambda Expressions

Anonymous functions (no name, no return type, no modifiers) that implement functional interface
methods.

Syntax: (parameters) -> { body }

// Traditional
Runnable r1 = new Runnable() {
public void run() { [Link]("Hello"); }
};

// Lambda Expression
Runnable r2 = () -> [Link]("Hello");

Functional Interfaces

An interface that contains exactly one abstract method (SAM). Can contain any number of default and
static methods. Marked with @FunctionalInterface .

Built-in Functional Interfaces ( [Link] )

Predicate<T> : Takes one argument, returns a boolean .

Method: boolean test(T t) (e.g., check if a number is even: num -> num % 2 == 0 ).

Function<T, R> : Takes one argument of type T , returns a result of type R .

Method: R apply(T t) (e.g., string length: str -> [Link]() ).

Consumer<T> : Takes one argument, returns void (consumes data).

Method: void accept(T t) (e.g., print output: s -> [Link](s) ).

Supplier<T> : Takes no arguments, returns a result (supplies data).


Method: T get() (e.g., supply random: () -> [Link]() ).

Method References

A shorthand syntax for Lambdas that call an existing method. Uses the double-colon operator ( :: ).

Static Method Reference: Class::staticMethod (e.g., Integer::parseInt )

Instance Method on Specific Object: instance::instanceMethod (e.g., [Link]::println )

Instance Method on Arbitrary Object: Class::instanceMethod (e.g., String::toUpperCase )

Constructor Reference: Class::new (e.g., ArrayList::new )

2. Stream API

A Stream is a sequence of elements supporting sequential and parallel aggregate operations. It does
not store elements (not a data structure); it conveys elements from a source (collection, array) through a
pipeline of operations.

Source ---> [Intermediate Op (Lazy)] ---> [Intermediate Op (Lazy)] ---> [Terminal


Op]

1. Intermediate Operations (Lazy Evaluation)

These operations return a new Stream and are not executed until a terminal operation is invoked.

filter(Predicate) : Filters elements based on a condition.

map(Function) : Transforms each element.

sorted() : Sorts elements.

distinct() : Removes duplicate elements.

limit(long) / skip(long) : Truncates stream / discards first N elements.


2. Terminal Operations (Trigger Pipeline Execution)

These operations produce a final non-stream result (value, collection, side effect) and close the stream.

collect(Collector) : Gathers elements into a Collection (e.g., [Link]() ).

forEach(Consumer) : Iterates through each element.

reduce(BinaryOperator) : Combines elements to produce a single value (e.g., sum, min, max).

count() : Returns the count of elements.

anyMatch(Predicate) / allMatch(Predicate) : Returns boolean checks.

List<String> names = [Link]("Alice", "Bob", "Charlie", "Alex");

List<String> result = [Link]()


.filter(name -> [Link]("A")) // Intermediate
.map(String::toUpperCase) // Intermediate
.sorted() // Intermediate
.collect([Link]()); // Terminal: ["ALEX", "ALICE"]

3. Optional Class

A container object which may or may not contain a non-null value. It is designed to prevent
NullPointerException (NPE) and clean up null-checking clutter.

Optional<String> optional = [Link](getName());

// Checking presence
if ([Link]()) {
[Link]([Link]());
}

// Fluent handling
String name = [Link]("Default Name"); // Fallback value
String uppercaseName = [Link](String::toUpperCase).orElseThrow(() -> new
RuntimeException("Empty"));

4. Date and Time API (Java 8)

The old [Link] and Calendar classes were thread-unsafe, mutable, and hard to read. Java 8
introduced the thread-safe, immutable [Link] package:

LocalDate : Represents date without time (e.g., 2026-06-16 ).

LocalTime : Represents time without date (e.g., 14:30:15 ).

LocalDateTime : Represents both date and time (e.g., 2026-06-16T14:30:15 ).

Period : Meaures distance between dates in years, months, and days.

Duration : Measures distance between times in seconds, milliseconds, or nanoseconds.

DateTimeFormatter : Formatting and parsing dates (e.g.,


[Link]("dd/MM/yyyy") ).

5. Modern Java Features (Java 9–21)

Local Variable Type Inference ( var ) (Java 10)

Enables type inference for local variables. The compiler infers the type, keeping runtime safety identical.
Cannot be used for instance variables, method parameters, or return types.

var list = new ArrayList<String>(); // Inferred as ArrayList<String>


var stream = [Link](); // Inferred as Stream<String>
Records (Java 14 / LTS 16)

Concise data carrier classes that automatically generate standard boilerplates: immutable fields,
getters, equals() , hashCode() , toString() , and a constructor.

public record UserDto(String username, String email) {}


// That's it! Instantiated as: UserDto u = new UserDto("soham",
"soham@[Link]");
// Getters are: [Link]() and [Link]()

Sealed Classes (Java 15 / LTS 17)

Restricts which subclasses can extend or implement a class/interface.

Must use the sealed keyword and list permitted subclasses using permits .

Subclasses must be marked final , sealed , or non-sealed .

public sealed class Shape permits Circle, Square {}


public final class Circle extends Shape {}
public non-sealed class Square extends Shape {}

Text Blocks (Java 13 / LTS 15)

Multi-line string literals that avoid escape sequences and align indentation automatically.

String json = """


{
"name": "Soham",
"role": "Developer"
}
""";

Switch Expressions & Pattern Matching (Java 14/16/21)

Simplifies switch statements and integrates type checking.

// Pattern Matching for instanceof (Java 16)


if (obj instanceof String s) {
[Link]([Link]()); // 's' is automatically cast and in scope
}

// Switch Pattern Matching (Java 21)


String response = switch (obj) {
case Integer i -> [Link]("Integer value: %d", i);
case String s && [Link]() > 5 -> "Long String";
case String s -> "Short String";
default -> "Unknown Type";
};

Virtual Threads (Java 19 / LTS 21)

Project Loom introduces lightweight, user-space virtual threads that run on top of carrier threads.

Traditional thread: 1 : 1 mapping to OS kernel thread (expensive, max out around thousands).
Virtual thread: M : N mapping. JVM multiplexes millions of virtual threads on a small pool of carrier
kernel threads.

Ideal for high-throughput, I/O-bound applications (like web servers).

try (var executor = [Link]()) {


[Link](() -> {
// Blocks on HTTP query without exhausting OS thread resources
});
}

Modules (Java 9 / Project Jigsaw)

A modular system ( [Link] ) grouping packages and resources.

Controls access explicitly: a module must require other modules and export its own packages to
expose classes.

module [Link] {
requires [Link];
exports [Link];
}
09_IO_File_JDBC_Networking

Module 9: Java I/O, File Handling, JDBC, and Networking

This module covers stream communication, file persistence, database connectivity, and socket-based
network programming.

1. Java I/O (Input/Output)


Java I/O uses streams to perform read and write operations. Streams are categorized into Byte
Streams and Character Streams:

Stream
/ \
Byte Stream Character Stream
(8-bit bytes) (16-bit Unicode)
/ \ / \
InputStream OutputStream Reader Writer

1. Byte Streams (Binary Data)

Used to read and write 8-bit bytes of binary data (images, audio, videos, files).

FileInputStream : Reads bytes from a file.

FileOutputStream : Writes bytes to a file.

2. Character Streams (Text Data)

Used to read and write 16-bit Unicode characters. Automatically handles character encoding
translations.

FileReader : Reads characters from a file.

FileWriter : Writes characters to a file.

3. Buffered Streams (Performance Optimization)

Wraps raw streams to read or write data in memory buffer blocks rather than invoking single-byte/char
disk calls, drastically reducing overhead.

BufferedReader / BufferedWriter : Wraps character streams.

BufferedInputStream / BufferedOutputStream : Wraps byte streams.

// Fast Buffered File Reading Pattern


try (BufferedReader br = new BufferedReader(new FileReader("[Link]"))) {
String line;
while ((line = [Link]()) != null) {
[Link](line);
}
} catch (IOException e) {
[Link]();
}

4. Serialization and Deserialization

Serialization: The process of converting an object's state into a byte stream, allowing it to be saved
to a file or sent over a network.
Deserialization: The reverse process of recreating the Java object from the byte stream.

Serializable Interface: A marker interface (no methods) that a class must implement to enable
serialization.
transient Keyword: Applied to variables to exclude them from serialization (e.g., passwords,
temporary cached states).

serialVersionUID : A unique version ID checking compatibility of the compiled class definition


during deserialization. If the class definition changes, deserialization fails.

import [Link];

public class Employee implements Serializable {


private static final long serialVersionUID = 1L; // Version ID

String name;
transient String password; // Excluded from serialization
}

2. File Handling

Java offers the legacy [Link] API and the modern [Link] (New I/O) API (Java 7+):

Legacy [Link]

File file = new File("[Link]");


if ([Link]()) { [Link]("Created"); }
if ([Link]()) { [Link](); }

Modern [Link] (Recommended)

Offers non-blocking operations, symbol link support, and utility classes ( Path , Paths , Files ).

import [Link];
import [Link];
import [Link];

Path path = [Link]("[Link]");

// Write lines to a file


List<String> lines = [Link]("Line 1", "Line 2");
[Link](path, lines);

// Read all lines


List<String> readLines = [Link](path);

// File deletion
[Link](path);

3. JDBC (Java Database Connectivity)

JDBC is a Java API that manages database connections and executes SQL statements.

+-----------------+
| Java Application|
+-----------------+
|
+-----------------+
| JDBC API |
+-----------------+
|
+-----------------+
| Driver Manager |
+-----------------+
|
+-----------------+
| JDBC Driver |
+-----------------+
|
+-----------------+
| Database |
+-----------------+

Core Components

DriverManager : Manages a list of database drivers and establishes connections.

Connection : Represents a session with a specific database. Used to control transactions.

Statement : Used to run static SQL statements. Susceptible to SQL Injection attacks because
parameters are concatenated into raw strings.
PreparedStatement : Compiles the SQL query first. Uses placeholder parameters ( ? ). Prevents
SQL Injection, improves performance due to pre-compilation, and is clean.
ResultSet : A cursor representing a database result set table. Iterated using .next() .

JDBC CRUD Execution Template (Try-With-Resources)

import [Link].*;

public class JdbcDemo {


private static final String URL = "jdbc:mysql://localhost:3306/mydb";
private static final String USER = "root";
private static final String PASSWORD = "password";

public static void main(String[] args) {


String insertSql = "INSERT INTO users (username, email) VALUES (?, ?)";

// Try-With-Resources automatically closes Connection, PreparedStatement,


and ResultSet
try (Connection conn = [Link](URL, USER, PASSWORD);
PreparedStatement pstmt = [Link](insertSql)) {

// Set bind parameters (1-indexed)


[Link](1, "soham");
[Link](2, "soham@[Link]");

int rowsAffected = [Link]();


[Link]("Inserted: " + rowsAffected + " row(s).");

// Querying
try (Statement stmt = [Link]();
ResultSet rs = [Link]("SELECT * FROM users")) {
while ([Link]()) {
[Link]("User ID: " + [Link]("id") + ", Username:
" + [Link]("username"));
}
}
} catch (SQLException e) {
[Link]();
}
}
}

4. Networking
Networking in Java relies on socket connections in the [Link] package.

Sockets

A socket is an endpoint for communication between two machines.

1. TCP Socket Programming (Connection-Oriented, Reliable)

Uses ServerSocket (for server) and Socket (for clients). Communicates via I/O streams.

// Simple TCP Server


public class TcpServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8080);
[Link]("Server listening on port 8080...");

try (Socket clientSocket = [Link](); // Blocks until client


connects
BufferedReader in = new BufferedReader(new
InputStreamReader([Link]()));
PrintWriter out = new PrintWriter([Link](),
true)) {

String message = [Link]();


[Link]("Client sent: " + message);
[Link]("Echo: " + message);
}
}
}

// Simple TCP Client


public class TcpClient {
public static void main(String[] args) throws IOException {
try (Socket socket = new Socket("localhost", 8080);
PrintWriter out = new PrintWriter([Link](), true);
BufferedReader in = new BufferedReader(new
InputStreamReader([Link]()))) {

[Link]("Hello Server!");
[Link]("Server responded: " + [Link]());
}
}
}

2. UDP Socket Programming (Connectionless, Faster but Unreliable)


Uses DatagramSocket and DatagramPacket to send independent packets of bytes. No dedicated
connection stream is established.

// Send UDP Packet


DatagramSocket socket = new DatagramSocket();
byte[] buffer = "UDP Message".getBytes();
InetAddress address = [Link]("localhost");
DatagramPacket packet = new DatagramPacket(buffer, [Link], address, 9090);
[Link](packet);
[Link]();
10_Design_Patterns_and_DSA

Module 10: Advanced Java Topics (Reflection, Annotations,


Design Patterns, & DSA)

This module covers Runtime Reflection, Custom Meta-programming annotations, core Software Design
Patterns, and Java-specific implementations of major Data Structures and Algorithms.

1. Reflection API

Reflection is an API that allows inspecting and modifying the runtime behavior of applications. You can
inspect classes, interfaces, fields, methods, and constructors at runtime, even if they are declared
private .

Key Classes

[Link] : Represents classes and interfaces. Entry point for reflection.

[Link] : Provides metadata and dynamic access to a class field.

[Link] : Provides metadata and dynamic invocation of a method.

[Link] : Provides information about and dynamic access to constructors.

Example: Dynamic Inspection and Private Field Modification

import [Link].*;

public class ReflectionDemo {


public static void main(String[] args) throws Exception {
// Obtain Class reference
Class<?> clazz = [Link]("[Link]");

// Dynamic Object Creation


Constructor<?> constructor = [Link]([Link]);
Object personInstance = [Link]("Soham");

// Inspecting private field


Field privateField = [Link]("secretKey");
[Link](true); // Bypasses access modifiers (security
manager alert)

// Reading value
String keyVal = (String) [Link](personInstance);
[Link]("Read private field: " + keyVal);

// Modifying value
[Link](personInstance, "NEW_SECRET_KEY");
}
}

2. Annotations

Annotations are metadata added to code that do not change execution directly but can be read by
compiler tools, runtime reflection, or build configurations.

Core Built-in Annotations

@Override : Instructs compiler that the annotated method overrides a parent method.

@Deprecated : Marks class/method as obsolete, issuing warnings during compilation.

@SuppressWarnings : Suppresses compiler warnings.

@FunctionalInterface : Restricts interface to a single abstract method.

Custom Annotations & Meta-Annotations

Custom annotations are declared using @interface . Meta-annotations configure their behavior:

@Retention : Defines how long the annotation is retained.

[Link] : Discarded by compiler (e.g., @Override ).

[Link] : Stored in .class file, ignored by JVM at runtime.

[Link] : Kept at runtime, readable by reflection.

@Target : Defines where annotation can be applied (e.g., [Link] , FIELD , TYPE ).

import [Link].*;

@Retention([Link]) // Readable at runtime


@Target([Link]) // Can only annotate methods
public @interface ExecutionTimer {
String value() default "MethodTimer"; // Attribute with default value
}

3. Design Patterns

Design patterns are reusable, templated solutions to common software design problems.

1. Creational Patterns (Object Creation)

Singleton Pattern (Thread-safe Double-Checked Locking)


Ensures a class has only one instance and provides a global point of access.

public class DatabaseConnection {


// Volatile prevents half-initialized object publishing (out-of-order
execution)
private static volatile DatabaseConnection instance;

private DatabaseConnection() {} // Private constructor prevents instantiation

public static DatabaseConnection getInstance() {


if (instance == null) { // First check (no synchronization)
synchronized ([Link]) {
if (instance == null) { // Second check (synchronized)
instance = new DatabaseConnection();
}
}
}
return instance;
}
}

Factory Pattern

Decouples object instantiation logic by letting subclasses choose which class to instantiate.

interface Notification { void notifyUser(); }


class EmailNotification implements Notification { public void notifyUser() { ... }
}
class SmsNotification implements Notification { public void notifyUser() { ... } }

class NotificationFactory {
public static Notification createNotification(String channel) {
return switch (channel) {
case "EMAIL" -> new EmailNotification();
case "SMS" -> new SmsNotification();
default -> throw new IllegalArgumentException("Unknown channel");
};
}
}

Builder Pattern

Constructs complex objects step-by-step, avoiding telescoping constructors.

public class UserProfile {


private final String username; // Required
private final String email; // Optional

private UserProfile(Builder builder) {


[Link] = [Link];
[Link] = [Link];
}

public static class Builder {


private final String username;
private String email;

public Builder(String username) { [Link] = username; }


public Builder email(String email) { [Link] = email; return this; }
public UserProfile build() { return new UserProfile(this); }
}
}
// Usage: UserProfile u = new
[Link]("soham").email("soham@[Link]").build();

2. Structural Patterns (Relationships between objects)

Adapter: Wrapper that allows incompatible interfaces to work together.

Decorator: Attaches additional responsibilities to an object dynamically without modifying original


class (uses composition over inheritance).

3. Behavioral Patterns (Object Communication)

Observer: Subject maintains list of dependents (observers) and notifies them automatically of state
changes (e.g. event listeners).

Strategy: Encapsulates a family of algorithms, making them interchangeable at runtime.

interface PaymentStrategy { void pay(int amount); }


class CreditCardPayment implements PaymentStrategy { ... }
class PayPalPayment implements PaymentStrategy { ... }

class ShoppingCart {
void checkout(int total, PaymentStrategy payment) { [Link](total); }
}

4. Data Structures & Algorithms (DSA) in Java

Implementing custom data structures and algorithm paradigms.

Singly Linked List Implementation


public class SinglyLinkedList {
private Node head;

private static class Node {


int data;
Node next;
Node(int d) { [Link] = d; }
}

public void insertAtEnd(int data) {


Node newNode = new Node(data);
if (head == null) {
head = newNode;
return;
}
Node temp = head;
while ([Link] != null) {
temp = [Link];
}
[Link] = newNode;
}
}

Stack (LIFO - Array Implementation)

public class CustomStack {


private final int[] arr;
private int top;
private final int capacity;

public CustomStack(int size) {


arr = new int[size];
capacity = size;
top = -1;
}

public void push(int x) {


if (top == capacity - 1) throw new StackOverflowError("Stack Full");
arr[++top] = x;
}

public int pop() {


if (top == -1) throw new RuntimeException("Stack Empty");
return arr[top--];
}
}

Binary Search Tree (BST)

public class BinarySearchTree {


private TreeNode root;

private static class TreeNode {


int val;
TreeNode left, right;
TreeNode(int val) { [Link] = val; }
}

public void insert(int val) {


root = insertRec(root, val);
}

private TreeNode insertRec(TreeNode root, int val) {


if (root == null) {
return new TreeNode(val);
}
if (val < [Link]) [Link] = insertRec([Link], val);
else if (val > [Link]) [Link] = insertRec([Link], val);
return root;
}
}

Graph Representation (Adjacency List)

import [Link].*;

public class Graph {


private final Map<Integer, List<Integer>> adjList = new HashMap<>();

public void addVertex(int vertex) {


[Link](vertex, new ArrayList<>());
}

public void addEdge(int source, int destination) {


[Link](source).add(destination); // Directed edge
}

// Depth-First Search (DFS)


public void dfs(int start, Set<Integer> visited) {
[Link](start);
[Link](start + " ");
for (int neighbor : [Link](start, [Link]())) {
if (![Link](neighbor)) {
dfs(neighbor, visited);
}
}
}
}

5. Essential Sorting and Searching Implementations

Merge Sort (Divide & Conquer) - O(N log N )

public class MergeSort {


public void sort(int[] arr, int l, int r) {
if (l < r) {
int m = l + (r - l) / 2;
sort(arr, l, m);
sort(arr, m + 1, r);
merge(arr, l, m, r);
}
}

private void merge(int[] arr, int l, int m, int r) {


int n1 = m - l + 1;
int n2 = r - m;

int[] L = new int[n1];


int[] R = new int[n2];

[Link](arr, l, L, 0, n1);
[Link](arr, m + 1, R, 0, n2);

int i = 0, j = 0, k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) arr[k++] = L[i++];
else arr[k++] = R[j++];
}
while (i < n1) arr[k++] = L[i++];
while (j < n2) arr[k++] = R[j++];
}
}

You might also like