☕ Java Mastery Guide — Core Java from Basic to Advanced Page 1
☕
JAVA MASTERY GUIDE
From Zero to Interview God
Core Java · Java 8+ · Modern Java 9–21 · Concurrency · Interview Prep
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 2
📖 How to Use This Guide
This guide is structured so you build knowledge layer by layer — fundamentals first, then production
patterns, then modern Java. Every section ends with interview questions that top product companies
(Google, Amazon, Meta, Flipkart, Atlassian, etc.) have asked.
• Read sequentially on your first pass
• Return to specific sections during revision
• Every code block is production-ready and copy-pasteable
• Interview Q&A boxes at the end of each section
🚫 Spring, Spring Boot, Spring MVC, Hibernate — only Core Java in this guide.
EXCLUDE
D
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 3
SECTION 1 — JVM, JDK & JRE
1. JVM, JDK & JRE — The Java Platform
1.1 The Holy Trinity
JDK (Java Development Kit) = JRE + compiler (javac) + dev tools. Use this to write and compile Java.
JRE (Java Runtime Environment) = JVM + standard libraries. Use this to run Java programs.
JVM (Java Virtual Machine) = The engine that executes bytecode. Platform-specific but bytecode is
platform-independent — this is Java's 'Write Once, Run Anywhere' promise.
1.2 JVM Architecture (What every senior dev must know)
JVM Architecture
─────────────────────────────────────────────────────
Source (.java) → javac → Bytecode (.class) → JVM
Inside the JVM:
┌─────────────────────────────────────────────────┐
│ Class Loader Subsystem │
│ (Loading → Linking → Initialization) │
├─────────────────────────────────────────────────┤
│ Runtime Data Areas │
│ ┌──────────┐ ┌──────────┐ ┌────────────────┐ │
│ │ Heap │ │ Stack │ │ Method Area │ │
│ │(objects) │ │(frames) │ │(class meta) │ │
│ └──────────┘ └──────────┘ └────────────────┘ │
│ ┌─────────────────┐ ┌──────────────────────┐ │
│ │ PC Registers │ │ Native Method Stack │ │
│ └─────────────────┘ └──────────────────────┘ │
├─────────────────────────────────────────────────┤
│ Execution Engine │
│ Interpreter → JIT Compiler → Garbage Collector│
└─────────────────────────────────────────────────┘
Heap Memory Breakdown
Heap (where all objects live)
┌─────────────────────────────────────────────┐
│ Young Generation │
│ ┌──────────┐ ┌────────────────────────┐ │
│ │ Eden │ │ Survivor (S0 + S1) │ │
│ └──────────┘ └────────────────────────┘ │
├─────────────────────────────────────────────┤
│ Old Generation (Tenured) │
│ Long-lived objects promoted here │
└─────────────────────────────────────────────┘
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 4
Stack: Each thread has its own stack of frames
Each frame holds local vars + operand stack
Metaspace (Java 8+): Replaced PermGen, stores class metadata
1.3 Class Loading
// Three class loaders (parent delegation model)
Bootstrap ClassLoader → [Link] / JDK classes
└── Extension ClassLoader → ext/*.jar
└── Application ClassLoader → your classpath
// Parent Delegation: child asks parent first, loads only if parent can't
// This prevents your String class from overriding [Link]
1.4 JIT Compilation
The JVM starts interpreting bytecode (slow but quick startup), then the JIT (Just-In-Time) compiler
identifies 'hot' code (called frequently) and compiles it to native machine code — giving near-native
performance over time.
Q: What is the difference between JVM, JDK, and JRE?
A: JDK is the full development kit with compiler and tools. JRE is the runtime environment with JVM and libraries.
JVM is the virtual machine that executes bytecode. You code with JDK, distribute with JRE, execute with JVM.
Q: What is the difference between Stack and Heap memory?
A: Stack stores method call frames, local primitives, and object references — it's LIFO and thread-safe (each
thread has its own). Heap stores actual objects and is shared across threads, managed by GC. Stack overflow =
too many recursive calls. OutOfMemoryError = heap exhausted.
Q: What is PermGen vs Metaspace?
A: Before Java 8, class metadata was in PermGen (fixed size, caused OutOfMemoryError). Java 8 replaced it
with Metaspace which lives in native memory and grows dynamically. You can still cap it with -
XX:MaxMetaspaceSize.
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 5
SECTION 2 — Data Types, Variables &
Operators
2. Data Types & Variables
2.1 Primitive Data Types
// 8 Primitive types — stored in Stack (value directly)
byte b = 127; // 8-bit, -128 to 127
short s = 32000; // 16-bit
int i = 2_000_000; // 32-bit (default integer literal)
long l = 9_000_000_000L; // 64-bit (note: L suffix)
float f = 3.14f; // 32-bit float (note: f suffix)
double d = 3.14159265; // 64-bit (default decimal literal)
char c = 'A'; // 16-bit Unicode character
boolean flag = true; // true or false (size not specified by JVM)
// Underscores in literals (Java 7+) — makes big numbers readable
int million = 1_000_000;
long creditCard = 1234_5678_9012_3456L;
2.2 Type Casting
// Widening (implicit, safe — no data loss)
int x = 100;
long y = x; // int → long (automatic)
double z = x; // int → double (automatic)
// Narrowing (explicit, may lose data)
double d = 9.99;
int i = (int) d; // i = 9 (truncates, NOT rounds!)
// Tricky: char ↔ int
char ch = 'A';
int ascii = ch; // 65
char back = (char) 66; // 'B'
2.3 Wrapper Classes & Autoboxing
// Every primitive has a Wrapper class (for use in Collections)
int → Integer
double → Double
boolean → Boolean ... etc.
// Autoboxing: primitive → wrapper (automatic)
Integer obj = 42; // compiler does: [Link](42)
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 6
// Unboxing: wrapper → primitive (automatic)
int val = obj; // compiler does: [Link]()
// GOTCHA: Integer cache (-128 to 127)
Integer a = 127;
Integer b = 127;
[Link](a == b); // true (same cached object)
Integer c = 128;
Integer d = 128;
[Link](c == d); // false (different objects!)
[Link]([Link](d)); // true (always use equals for wrappers)
2.4 String — The Most Important Class
// String is IMMUTABLE — every change creates a new object
String s = "Hello";
[Link](" World"); // original s unchanged! Returns new String
// String Pool (interning)
String s1 = "Java"; // stored in pool
String s2 = "Java"; // reuses same pool object
String s3 = new String("Java"); // NEW object in heap (avoids pool)
[Link](s1 == s2); // true (same pool reference)
[Link](s1 == s3); // false (different object)
[Link]([Link](s3)); // true (same content)
// String methods you MUST know
String str = "Hello, World!";
[Link]() // 13
[Link](0) // 'H'
[Link]("World") // 7
[Link](7, 12) // "World"
[Link]() // "hello, world!"
[Link]() // "HELLO, WORLD!"
[Link]() // removes leading/trailing spaces
[Link]() // Java 11+ (handles Unicode whitespace too)
[Link]("World","Java") // "Hello, Java!"
[Link](", ") // ["Hello", "World!"]
[Link]("World") // true
[Link]("Hello") // true
[Link]("!") // true
[Link]() // false
[Link]() // false (Java 11+, checks whitespace too)
[Link](42) // "42" (convert anything to String)
[Link]() // char[]
[Link]("-","a","b","c") // "a-b-c"
" hi ".strip() // "hi" — Java 11+
// [Link] vs printf
String msg = [Link]("Name: %s, Age: %d, Score: %.2f", "Ram", 25, 95.567);
// → "Name: Ram, Age: 25, Score: 95.57"
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 7
2.5 StringBuilder vs StringBuffer
// Use StringBuilder (NOT String) for repeated modifications in loops
// String + String in a loop = O(n²) due to new objects each time
// StringBuilder: NOT thread-safe, FAST — use in single threads
StringBuilder sb = new StringBuilder();
[Link]("Hello");
[Link](", ").append("World");
[Link](5, "!");
[Link](5, 6);
[Link]();
[Link](0, 5, "Hi");
String result = [Link]();
// StringBuffer: thread-safe, SLOWER — use when multiple threads modify
StringBuffer sbuf = new StringBuffer("safe");
// Interview trick:
// String → immutable, thread-safe (but can't modify)
// StringBuilder → mutable, NOT thread-safe, fast
// StringBuffer → mutable, thread-safe, slow (synchronized)
Q: Why is String immutable in Java?
A: Security (can't change class name after class loading), thread safety (safe to share without sync), String pool
optimization (can cache identical strings). Immutability means hashCode can be cached — important since String
is heavily used as HashMap keys.
Q: What is String interning?
A: [Link]() looks up the string pool — if the value exists, returns the pooled reference; otherwise adds it.
Literal strings are automatically interned. new String('abc') is NOT interned unless you call .intern().
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 8
SECTION 3 — Object-Oriented Programming
3. OOP — The Four Pillars
3.1 Encapsulation
Bundling data (fields) and methods together, hiding internals via access modifiers. The goal: control
how data is accessed and mutated.
public class BankAccount {
private double balance; // hidden — outsiders can't touch directly
public double getBalance() { return balance; } // controlled read
public void deposit(double amount) { // controlled write
if (amount <= 0) throw new IllegalArgumentException("Must be > 0");
balance += amount;
}
public void withdraw(double amount) {
if (amount > balance) throw new IllegalStateException("Insufficient
funds");
balance -= amount;
}
}
// Access Modifiers:
// private → only within this class
// default → within same package (no keyword)
// protected → same package + subclasses
// public → everywhere
3.2 Inheritance
public class Animal {
protected String name;
public Animal(String name) { [Link] = name; }
public String sound() { return "..."; }
public String toString() { return name + " says " + sound(); }
}
public class Dog extends Animal {
private String breed;
public Dog(String name, String breed) {
super(name); // must call parent constructor first
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 9
[Link] = breed;
}
@Override
public String sound() { return "Woof!"; } // overrides parent
}
// Java allows only SINGLE inheritance for classes
// But a class can implement MULTIPLE interfaces
Dog d = new Dog("Rex", "Labrador");
[Link](d); // Rex says Woof!
[Link](d instanceof Animal); // true
[Link](d instanceof Dog); // true
3.3 Polymorphism
// Compile-time (Method Overloading) — same name, different params
public class MathUtil {
public int add(int a, int b) { return a + b; }
public double add(double a, double b) { return a + b; }
public int add(int a, int b, int c) { return a + b + c; }
// Return type alone CANNOT differentiate overloads
}
// Runtime (Method Overriding) — subclass provides its own implementation
Animal animal = new Dog("Rex", "Lab"); // parent ref, child object
[Link](); // calls Dog's sound() — decided at RUNTIME
// Classic polymorphism example:
List<Animal> zoo = new ArrayList<>();
[Link](new Dog("Rex", "Lab"));
[Link](new Cat("Whiskers"));
[Link](new Bird("Tweety"));
for (Animal a : zoo) {
[Link]([Link]()); // each calls its OWN sound()
}
3.4 Abstraction
// Abstract Class — can have abstract methods AND concrete methods
public abstract class Shape {
protected String color;
public Shape(String color) { [Link] = color; }
public abstract double area(); // subclass MUST implement
public abstract double perimeter();
public void printInfo() { // concrete — shared behaviour
[Link]("Color: %s, Area: %.2f%n", color, area());
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 10
}
}
public class Circle extends Shape {
private double radius;
public Circle(String color, double radius) {
super(color);
[Link] = radius;
}
@Override public double area() { return [Link] * radius * radius; }
@Override public double perimeter() { return 2 * [Link] * radius; }
}
// Interface — 100% abstract contract (pre Java 8)
// Java 8+: can have default and static methods
public interface Drawable {
void draw(); // abstract (public by default)
default void drawWithBorder() { // Java 8+ default method
[Link]("Drawing border...");
draw();
}
static Drawable noOp() { // Java 8+ static method
return () -> {};
}
}
// Abstract class vs Interface:
// Use abstract class when classes share CODE (common behaviour)
// Use interface when you want to define a CAPABILITY/CONTRACT
// A class can extend ONE abstract class, implement MANY interfaces
3.5 Important OOP Keywords
// this — refers to current object
public class Person {
String name;
Person(String name) {
[Link] = name; // disambiguate field vs param
}
Person() { this("Unknown"); } // this() — calls another constructor
}
// super — refers to parent class
class Child extends Parent {
Child() { super(); } // call parent constructor
void method() { [Link](); } // call parent method
// final — three uses:
final int MAX = 100; // 1. variable: can't reassign (constant)
final class ImmutableClass {} // 2. class: can't be subclassed
final void secureMethod() {} // 3. method: can't be overridden
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 11
// static — belongs to class, not instance
class Counter {
static int count = 0; // shared across all instances
Counter() { count++; }
static int getCount() { return count; } // static method
}
// instanceof — type check (Java 16+: pattern matching)
if (animal instanceof Dog dog) { // Java 16+ pattern matching
[Link](); // no explicit cast needed!
}
Q: What is the difference between abstract class and interface?
A: Abstract class: can have state (fields), constructors, concrete methods, single inheritance. Interface: no state
(constants only), no constructors, all methods public, multiple implementation. From Java 8, interfaces can have
default/static methods. From Java 9, private methods too. Rule of thumb: abstract class for 'is-a' with shared
code; interface for 'can-do' capabilities.
Q: Can you override a static method?
A: No. Static methods belong to the class, not the instance, so they can be hidden (method hiding) but not
overridden. If you define a static method with the same signature in a subclass, calling it on a parent reference
calls the parent's version — no polymorphism.
Q: What is the difference between overloading and overriding?
A: Overloading: same method name, different parameter list, in same or different class — resolved at compile
time (static polymorphism). Overriding: same method name AND parameter list in parent/child — resolved at
runtime (dynamic polymorphism). Overriding requires @Override annotation (best practice), can't reduce visibility,
can't throw broader checked exceptions.
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 12
SECTION 4 — Generics
4. Generics — Type Safety Without Casting
Generics were introduced in Java 5 to catch type errors at compile time instead of runtime. They let you
write one class/method that works for any type.
4.1 Generic Classes
// Without generics — dangerous!
List list = new ArrayList();
[Link]("Hello");
[Link](42); // compiles, but wrong!
String s = (String) [Link](1); // ClassCastException at runtime!
// With generics — safe
List<String> strings = new ArrayList<>();
[Link]("Hello");
// [Link](42); // COMPILE ERROR — caught early!
String s = [Link](0); // no cast needed
// Generic class definition
public class Box<T> { // T is type parameter (convention: T, E, K, V, N)
private T value;
public Box(T value) { [Link] = value; }
public T getValue() { return value; }
public <R> Box<R> map([Link]<T,R> f) {
return new Box<>([Link](value));
}
}
Box<String> strBox = new Box<>("Hello");
Box<Integer> intBox = new Box<>(42);
Box<Double> dblBox = [Link](i -> i * 1.5);
4.2 Generic Methods
// Generic method — type parameter before return type
public static <T extends Comparable<T>> T max(T a, T b) {
return [Link](b) >= 0 ? a : b;
}
[Link](max(3, 7)); // 7
[Link](max("Apple", "Mango")); // Mango
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 13
4.3 Wildcards — The Tricky Part
// ? — unknown type
List<?> list = new ArrayList<String>(); // can hold any typed list
// Upper bound: <? extends T> — read-only safe (producer)
// "This list contains T or subclass of T"
public double sumList(List<? extends Number> nums) {
return [Link]().mapToDouble(Number::doubleValue).sum();
}
sumList([Link](1, 2, 3)); // Integer extends Number ✓
sumList([Link](1.1, 2.2, 3.3)); // Double extends Number ✓
// Lower bound: <? super T> — write-safe (consumer)
// "This list accepts T or superclass of T"
public void addNumbers(List<? super Integer> list) {
[Link](1); [Link](2); // safe to add Integer
}
// PECS rule: Producer → Extends, Consumer → Super
// If you READ from it → use extends
// If you WRITE to it → use super
4.4 Type Erasure
// Generics exist only at COMPILE time — erased at runtime (JVM sees raw types)
List<String> strings = new ArrayList<>();
List<Integer> ints = new ArrayList<>();
[Link]([Link]() == [Link]()); // true!
// Both are just ArrayList at runtime
// Consequence: you can't do:
// new T() // can't instantiate type parameter
// T[] arr = new T[10] // can't create generic array
// if (obj instanceof List<String>) // can't check generic type at runtime
Q: What is PECS?
A: PECS = Producer Extends, Consumer Super. When a collection PRODUCES values (you read from it), use <?
extends T>. When it CONSUMES values (you write to it), use <? super T>. Example: [Link](List<?
super T> dest, List<? extends T> src).
Q: What is type erasure?
A: Java implements generics via type erasure — generic type info is removed at compile time and replaced with
Object (or the bound type). This ensures backward compatibility with pre-Java-5 bytecode. Consequence: you
can't use instanceof with generic types or create generic arrays.
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 14
SECTION 5 — Collections Framework
5. Collections Framework
5.1 Collections Hierarchy
Collection (interface)
├── List (ordered, allows duplicates)
│ ├── ArrayList — dynamic array, O(1) get, O(n) insert/delete
│ ├── LinkedList — doubly linked, O(1) insert/delete ends, O(n) get
│ ├── Vector — like ArrayList but synchronized (legacy, avoid)
│ └── Stack — extends Vector, use Deque instead
├── Set (no duplicates)
│ ├── HashSet — backed by HashMap, O(1) ops, NO order
│ ├── LinkedHashSet — insertion order, O(1) ops
│ └── TreeSet — sorted (natural or Comparator), O(log n) ops
└── Queue/Deque
├── PriorityQueue — min-heap, O(log n) offer/poll
├── ArrayDeque — resizable array deque, faster than LinkedList
└── LinkedList — implements both List and Deque
Map (interface — NOT a Collection)
├── HashMap — O(1) avg, NO order, allows null key/values
├── LinkedHashMap — insertion/access order, O(1)
├── TreeMap — sorted by key, O(log n), no null key
├── Hashtable — synchronized, legacy, avoid
├── ConcurrentHashMap — thread-safe HashMap, segment locking
├── WeakHashMap — keys are weak references (GC can collect)
└── EnumMap — keys must be enum, very fast
5.2 ArrayList — Deep Dive
List<String> list = new ArrayList<>(16); // initial capacity hint
// Core operations
[Link]("Apple"); // append — amortized O(1)
[Link](0, "Banana"); // insert at index — O(n) shift
[Link](1, "Cherry"); // replace
[Link](0); // O(1) random access
[Link]("Cherry"); // removes first occurrence — O(n)
[Link](0); // removes by index — O(n) shift
[Link]("Apple"); // O(n) linear scan
[Link](); // O(1)
// Bulk ops
[Link]([Link]("D", "E", "F"));
[Link](s -> [Link]("A")); // Java 8+
[Link](String::toUpperCase); // Java 8+
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 15
[Link]([Link]()); // Java 8+
// Iterating
for (String s : list) { } // enhanced for (preferred)
[Link]([Link]::println); // Java 8+ forEach
Iterator<String> it = [Link]();
while ([Link]()) {
if ([Link]().isEmpty()) [Link](); // safe removal during iteration
}
// ConcurrentModificationException!
// Never modify list directly inside enhanced for loop
5.3 HashMap — The Most Important Map
Map<String, Integer> scores = new HashMap<>();
// Core ops
[Link]("Alice", 95);
[Link]("Bob", 87);
[Link]("Alice"); // 95
[Link]("Charlie", 0); // 0 (safe!)
[Link]("Alice"); // true
[Link](87); // true
[Link]("Bob");
// Java 8+ Map methods (VERY common in interviews)
[Link]("Dave", 70); // only puts if key absent
[Link]("Alice", 5, Integer::sum); // Alice = 95+5 = 100
[Link]("Alice", (k,v) -> v == null ? 1 : v + 1);
[Link]("Eve", k -> 0); // compute only if missing
[Link]("Alice", (k,v) -> v * 2);
[Link]("Alice", 100);
// Iterating maps
for ([Link]<String, Integer> e : [Link]()) {
[Link]([Link]() + " → " + [Link]());
}
[Link]((k, v) -> [Link](k + ": " + v)); // Java 8+
// How HashMap works internally:
// - array of buckets (default 16, load factor 0.75)
// - [Link]() determines bucket index
// - Java 8+: bucket becomes TreeMap (Red-Black tree) when >8 entries
// - Key MUST implement equals() + hashCode() correctly!
5.4 HashSet, LinkedHashMap, TreeMap
// HashSet — unique elements, O(1)
Set<String> visited = new HashSet<>();
[Link]("A"); [Link]("B"); [Link]("A"); // dup ignored
[Link](); // 2
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 16
// LinkedHashMap — insertion order (useful for LRU cache!)
Map<String, Integer> lru = new LinkedHashMap<>(16, 0.75f, true) {
protected boolean removeEldestEntry([Link] e) {
return size() > 3; // evict when size > 3
}
};
// TreeMap — sorted by key (natural or custom Comparator)
TreeMap<String, Integer> sorted = new TreeMap<>();
[Link]("Banana", 2); [Link]("Apple", 1); [Link]("Cherry", 3);
[Link](); // "Apple"
[Link](); // "Cherry"
[Link]("Cherry"); // everything before Cherry
[Link]("Banana"); // Banana and after
[Link]("Blueberry"); // "Banana" (largest key ≤ "Blueberry")
5.5 Queue & PriorityQueue
// Queue — FIFO
Queue<String> queue = new LinkedList<>();
[Link]("first"); // adds (returns false if full, prefer over add())
[Link](); // view front without removing (null if empty)
[Link](); // remove and return front (null if empty)
// Deque — double-ended queue (stack + queue)
Deque<Integer> deque = new ArrayDeque<>();
[Link](1); [Link](2);
[Link](); [Link]();
[Link](); [Link]();
// Use ArrayDeque as a STACK (faster than Stack class)
[Link](10); // offerFirst
[Link](); // pollFirst
// PriorityQueue — min-heap by default
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
[Link](5); [Link](1); [Link](3);
[Link](); // 1 (smallest!)
// Max-heap
PriorityQueue<Integer> maxHeap = new PriorityQueue<>([Link]());
// Custom priority
PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[0] - b[0]);
// Sort by first element of each int[]
5.6 Comparable vs Comparator
// Comparable — natural ordering (class defines its own order)
// Implement in the class itself
public class Student implements Comparable<Student> {
int age; String name;
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 17
@Override
public int compareTo(Student other) {
return [Link]([Link], [Link]); // natural order by age
// return [Link]([Link]); // alphabetical by name
}
}
[Link](students); // uses compareTo
// Comparator — external ordering (flexible, multiple orderings possible)
Comparator<Student> byName = [Link](s -> [Link]);
Comparator<Student> byAge = [Link](s -> [Link]);
Comparator<Student> complex = Comparator
.comparingInt(Student::getAge) // primary: age
.thenComparing(Student::getName) // secondary: name
.reversed(); // descending
[Link](complex);
[Link]([Link](Student::getName).reversed());
// In interviews: use [Link] for primitives (avoids boxing)
// Return convention: negative = this < other, 0 = equal, positive = this > other
// NEVER use (a - b) for integer comparison — integer overflow risk!
// ALWAYS use [Link](a, b)
5.7 Collections Utility Methods
// [Link]
[Link](list); // sorts in place
[Link](list, comparator);
[Link](list, key); // O(log n), list must be sorted
[Link](list);
[Link](list);
[Link](collection);
[Link](collection);
[Link](list, element); // count occurrences
[Link](5, "X"); // [X, X, X, X, X]
[Link](list); // read-only view
[Link](list); // thread-safe wrapper (prefer
CopyOnWriteArrayList)
// [Link]
[Link](arr);
[Link](arr, 2, 5); // sort subarray [2,5)
[Link](arr, key);
[Link](arr, 0);
[Link](arr, newLength);
[Link](arr, from, to);
[Link](arr1, arr2);
[Link](arr); // "[1, 2, 3]"
[Link](1, 2, 3); // fixed-size List (can't add/remove!)
Q: ArrayList vs LinkedList — when to use which?
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 18
A: ArrayList: O(1) random access, O(n) insert/delete in middle. Good for frequent reads, index-based access.
LinkedList: O(1) insert/delete at known position, O(n) get. Good for frequent add/remove from ends. In practice,
ArrayList is usually faster because of CPU cache locality (contiguous memory) even for 'middle' ops.
Q: How does HashMap handle collisions in Java 8?
A: Before Java 8: linked list in each bucket — O(n) worst case. Java 8+: when a bucket has >8 entries, it converts
to a Red-Black tree — O(log n) worst case. Reverts to linked list when entries drop below 6. The key requirement:
keys must correctly implement hashCode() and equals().
Q: What is fail-fast vs fail-safe iterator?
A: Fail-fast: throws ConcurrentModificationException if collection is modified during iteration (ArrayList, HashMap
iterators). Fail-safe: works on a copy, no exception (CopyOnWriteArrayList, ConcurrentHashMap iterators) but
may not reflect latest changes.
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 19
SECTION 6 — Java 8: Lambdas, Streams &
Functional Interfaces
6. Java 8 — The Most Important Version
Java 8 (2014) was the biggest change to Java since Java 5. It introduced functional programming
capabilities. Mastering Java 8 features is MANDATORY for any Java interview.
6.1 Lambda Expressions
// Lambda = anonymous function = implementation of a functional interface
// Syntax: (parameters) -> expression OR (parameters) -> { block }
// Before lambdas (anonymous inner class — verbose)
Runnable r1 = new Runnable() {
@Override
public void run() { [Link]("Running..."); }
};
// With lambda — clean!
Runnable r2 = () -> [Link]("Running...");
// Examples:
Comparator<String> comp = (a, b) -> [Link](b);
// Multi-line
Comparator<String> comp2 = (a, b) -> {
[Link]("Comparing: " + a + " vs " + b);
return [Link](b);
};
// Lambda captures "effectively final" variables from enclosing scope
String prefix = "Hello, ";
// prefix = "Hi"; // would break lambda below!
Consumer<String> greeter = name -> [Link](prefix + name);
6.2 Functional Interfaces
A functional interface has exactly ONE abstract method. Lambdas implement functional interfaces.
Java provides key built-in ones in [Link]:
// ── [Link] core interfaces ──────────────────────────────
// Function<T, R> — takes T, returns R
Function<String, Integer> strLen = s -> [Link]();
[Link]("Hello"); // 5
// Compose functions:
Function<Integer, Integer> doubleIt = x -> x * 2;
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 20
Function<Integer, Integer> addThree = x -> x + 3;
Function<Integer, Integer> doubleThenAdd = [Link](addThree);
// addThen: doubleIt first, then addThree
// compose: addThree first, then doubleIt
[Link](5); // (5*2)+3 = 13
// Predicate<T> — takes T, returns boolean
Predicate<String> isEmpty = String::isEmpty;
Predicate<Integer> isPositive = n -> n > 0;
Predicate<Integer> isEven = n -> n % 2 == 0;
Predicate<Integer> isEvenPositive = [Link](isPositive);
Predicate<Integer> isEvenOrPos = [Link](isPositive);
Predicate<Integer> isOdd = [Link]();
// Consumer<T> — takes T, returns nothing (side-effect)
Consumer<String> print = [Link]::println;
Consumer<String> log = s -> [Link]("[LOG] " + s);
Consumer<String> printAndLog = [Link](log);
// Supplier<T> — takes nothing, returns T
Supplier<List<String>> listFactory = ArrayList::new;
Supplier<Double> random = Math::random;
// BiFunction<T, U, R> — takes two args, returns R
BiFunction<String, Integer, String> repeat = (s, n) -> [Link](n);
// BiPredicate, BiConsumer — two-arg versions
BiPredicate<String, String> startsWith = String::startsWith;
// UnaryOperator<T> — Function<T, T>
UnaryOperator<String> shout = s -> [Link]() + "!";
// BinaryOperator<T> — BiFunction<T, T, T>
BinaryOperator<Integer> sum = Integer::sum;
// Primitive specializations (avoids boxing overhead)
IntFunction<String> intToStr = Integer::toString;
ToIntFunction<String> strToInt = Integer::parseInt;
IntPredicate isPositiveInt = n -> n > 0;
IntConsumer printInt = [Link]::println;
IntSupplier rand = () -> (int)([Link]() * 100);
6.3 Method References — The :: Operator
Method references are shorthand lambdas. They refer to existing methods by name. Four types:
// Type 1: Static method reference — ClassName::staticMethod
// Lambda: n -> [Link](n)
Function<String, Integer> parser = Integer::parseInt;
Function<String, Integer> parser2 = s -> [Link](s); // same thing
// Type 2: Instance method on a particular instance — instance::method
String prefix = "Hello";
// Lambda: s -> [Link](s)
Predicate<String> startsWithHello = prefix::startsWith;
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 21
// Type 3: Instance method on arbitrary instance of a type —
ClassName::instanceMethod
// Lambda: s -> [Link]()
Function<String, String> upper = String::toUpperCase;
// Lambda: (s1, s2) -> [Link](s2)
Comparator<String> cmp = String::compareTo;
// Type 4: Constructor reference — ClassName::new
// Lambda: () -> new ArrayList<>()
Supplier<List<String>> listFactory = ArrayList::new;
// Lambda: s -> new StringBuilder(s)
Function<String, StringBuilder> sbFactory = StringBuilder::new;
// Real-world examples:
List<String> names = [Link]("Alice", "Bob", "Charlie");
[Link]([Link]::println); // Type 2 instance
[Link]().map(String::length) // Type 3 arbitrary instance
.forEach([Link]::println);
[Link]().sorted(String::compareTo) // Type 3
.collect([Link]());
[Link]().filter(String::isEmpty) // Type 3
.collect([Link]());
6.4 Stream API — Complete Guide
Streams process data in a pipeline: Source → Zero or more Intermediate ops → One Terminal op.
Streams are lazy — intermediate ops don't execute until a terminal op is called.
// ── Creating Streams ─────────────────────────────────────────────
Stream<String> from_list = [Link]();
Stream<String> parallel = [Link]();
Stream<Integer> of_vals = [Link](1, 2, 3, 4, 5);
Stream<String> empty = [Link]();
Stream<Integer> infinite = [Link](0, n -> n + 2); // 0,2,4,6,...
Stream<Double> randoms = [Link](Math::random); // infinite
Stream<Integer> range = [Link](1, 10).boxed(); // 1..10
IntStream chars = "Hello".chars(); // char stream
// ── INTERMEDIATE OPERATIONS (lazy, return Stream) ──────────────────
// filter — keep elements matching predicate
[Link](n -> n % 2 == 0)
// map — transform each element
[Link](String::toUpperCase)
[Link](s -> [Link]())
// flatMap — flatten nested structures (KEY operation!)
// List<List<String>> → Stream<String>
List<List<String>> nested = [Link]([Link]("a","b"), [Link]("c","d"));
[Link]().flatMap(Collection::stream) // [Link]("a","b","c","d")
// distinct — remove duplicates (uses equals/hashCode)
[Link]()
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 22
// sorted — natural or custom order
[Link]()
[Link]([Link]())
[Link]([Link](String::length))
// limit / skip — pagination
[Link](5).limit(10) // page 2 (5 per page)
// peek — debug without breaking chain
[Link](e -> [Link]("Before: " + e))
.filter(n -> n > 5)
.peek(e -> [Link]("After: " + e))
// mapToInt/mapToLong/mapToDouble — avoid boxing for numbers
[Link](String::length) // IntStream (no boxing)
// ── TERMINAL OPERATIONS (eager, trigger the pipeline) ──────────────
// collect — most versatile terminal op
List<String> list = [Link]([Link]());
Set<String> set = [Link]([Link]());
String joined = [Link]([Link](", ", "[", "]"));
Map<Boolean, List<Integer>> partitioned = // even vs odd
[Link]().collect([Link](n -> n % 2 == 0));
Map<String, List<Employee>> byDept =
[Link]().collect([Link](Employee::getDept));
Map<String, Long> countByDept =
[Link]().collect([Link](
Employee::getDept, [Link]()));
Map<String, Double> avgSalaryByDept =
[Link]().collect([Link](
Employee::getDept, [Link](Employee::getSalary)));
// reduce — fold elements into single value
Optional<Integer> sum = [Link](Integer::sum);
int sumWithIdentity = [Link](0, Integer::sum);
int product = [Link](1, (a, b) -> a * b);
// forEach / forEachOrdered
[Link]([Link]::println);
// count
long count = [Link](n -> n > 5).count();
// findFirst / findAny
Optional<String> first = [Link](s -> [Link]("A")).findFirst();
// anyMatch / allMatch / noneMatch
boolean any = [Link](n -> n < 0);
boolean all = [Link](n -> n > 0);
boolean none = [Link](n -> n < 0);
// min / max
Optional<Integer> max = [Link]([Link]());
Optional<String> shortest = [Link]([Link](String::length));
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 23
// toArray
Object[] arr = [Link]();
String[] sarr = [Link](String[]::new);
// IntStream specific
IntStream nums = [Link](1, 2, 3, 4, 5);
[Link](); // 15
[Link](); // OptionalDouble
[Link](); // OptionalInt
[Link](); // OptionalInt
[Link](); // count, sum, min, max, average
6.5 Stream — Complete Real-World Examples
// ── Example 1: Employee data processing ───────────────────────────
record Employee(String name, String dept, double salary) {}
List<Employee> employees = [Link](
new Employee("Alice", "Engineering", 95000),
new Employee("Bob", "Engineering", 85000),
new Employee("Charlie", "Marketing", 70000),
new Employee("Dave", "Marketing", 75000),
new Employee("Eve", "Engineering", 105000)
);
// Top earner per department
[Link]()
.collect([Link](
Employee::dept,
[Link]([Link](Employee::salary))
))
.forEach((dept, emp) ->
[Link](dept + ": " + [Link](Employee::name).orElse("none"))
);
// Average salary > 80k departments
[Link]()
.collect([Link](
Employee::dept, [Link](Employee::salary)))
.entrySet().stream()
.filter(e -> [Link]() > 80000)
.map([Link]::getKey)
.forEach([Link]::println);
// ── Example 2: Flatten and count word frequency ─────────────────────
List<String> sentences = [Link]("hello world", "hello java", "java streams");
Map<String, Long> wordFreq = [Link]()
.flatMap(s -> [Link]([Link](" ")))
.collect([Link](w -> w, [Link]()));
// {hello=2, world=1, java=2, streams=1}
// ── Example 3: Custom collector ─────────────────────────────────────
// Collect to unmodifiable list (Java 10+)
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 24
List<String> immutable = [Link]([Link]());
// Teeing collector (Java 12+) — two collectors in one pass
[Link](
[Link](Employee::salary),
[Link](),
(sum, count) -> sum / count // combine results
);
6.6 Optional — Goodbye NullPointerException
// Optional wraps a value that may or may not be present
// Forces you to handle the null case explicitly
// Creating
Optional<String> present = [Link]("Hello"); // throws if null!
Optional<String> maybe = [Link](name); // safe, may be empty
Optional<String> empty = [Link]();
// Checking
[Link](); // true
[Link](); // false (Java 11+)
// Getting the value
[Link](); // throws NoSuchElementException if empty!
[Link]("default"); // return default if empty
[Link](() -> computeDefault()); // lazy default (only called if empty)
[Link](); // throw NoSuchElementException if empty
[Link](() -> new RuntimeException("Not found"));
// Transforming
Optional<Integer> len = [Link](String::length);
Optional<String> upper = [Link](s -> ![Link]()).map(String::toUpperCase);
Optional<String> flat = [Link](s -> [Link]([Link]())); // avoid
Optional<Optional<T>>
// Consuming
[Link]([Link]::println);
[Link]( // Java 9+
s -> [Link]("Found: " + s),
() -> [Link]("Not found")
);
// In stream (Java 9+)
Optional<String> opt = [Link]("hello");
Stream<String> stream = [Link](); // Stream of 0 or 1 element
// RULES: Never use Optional as a field or parameter — only as return type
// Optional is for return types that may not have a result
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 25
6.7 Default & Static Methods in Interfaces
public interface Validator<T> {
boolean validate(T value); // abstract — must implement
default Validator<T> and(Validator<T> other) { // default method
return value -> [Link](value) && [Link](value);
}
default Validator<T> or(Validator<T> other) {
return value -> [Link](value) || [Link](value);
}
static <T> Validator<T> of(Validator<T> v) { // static factory
return v;
}
}
// Diamond problem resolution: class wins > interface default
// If two interfaces have same default method, class must override it
Q: What is a functional interface? Can you name some?
A: A functional interface has exactly one abstract method (SAM — Single Abstract Method).
@FunctionalInterface annotation is optional but recommended. Built-in ones: Runnable (run), Callable (call),
Function (apply), Predicate (test), Consumer (accept), Supplier (get), Comparator (compare), BiFunction (apply).
Q: What is the difference between map and flatMap in streams?
A: map() transforms each element 1-to-1 (Stream<T> → Stream<R>). flatMap() transforms each element to a
stream and then flattens (Stream<Stream<T>> → Stream<T>). Use flatMap when your mapping function itself
returns a Stream or collection — like splitting sentences into words.
Q: What is lazy evaluation in Streams?
A: Intermediate operations (filter, map, sorted) are lazy — they don't process data until a terminal operation is
invoked. This allows short-circuit optimizations: findFirst() after filter() stops as soon as one match is found, even
for a million-element stream. This makes streams memory-efficient for large/infinite data.
Q: Explain the :: operator with all four types.
A: 1) ClassName::staticMethod → replaces lambda calling static method. 2) instance::method → lambda calling
method on specific captured instance. 3) ClassName::instanceMethod → lambda calling method on the lambda
parameter itself. 4) ClassName::new → constructor reference, replaces new ClassName(args).
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 26
SECTION 7 — Exception Handling
7. Exception Handling
7.1 Exception Hierarchy
Throwable
├── Error — JVM errors, don't catch (OutOfMemoryError,
StackOverflowError)
└── Exception
├── RuntimeException (UNCHECKED — no need to declare/catch)
│ ├── NullPointerException
│ ├── ArrayIndexOutOfBoundsException
│ ├── ClassCastException
│ ├── IllegalArgumentException
│ ├── IllegalStateException
│ ├── ArithmeticException (divide by zero)
│ ├── NumberFormatException
│ ├── UnsupportedOperationException
│ └── ConcurrentModificationException
└── Checked Exceptions (MUST handle or declare with throws)
├── IOException
├── SQLException
├── ClassNotFoundException
└── InterruptedException
7.2 try-catch-finally & try-with-resources
// Basic try-catch-finally
try {
int result = 10 / 0; // throws ArithmeticException
} catch (ArithmeticException e) {
[Link]("Error: " + [Link]());
} catch (RuntimeException e) { // catches parent
[Link]("Runtime error");
} finally {
[Link]("Always runs — cleanup here");
}
// Multi-catch (Java 7+) — handle multiple exceptions same way
try {
// ...
} catch (IOException | SQLException e) {
[Link]("Data error", e);
}
// try-with-resources (Java 7+) — auto-closes AutoCloseable
// closes in REVERSE order of declaration, even if exception occurs
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 27
try (
Connection conn = [Link](url);
PreparedStatement ps = [Link](sql)
) {
ResultSet rs = [Link]();
} catch (SQLException e) {
throw new RuntimeException("DB error", e);
}
// No finally needed! conn and ps closed automatically.
// finally gotcha:
public int test() {
try { return 1; }
finally { return 2; } // finally overrides return! Returns 2!
}
7.3 Custom Exceptions & Best Practices
// Custom exception
public class InsufficientFundsException extends RuntimeException {
private final double amount;
public InsufficientFundsException(double amount) {
super("Insufficient funds: tried to withdraw " + amount);
[Link] = amount;
}
public double getAmount() { return amount; }
}
// Exception chaining — ALWAYS preserve original cause
try {
[Link](entity);
} catch (SQLException e) {
throw new ServiceException("Failed to save entity", e); // wraps original!
}
// Best practices:
// 1. Catch specific, not generic (avoid catch Exception)
// 2. Never swallow exceptions: catch (Exception e) {} // BAD!
// 3. Log OR throw, not both (causes duplicate logs)
// 4. Use unchecked for programming errors, checked for recoverable ops
// 5. Exception message should explain WHAT happened AND HOW to fix
// 6. Don't use exceptions for flow control — expensive!
// 7. Always include original exception in cause chain
Q: Checked vs Unchecked exceptions — when to use which?
A: Checked: when the caller CAN reasonably recover (file not found — user can retry with different path).
Unchecked/RuntimeException: programming errors (NPE, illegal arg) where caller can't do anything useful.
Modern Java practice leans toward unchecked to avoid exception pollution. Libraries like Spring only throw
unchecked.
Q: What happens if exception occurs in finally block?
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 28
A: The finally exception suppresses the original exception. The original exception is lost! In try-with-resources, the
close() exception is suppressed (accessible via getSuppressed()) and the try exception propagates — much
better behavior.
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 29
SECTION 8 — Multithreading & Concurrency
8. Multithreading & Concurrency
8.1 Creating Threads
// Method 1: Extend Thread (NOT preferred — ties you to Thread)
class MyThread extends Thread {
@Override
public void run() { [Link]("Thread: " + getName()); }
}
new MyThread().start(); // start() creates new thread; run() just runs in current
// Method 2: Implement Runnable (preferred for tasks without result)
Runnable task = () -> [Link]("Runnable thread: " +
[Link]().getName());
new Thread(task).start();
// Method 3: Callable + Future (preferred for tasks WITH result)
Callable<Integer> callable = () -> {
[Link](1000);
return 42;
};
ExecutorService executor = [Link](4);
Future<Integer> future = [Link](callable);
Integer result = [Link](); // blocks until done
[Link](2, [Link]); // with timeout
8.2 Thread Lifecycle
NEW → RUNNABLE → RUNNING → BLOCKED/WAITING/TIMED_WAITING → TERMINATED
NEW: Thread created, start() not yet called
RUNNABLE: start() called, waiting for CPU
RUNNING: CPU executing the thread
BLOCKED: Waiting for monitor lock (synchronized)
WAITING: Wait indefinitely: wait(), join(), [Link]()
TIMED_WAITING: Wait with timeout: sleep(ms), wait(ms), join(ms)
TERMINATED: run() completed or exception thrown
8.3 Synchronization & Visibility
// Race condition example
class Counter {
private int count = 0;
public void increment() { count++; } // NOT atomic! read-modify-write
}
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 30
// Multiple threads calling increment() → data corruption
// Solution 1: synchronized method
class SafeCounter {
private int count = 0;
public synchronized void increment() { count++; }
public synchronized int getCount() { return count; }
}
// Solution 2: synchronized block (finer control)
class FinerCounter {
private int count = 0;
private final Object lock = new Object(); // explicit lock object
public void increment() {
synchronized (lock) { count++; }
}
}
// volatile — ensures visibility (NOT atomicity!)
// Changes are immediately visible to all threads
private volatile boolean running = true;
// Use volatile when: one thread writes, others only read
// NOT sufficient for count++ (that's read-modify-write = 3 ops)
// AtomicInteger — lock-free atomic operations (preferred for counters)
import [Link].*;
AtomicInteger atomicCount = new AtomicInteger(0);
[Link](); // atomic, no sync needed
[Link](expected, newValue); // CAS operation
AtomicReference<String> atomicRef = new AtomicReference<>("initial");
AtomicBoolean atomicBool = new AtomicBoolean(false);
8.4 Executor Framework (Production Way)
// Never create raw threads in production — use Executor framework
ExecutorService pool = [Link](
[Link]().availableProcessors()
);
// Submit tasks
[Link](runnable); // fire and forget
Future<String> f = [Link](callable); // get result later
// Proper shutdown
[Link](); // no new tasks, finish existing
[Link](30, [Link]);
// or
[Link](); // interrupt running tasks
// Types of thread pools
[Link](n); // fixed n threads, unbounded queue
[Link](); // grows/shrinks as needed (careful in
prod!)
[Link](); // 1 thread, sequential execution
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 31
[Link](n); // for scheduled/delayed tasks
// ScheduledExecutorService
ScheduledExecutorService scheduler = [Link](2);
[Link](task, 5, [Link]); // once after 5s
[Link](task, 0, 1, [Link]); // every 1s
[Link](task, 0, 1, [Link]); // 1s after last
finishes
// Custom ThreadPoolExecutor (production configuration)
ThreadPoolExecutor executor = new ThreadPoolExecutor(
4, // corePoolSize
8, // maximumPoolSize
60, [Link], // keepAliveTime
new LinkedBlockingQueue<>(100), // bounded work queue
new ThreadFactory() { ... }, // custom thread naming
new [Link]() // rejection policy
);
8.5 CompletableFuture — Async Programming
// CompletableFuture = Future + callbacks + composition
// Running async (default: [Link]())
CompletableFuture<String> cf = [Link](() -> {
// some long-running computation
return fetchDataFromDB();
});
// Chaining (non-blocking transformations)
CompletableFuture<Integer> result = cf
.thenApply(String::length) // transform result
.thenApply(n -> n * 2);
// Side effects (no transformation)
[Link](data -> [Link]("Got: " + data));
[Link](() -> [Link]("Done!"));
// Combining two futures
CompletableFuture<String> future1 = [Link](() -> "Hello");
CompletableFuture<String> future2 = [Link](() -> "World");
[Link](future2, (a, b) -> a + " " + b)
.thenAccept([Link]::println); // "Hello World"
// Wait for all / any
[Link](future1, future2).thenRun(() -> [Link]("All
done"));
[Link](future1, future2).thenAccept(first ->
[Link](first));
// Exception handling
[Link](ex -> "default value on error")
.handle((result, ex) -> ex != null ? "error" : result); // handle both cases
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 32
// Using custom executor
[Link](() -> heavyOp(), myThreadPool);
// Async variants: thenApplyAsync, thenAcceptAsync — run callback in different
thread
8.6 Locks & Advanced Synchronization
// ReentrantLock — more flexible than synchronized
ReentrantLock lock = new ReentrantLock();
[Link]();
try {
// critical section
} finally {
[Link](); // ALWAYS in finally!
}
// tryLock — don't block indefinitely
if ([Link](1, [Link])) {
try { /* ... */ } finally { [Link](); }
} else {
[Link]("Could not acquire lock");
}
// ReadWriteLock — many readers OR one writer
ReadWriteLock rwLock = new ReentrantReadWriteLock();
// Multiple threads can read simultaneously:
[Link]().lock();
try { return data; } finally { [Link]().unlock(); }
// Only one thread can write:
[Link]().lock();
try { data = newValue; } finally { [Link]().unlock(); }
// Semaphore — control concurrent access count
Semaphore semaphore = new Semaphore(3); // max 3 concurrent
[Link]();
try { accessResource(); } finally { [Link](); }
// CountDownLatch — wait for N events to complete
CountDownLatch latch = new CountDownLatch(3);
// In each of 3 threads: [Link]();
[Link](); // blocks until count reaches 0
// CyclicBarrier — wait for N threads to reach same point (reusable)
CyclicBarrier barrier = new CyclicBarrier(3, () -> [Link]("All
arrived!"));
// In each thread: [Link](); // waits until 3 threads arrive
8.7 Concurrent Collections
// Thread-safe collections — prefer over synchronized wrappers
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 33
// ConcurrentHashMap — segment-level locking, high throughput
// In Java 8+: CAS-based (even more efficient)
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
[Link]("key", 1);
[Link]("key", k -> expensiveCompute(k));
// CopyOnWriteArrayList — copy on every write (read-heavy use cases)
// Reads are lock-free; writes create a new copy of the array
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
// Good for: event listeners, config that rarely changes
// BlockingQueue — producer-consumer pattern
BlockingQueue<Task> queue = new LinkedBlockingQueue<>(100);
// Producer:
[Link](task); // blocks if full
[Link](task, 1, [Link]); // timeout
// Consumer:
Task t = [Link](); // blocks if empty
[Link](1, [Link]); // timeout
// Deadlock prevention:
// 1. Always acquire locks in same order
// 2. Use tryLock with timeout
// 3. Minimize synchronized scope
// 4. Prefer higher-level abstractions (ConcurrentHashMap, BlockingQueue)
Q: What is the difference between synchronized and ReentrantLock?
A: synchronized: built into language, simpler, auto-releases on exception. ReentrantLock: tryLock() (non-blocking
acquire), lockInterruptibly(), fairness policy (longest-waiting thread gets lock), multiple conditions per lock, explicit
lock/unlock. ReentrantLock is more flexible; synchronized is simpler and usually sufficient.
Q: What is the happens-before relationship?
A: Happens-before guarantees memory visibility between threads. If A happens-before B, all memory writes in A
are visible to B. Key relationships: unlock happens-before subsequent lock of same monitor; volatile write
happens-before subsequent read; [Link]() happens-before run(); run() completion happens-before join()
return.
Q: What is thread starvation and livelock?
A: Starvation: a thread can't get CPU because others always get priority. Livelock: threads are active but keep
responding to each other and making no progress (like two people in a hallway both stepping aside for each other
indefinitely). Deadlock: circular wait where none can proceed.
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 34
SECTION 9 — Modern Java: Java 9 → Java 21
9. Modern Java Features (9 through 21)
9.1 Java 9 — Modules & Small Improvements
// Module system (Project Jigsaw) — optional but good to know
// [Link]
module [Link] {
requires [Link]; // depends on HTTP module
requires [Link]; // depends on your module
exports [Link]; // expose only this package
}
// Useful small additions:
// Stream: takeWhile, dropWhile, iterate with predicate
[Link](1, n -> n < 100, n -> n * 2) // 1,2,4,8,16...32,64
[Link](1,2,3,null,4).takeWhile(n -> n != null) // [1,2,3]
// Optional: ifPresentOrElse, stream(), or()
[Link](() -> [Link]("fallback")); // Java 9+
[Link]().flatMap(...); // Java 9+
// Collection factory methods (immutable!)
List<String> names = [Link]("Alice", "Bob", "Charlie"); // unmodifiable!
Set<Integer> ids = [Link](1, 2, 3);
Map<String,Integer> scores = [Link]("Alice", 95, "Bob", 87);
Map<String,Integer> map = [Link](
[Link]("Alice", 95),
[Link]("Bob", 87)
);
// Note: [Link]() allows duplicates but [Link]() throws on duplicates
// Note: null values NOT allowed in any of these
9.2 Java 10 — var (Local Variable Type Inference)
// var lets compiler infer type from right-hand side
var list = new ArrayList<String>(); // inferred as ArrayList<String>
var map = new HashMap<String, List<Integer>>();
var sb = new StringBuilder();
// In for loops
for (var entry : [Link]()) { // cleaner!
[Link]([Link]() + ": " + [Link]());
}
// In try-with-resources
try (var conn = [Link](url)) { }
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 35
// RULES for var:
// - Only for LOCAL variables (not fields, params, return types)
// - Must initialize on same line (compiler needs type to infer)
// - Cannot be null without cast
// - Cannot be used with lambda (ambiguous type)
// var x; → compile error (no initializer)
// var x = null; → compile error (can't infer)
// var r = () -> {}; → compile error (ambiguous target type)
9.3 Java 11 — String & HTTP Improvements
// New String methods
" hello ".strip(); // "hello" (Unicode-aware trim)
" ".isBlank(); // true (whitespace only)
"line1
line2
line3".lines() // Stream<String>
.collect([Link]()); // ["line1","line2","line3"]
"ha".repeat(3); // "hahaha"
"Hello".stripLeading(); // trim leading only
"Hello".stripTrailing(); // trim trailing only
// HTTP Client ([Link]) — replaces HttpURLConnection!
HttpClient client = [Link]()
.version([Link].HTTP_2)
.connectTimeout([Link](10))
.build();
HttpRequest request = [Link]()
.uri([Link]("[Link]
.header("Accept", "application/json")
.GET()
.build();
// Synchronous
HttpResponse<String> response = [Link](request,
[Link]());
[Link]([Link]()); // 200
[Link]([Link]()); // JSON string
// Asynchronous
CompletableFuture<HttpResponse<String>> asyncResp =
[Link](request, [Link]());
[Link](HttpResponse::body).thenAccept([Link]::println);
9.4 Java 14/15/16 — Records, Text Blocks, Pattern Matching
// ── Records (Java 14 preview, Java 16 stable) ──────────────────────
// Immutable data carriers — replaces POJO boilerplate
record Point(int x, int y) {} // That's it!
// Compiler generates: constructor, getters (x(), y()), equals, hashCode, toString
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 36
Point p1 = new Point(3, 4);
p1.x(); // 3 (getter is x(), not getX())
p1.y(); // 4
[Link](p1); // Point[x=3, y=4]
[Link](new Point(3, 4)); // true
// Custom records
record Employee(String name, double salary) implements Comparable<Employee> {
// Compact canonical constructor (validation)
Employee {
if (salary < 0) throw new IllegalArgumentException("Negative salary");
name = [Link](); // transform before storing
}
// Custom methods allowed
double annualBonus() { return salary * 0.1; }
@Override
public int compareTo(Employee other) {
return [Link]([Link], [Link]);
}
}
// Records can implement interfaces but NOT extend classes
// Records are implicitly final (can't be subclassed)
// Great for: DTOs, value objects, map keys, stream results
// ── Text Blocks (Java 13 preview, Java 15 stable) ────────────────────
// Multi-line strings without escape hell
String json = """
{
"name": "Alice",
"age": 30,
"active": true
}
""";
String html = """
<html>
<body>
<h1>Hello, %s!</h1>
</body>
</html>
""".formatted("World"); // [Link]() for interpolation
// Incidental whitespace is stripped (based on closing """)
// Trailing spaces removed from each line automatically
// ── Pattern Matching for instanceof (Java 16) ────────────────────────
// Old way:
if (obj instanceof String) {
String s = (String) obj; // redundant cast!
[Link]([Link]());
}
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 37
// New way — binding variable!
if (obj instanceof String s) {
[Link]([Link]()); // s is already String
}
if (obj instanceof String s && [Link]() > 5) { // combine with &&
[Link]("Long string: " + s);
}
9.5 Java 14/17 — Switch Expressions
// Old switch statement (verbose, fall-through bugs)
String result;
switch (day) {
case MONDAY:
case TUESDAY:
result = "Weekday";
break; // forget this → bug!
case SATURDAY:
case SUNDAY:
result = "Weekend";
break;
default:
result = "Unknown";
}
// New switch expression (Java 14+) — no fall-through, returns value!
String result = switch (day) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> "Weekday";
case SATURDAY, SUNDAY -> "Weekend";
};
// With blocks:
int score = switch (grade) {
case 'A' -> 100;
case 'B' -> 80;
case 'C' -> {
[Link]("Average grade");
yield 60; // yield returns value from block
}
default -> 0;
};
// switch with null (Java 21)
String msg = switch (input) {
case null -> "null input";
case "hello" -> "hi!";
default -> "unknown";
};
9.6 Java 17 — Sealed Classes
// Sealed classes restrict which classes can extend them
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 38
// Eliminates "unknown subclass" problem — compiler knows ALL subtypes
public sealed class Shape permits Circle, Rectangle, Triangle {}
public final class Circle extends Shape { double radius; }
public final class Rectangle extends Shape { double width, height; }
public non-sealed class Triangle extends Shape {} // can be further extended
// Combined with pattern matching switch (Java 21):
double area = switch (shape) {
case Circle c -> [Link] * [Link] * [Link];
case Rectangle r -> [Link] * [Link];
case Triangle t -> /* compute */ 0;
// No default needed! Compiler knows all cases.
};
// Sealed interfaces work too:
public sealed interface Result<T> permits Success, Failure {}
record Success<T>(T value) implements Result<T> {}
record Failure<T>(String error) implements Result<T> {}
9.7 Java 21 — Virtual Threads (Project Loom)
// Virtual threads — lightweight threads managed by JVM, not OS
// OS threads: limited (~thousands), expensive
// Virtual threads: millions possible, cheap to create
// Create virtual thread
[Link]().start(() -> [Link]("Virtual!"));
// Virtual thread executor (the main use case)
try (ExecutorService executor = [Link]()) {
[Link](0, 1_000_000).forEach(i ->
[Link](() -> {
[Link]([Link](1)); // blocks virtual thread, not OS
thread
return i;
})
);
} // auto-closes (try-with-resources)
// WHY virtual threads?
// Traditional: 1 task = 1 OS thread → limited to ~1000 concurrent IO
// Virtual: 1 task = 1 virtual thread → millions of concurrent IO ops
// JVM mounts virtual thread on carrier (platform) thread only while it runs
// On blocking IO → unmounted (carrier thread freed for others)
// Virtual threads are great for IO-bound workloads
// NOT for CPU-bound tasks (use parallel streams or ForkJoinPool)
// Structured Concurrency (Java 21 preview)
try (var scope = new [Link]()) {
Future<String> user = [Link](() -> fetchUser(id));
Future<String> order = [Link](() -> fetchOrders(id));
[Link]();
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 39
[Link]();
return new Page([Link](), [Link]());
}
9.8 Java Date/Time API (Java 8)
// [Link] — replaces the terrible Date/Calendar (those are legacy!)
import [Link].*;
import [Link].*;
// Core classes
LocalDate date = [Link](2024, [Link], 15);
LocalTime time = [Link](14, 30, 45);
LocalDateTime dt = [Link](date, time);
ZonedDateTime zdt = [Link]([Link]("Asia/Kolkata"));
Instant now = [Link](); // UTC epoch timestamp
// Creating
LocalDate today = [Link]();
LocalDate tomorrow = [Link](1);
LocalDate nextMonth = [Link](1);
LocalDate birthday = [Link]("1995-06-15");
// Operations
Period period = [Link](birthday, today); // years, months, days
[Link](); // your age!
Duration duration = [Link]([Link](9,0), [Link](17,0));
[Link](); // 8
// Comparing
[Link]([Link]());
[Link]([Link]());
[Link]([Link]());
// Formatting
DateTimeFormatter fmt = [Link]("dd/MM/yyyy HH:mm");
String formatted = [Link](fmt); // "15/01/2024 14:30"
LocalDateTime parsed = [Link]("15/01/2024 14:30", fmt);
// ZoneId — time zones
ZoneId kolkata = [Link]("Asia/Kolkata");
ZoneId utc = [Link]("UTC");
ZonedDateTime kol = [Link](kolkata);
ZonedDateTime utcTime = [Link](utc); // convert zones
// All [Link] objects are IMMUTABLE — operations return new objects
Q: What are the main Java 8 features?
A: Lambda expressions, Stream API, Functional interfaces (Function/Predicate/Consumer/Supplier), Method
references (::), Optional, default/static interface methods, new Date/Time API ([Link]), CompletableFuture
improvements, Collectors.
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 40
Q: What is a Record in Java? When would you use it?
A: Records (Java 16) are immutable data carriers. The compiler auto-generates constructor, accessors, equals,
hashCode, and toString. Use records for DTOs, value objects, response/request objects — anywhere you need a
class just to hold data. Records can't extend classes and are implicitly final. Accessors use field names directly:
point.x() not getX().
Q: What are Virtual Threads (Java 21)?
A: Virtual threads are lightweight JVM-managed threads (not OS threads). You can create millions of them.
They're mounted on platform (OS) threads only while running CPU work — on blocking IO they unmount, freeing
the OS thread. This allows massive concurrency for IO-bound tasks without callbacks or async complexity.
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 41
SECTION 10 — Design Patterns
10. Design Patterns in Java (Production Patterns)
10.1 Singleton — One Instance Only
// Thread-safe Singleton using enum (BEST approach)
public enum DatabaseConnection {
INSTANCE;
private final Connection connection;
DatabaseConnection() { connection = createConnection(); }
public Connection getConnection() { return connection; }
}
[Link]();
// Bill Pugh (Initialization-on-demand) — elegant and thread-safe
public class Config {
private Config() {}
private static class Holder {
static final Config INSTANCE = new Config(); // loaded lazily
}
public static Config getInstance() { return [Link]; }
}
// Double-checked locking — for cases requiring lazy init with parameters
public class Cache {
private static volatile Cache instance; // volatile is CRITICAL
private Cache() {}
public static Cache getInstance() {
if (instance == null) { // first check (no lock)
synchronized ([Link]) {
if (instance == null) { // second check (with lock)
instance = new Cache();
}
}
}
return instance;
}
}
10.2 Builder Pattern
// For objects with many optional parameters
public class HttpRequest {
private final String url;
private final String method;
private final Map<String, String> headers;
private final int timeout;
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 42
private HttpRequest(Builder b) {
[Link] = [Link];
[Link] = [Link];
[Link] = [Link]([Link]);
[Link] = [Link];
}
public static class Builder {
private final String url; // required
private String method = "GET"; // optional with default
private Map<String, String> headers = new HashMap<>();
private int timeout = 30;
public Builder(String url) { [Link] = url; }
public Builder method(String method) { [Link] = method; return
this; }
public Builder header(String k, String v) { [Link](k, v); return this;
}
public Builder timeout(int secs) { [Link] = secs; return this; }
public HttpRequest build() { return new HttpRequest(this); }
}
}
HttpRequest request = new [Link]("[Link]
.method("POST")
.header("Content-Type", "application/json")
.timeout(60)
.build();
10.3 Factory & Abstract Factory
// Factory Method — subclasses decide which class to instantiate
public interface Notification {
void send(String message);
}
public class EmailNotification implements Notification {
public void send(String message) { [Link]("Email: " + message); }
}
public class SMSNotification implements Notification {
public void send(String message) { [Link]("SMS: " + message); }
}
// Factory
public class NotificationFactory {
public static Notification create(String type) {
return switch ([Link]()) {
case "email" -> new EmailNotification();
case "sms" -> new SMSNotification();
default -> throw new IllegalArgumentException("Unknown: " + type);
};
}
}
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 43
Notification n = [Link]("email");
[Link]("Hello!");
10.4 Observer Pattern
// One-to-many dependency: when one changes, all dependents notified
// Used by event systems, reactive programming, message brokers
public interface EventListener<T> {
void onEvent(T event);
}
public class EventBus<T> {
private final List<EventListener<T>> listeners = new CopyOnWriteArrayList<>();
public void subscribe(EventListener<T> listener) { [Link](listener); }
public void unsubscribe(EventListener<T> listener)
{ [Link](listener); }
public void publish(T event) {
[Link](l -> [Link](event));
}
}
EventBus<String> bus = new EventBus<>();
[Link](e -> [Link]("Handler 1: " + e));
[Link](e -> [Link]("Handler 2: " + e));
[Link]("[Link]"); // both handlers called
10.5 Strategy Pattern
// Define a family of algorithms, encapsulate each, make them interchangeable
@FunctionalInterface
public interface SortStrategy {
void sort(int[] array);
}
public class Sorter {
private SortStrategy strategy;
public Sorter(SortStrategy strategy) { [Link] = strategy; }
public void setStrategy(SortStrategy s) { [Link] = s; }
public void sort(int[] array) { [Link](array); }
}
Sorter sorter = new Sorter(Arrays::sort); // use built-in sort
[Link](arr -> bubbleSort(arr)); // switch to bubble sort
// Lambdas make Strategy pattern trivial in Java 8!
10.6 Decorator Pattern
// Adds behavior without subclassing — wraps with same interface
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 44
public interface Coffee {
double cost();
String description();
}
public class SimpleCoffee implements Coffee {
public double cost() { return 1.0; }
public String description() { return "Coffee"; }
}
public class MilkDecorator implements Coffee {
private final Coffee coffee;
MilkDecorator(Coffee c) { [Link] = c; }
public double cost() { return [Link]() + 0.3; }
public String description() { return [Link]() + ", Milk"; }
}
Coffee c = new MilkDecorator(new MilkDecorator(new SimpleCoffee()));
// Same as [Link]: new BufferedReader(new FileReader(file))
Q: Singleton vs Static class — when to use Singleton?
A: Use Singleton when: you need an instance (not class-level), you need to implement an interface, you need
lazy initialization, you need controlled inheritance, you may need to swap the implementation later. Static
methods/classes can't be overridden or injected. Enum-based Singleton is the safest approach (serialization-safe,
reflection-safe).
Q: What is the difference between Factory Method and Abstract Factory?
A: Factory Method: one factory method that subclasses override to create one product. Abstract Factory: creates
families of related products (e.g., WindowsFactory creates WindowsButton + WindowsScrollBar; MacFactory
creates MacButton + MacScrollBar). Abstract Factory is at a higher abstraction level.
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 45
SECTION 11 — Memory Management & GC
11. Memory Management & Garbage Collection
11.1 How GC Works
// GC frees heap memory for unreachable objects
// An object is GC-eligible when no reachable reference points to it
// Minor GC (Young Gen) — frequent, fast
// Major GC (Old Gen) — infrequent, slower (stop-the-world)
// Full GC — both, longest pause
// GC Algorithms:
// Serial GC → single thread, for small apps
// Parallel GC → multi-thread, throughput focus (Java 8 default)
// G1 GC → balanced latency+throughput (Java 9+ default)
// ZGC → near-zero pause (<1ms) (Java 15+ production)
// Shenandoah → concurrent GC, low latency
// Object lifecycle:
new Object() → Eden (Young Gen) → S0/S1 (survive GC) → Old Gen (survive many GCs)
// Object promotion to Old Gen when:
// 1. Survived N minor GCs (default threshold: 15)
// 2. Too large for Eden (directly promoted)
// 3. Survivor space full
11.2 Memory Leaks in Java
// Java CAN have memory leaks — GC only collects UNREACHABLE objects
// Common memory leak patterns:
// 1. Static collection growing indefinitely
static List<Object> cache = new ArrayList<>(); // never cleared = leak
// 2. Listener not unregistered
[Link](this::handler); // if you never unsubscribe
// Fix: unsubscribe when done, use WeakReference
// 3. ThreadLocal not removed
ThreadLocal<MyObj> local = [Link](MyObj::new);
// Fix: [Link]() in finally block
// 4. Unclosed resources
Connection conn = getConnection(); // connection pool exhausted
// Fix: always use try-with-resources
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 46
// WeakHashMap — keys are weak refs (GC can collect them)
// Useful for caches where GC can reclaim entries
Map<Object, Data> cache = new WeakHashMap<>();
// SoftReference — GC collects when memory is low (good for caches)
SoftReference<byte[]> softCache = new SoftReference<>(new byte[1024]);
byte[] data = [Link](); // null if GC collected it
11.3 Performance Best Practices
// 1. StringBuilder over String concatenation in loops
// BAD: O(n²) — creates new String each iteration
String bad = "";
for (int i = 0; i < 1000; i++) bad += i;
// GOOD: O(n)
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) [Link](i);
// 2. Choose right collection
// Need frequent get by index → ArrayList
// Need frequent insert/delete at front → ArrayDeque
// Need key lookup → HashMap (O(1))
// Need sorted keys → TreeMap (O(log n))
// 3. Use primitive streams to avoid boxing
int[] arr = {1,2,3,4,5};
int sum = [Link](arr).sum(); // no boxing
// Not: [Link](arr).mapToObj(...) // unnecessary boxing
// 4. Lazy initialization
class HeavyObject {
private ExpensiveResource resource;
public ExpensiveResource getResource() {
if (resource == null) resource = new ExpensiveResource(); // lazy
return resource;
}
}
// 5. Use [Link]() for repeated string values
// 6. Specify initial capacity for collections
new ArrayList<>(expectedSize);
new HashMap<>(expectedSize, 0.75f);
// 7. Avoid premature optimization — profile first!
// Tools: JProfiler, VisualVM, Java Flight Recorder (JFR)
Q: What is a memory leak in Java and how do you identify it?
A: A memory leak is when objects are no longer needed but still referenced, preventing GC. Common causes:
static collections, unclosed resources, event listeners, ThreadLocal. Identify with: heap dump analysis (jmap -
dump), tools like VisualVM, MAT (Memory Analyzer Tool), Java Flight Recorder. Look for objects with high
instance counts growing over time.
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 47
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 48
SECTION 12 — Advanced Java Topics
12. Advanced Java Topics
12.1 Enum — More Than Constants
// Enums are full-fledged classes
public enum Planet {
MERCURY(3.303e+23, 2.4397e6),
VENUS (4.869e+24, 6.0518e6),
EARTH (5.976e+24, 6.37814e6);
private final double mass;
private final double radius;
Planet(double mass, double radius) {
[Link] = mass;
[Link] = radius;
}
static final double G = 6.67300E-11;
public double surfaceGravity() { return G * mass / (radius * radius); }
public double surfaceWeight(double otherMass) { return otherMass *
surfaceGravity(); }
}
// Enum with abstract method
public enum Operation {
PLUS { public int apply(int x, int y) { return x + y; } },
MINUS { public int apply(int x, int y) { return x - y; } },
TIMES { public int apply(int x, int y) { return x * y; } };
public abstract int apply(int x, int y);
}
[Link](3, 4); // 7
// Enum utilities
[Link]("EARTH"); // get by name
[Link](); // all values as array
[Link](); // "EARTH"
[Link](); // 2 (index)
// EnumSet and EnumMap — extremely efficient
EnumSet<Planet> inner = [Link]([Link], [Link], [Link]);
EnumMap<Planet, String> names = new EnumMap<>([Link]);
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 49
12.2 Annotations
// Built-in annotations
@Override // verify overriding parent method (compile-time check)
@Deprecated // mark as outdated, compiler warns users
@SuppressWarnings("unchecked") // suppress specific compiler warnings
@FunctionalInterface // verify exactly one abstract method
@SafeVarargs // suppress heap pollution warning for varargs
// Custom annotation
@Retention([Link]) // available at runtime via reflection
@Target({[Link], [Link]}) // where it can be applied
public @interface Log {
String level() default "INFO";
String message() default "";
}
// Using it
@Log(level = "DEBUG", message = "Processing payment")
public void processPayment(Payment p) { ... }
// Reading at runtime (annotation processing)
Method method = [Link]("processPayment", [Link]);
Log log = [Link]([Link]);
if (log != null) {
[Link]([Link]() + ": " + [Link]());
}
12.3 Reflection
// Inspect and manipulate classes at runtime
Class<?> clazz = [Link];
// or:
Class<?> clazz2 = [Link]("[Link]");
Class<?> clazz3 = "hello".getClass();
// Inspect
[Link](); // "[Link]"
[Link](); // "String"
[Link](); // all fields (private too)
[Link](); // all methods
[Link]();
// Create instance
Constructor<?> ctor = [Link]([Link]);
Object obj = [Link]("Hello");
// Invoke method
Method method = [Link]("length");
int len = (int) [Link](obj); // 5
// Access private field
Field field = [Link]("value");
[Link](true); // bypass access control
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 50
Object value = [Link](obj);
// Use cases: frameworks (Spring DI), serialization, testing, ORMs
// Performance: reflection is slow (~50-100x slower) — cache Method/Field objects
12.4 Inner Classes
// 1. Static Nested Class — like a top-level class but inside another
class Outer {
private static int x = 10;
static class StaticNested {
void show() { [Link](x); } // can access static members
}
}
[Link] n = new [Link]();
// 2. Inner Class (non-static) — has implicit reference to enclosing instance
class Outer {
private int y = 20;
class Inner {
void show() { [Link](y); } // can access all outer members
}
}
Outer o = new Outer();
[Link] i = [Link] Inner(); // requires outer instance
// 3. Local Class — defined inside a method
void someMethod() {
class Local { void run() {} }
new Local().run();
}
// 4. Anonymous Class — one-time implementation
Runnable r = new Runnable() { // replaced by lambdas in Java 8
@Override public void run() { [Link]("anon"); }
};
// Use lambdas instead for functional interfaces
// WARNING: Non-static inner classes hold reference to outer class
// → can prevent GC of outer class → memory leak risk in long-lived inners
12.5 Serialization
// Serialization: convert object to byte stream (for storage/network)
// Deserialization: byte stream → object
public class Employee implements Serializable {
private static final long serialVersionUID = 1L; // version control
private String name;
private double salary;
private transient String password; // transient: NOT serialized
}
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 51
// Serialize
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("[Link]"))) {
[Link](employee);
}
// Deserialize
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("[Link]"))) {
Employee emp = (Employee) [Link]();
}
// serialVersionUID: if you change the class and someone tries to
// deserialize old data → InvalidClassException if UID doesn't match
// Modern alternative: prefer JSON (Jackson/Gson) or Protobuf
// Java serialization has security risks and is brittle
12.6 equals() and hashCode() — The Contract
// MUST override both together if you override either one
// The contract:
// 1. [Link](o) == true (reflexive)
// 2. [Link](y) == [Link](x) (symmetric)
// 3. If x==y and y==z then x==z (transitive)
// 4. [Link](null) == false (null-safe)
// 5. If [Link](y) then [Link]() == [Link]() (hash contract!)
// (reverse NOT guaranteed: same hashCode != equal)
public class Product {
private final String id;
private final String name;
@Override
public boolean equals(Object o) {
if (this == o) return true; // same reference shortcut
if (!(o instanceof Product p)) return false; // null + type check
return [Link](id, [Link]); // compare fields
}
@Override
public int hashCode() {
return [Link](id); // hash same fields as equals
}
}
// [Link]() is null-safe
// [Link]() is convenient but slightly slower than manual hash
// If only id determines equality, only use id in both equals and hashCode
// NEVER use mutable fields in hashCode if object is used as Map key
// → bucket changes when field changes → key becomes unfindable!
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 52
Q: Why must you override hashCode when you override equals?
A: The HashMap/HashSet contract: equal objects must have the same hashCode. Without overriding hashCode,
two equal objects may end up in different buckets, breaking HashMap. If you override only equals,
[Link](equalObject) returns false even though an equal object is in the set.
Q: What is serialVersionUID and what happens if you don't define it?
A: serialVersionUID is a version identifier for serialized classes. If you don't declare it, Java generates one from
the class structure. If you change the class (add/remove fields) and the computed UID changes, deserializing old
data throws InvalidClassException. Explicitly declaring it lets you maintain backward compatibility deliberately.
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 53
SECTION 13 — Interview Master Cheat Sheet
13. Interview Master Q&A — Top Company Questions
13.1 JVM & Memory
Q: What is the difference between == and equals()?
A: == compares references (memory addresses) for objects, values for primitives. equals() compares logical
content. For String: 'hello' == 'hello' may be true (pool), but new String('hello') == new String('hello') is false.
Always use equals() for object content comparison.
Q: Can we call a non-static method from a static context?
A: No. Static methods don't have access to 'this' — they're called on the class, not an instance. To call a non-
static method, you need an instance: new MyClass().nonStaticMethod().
Q: What is a ClassLoader? What is parent delegation?
A: ClassLoader loads .class files into JVM. Parent delegation: before loading a class, a ClassLoader asks its
parent first. This prevents user-defined [Link] from overriding the real one. Chain: Bootstrap →
Extension → Application ClassLoader.
13.2 Collections & Data Structures
Q: What is the time complexity of HashMap operations?
A: Average O(1) for get, put, remove. Worst case O(n) (all in one bucket, linked list). With Java 8 treeification:
worst case O(log n) when bucket has >8 entries. Rehashing (resize) is O(n) but amortized over many operations.
Q: When would you use LinkedHashMap over HashMap?
A: When you need to maintain insertion order (e.g., LRU cache with accessOrder=true, displaying items in the
order added). LinkedHashMap has slightly higher memory overhead but O(1) operations with preserved order.
Q: How would you implement an LRU Cache in Java?
A: Use LinkedHashMap with accessOrder=true and override removeEldestEntry. Or: ConcurrentHashMap +
doubly-linked list for thread-safe version. LinkedHashMap(capacity, 0.75f, true) moves most-recently-accessed to
end; override removeEldestEntry to evict head when size > capacity.
13.3 Java 8 & Streams
Q: What is the difference between Collection and Stream?
A: Collection stores data (in-memory data structure). Stream processes data (pipeline of operations). Stream is
not a data structure — it doesn't modify the source. Streams are lazy, single-use (can't be reused after terminal
op). Collections can be iterated multiple times.
Q: What is a Spliterator?
A: Spliterator (splittable iterator) is used for traversal and partitioning of a source, primarily for parallel streams.
[Link]() returns one. It can split the source for parallel processing. Unlike Iterator, Spliterator provides
parallel decomposition via trySplit().
Q: How does parallel stream work? When not to use it?
A: Parallel stream splits data and processes chunks on [Link]() threads, then combines
results. DON'T use when: operations have side effects, order matters, stream is small (overhead > gain),
operations involve shared mutable state or blocking IO. USE when: CPU-bound, large data, stateless operations.
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 54
13.4 Concurrency
Q: What is the difference between wait() and sleep()?
A: wait(): Object method, releases monitor lock, must be in synchronized block, woken by notify()/notifyAll().
sleep(): Thread method (static), does NOT release lock, just pauses the thread. Use wait() for inter-thread
communication, sleep() for time-based pauses.
Q: What is CAS (Compare-And-Swap)?
A: CAS is an atomic CPU instruction: compare a memory location to an expected value; if equal, swap with new
value; if not, fail (try again). Java's AtomicInteger, AtomicReference use CAS internally. Lock-free, so no thread
blocking — better throughput than synchronized for low-contention cases.
Q: What is ThreadLocal?
A: ThreadLocal provides thread-local variables — each thread has its own independent copy. Used for: per-
request contexts (user session, transaction ID), SimpleDateFormat (not thread-safe), DB connections. MUST call
remove() in finally to prevent memory leaks in thread pools (threads are reused!).
13.5 Advanced
Q: What is the difference between Comparable and Comparator?
A: Comparable: implemented by the class itself (natural ordering, compareTo method). One per class.
Comparator: external ordering strategy (compare method). Multiple per class. Comparable modifies the class;
Comparator is open-closed. In interviews: Comparable for 'is this type naturally ordered', Comparator for 'sort by
this criterion'.
Q: What is immutability? How do you make a class immutable?
A: Immutable class: once created, state cannot change. Steps: 1) make class final, 2) all fields private final, 3) no
setters, 4) deep-copy mutable objects in constructor, 5) return defensive copies of mutable fields. String, Integer,
LocalDate are immutable. Benefits: thread-safe by nature, safe to share, good for cache keys.
Q: What is the difference between fail-fast and fail-safe iterators?
A: Fail-fast: throws ConcurrentModificationException if collection modified during iteration (ArrayList, HashMap).
Implemented via modCount field. Fail-safe: iterates over a snapshot/copy, no exception (CopyOnWriteArrayList,
ConcurrentHashMap). Fail-safe may not reflect latest changes and has higher memory usage.
13.6 Coding Patterns to Know
// ── Find duplicates in array ────────────────────────────────────
Set<Integer> seen = new HashSet<>();
List<Integer> duplicates = [Link](arr)
.filter(n -> ) // add returns false if already present
.boxed().collect([Link]());
// ── Group anagrams ────────────────────────────────────────────────
Map<String, List<String>> grouped = [Link](words)
.collect([Link](word -> {
char[] chars = [Link]();
[Link](chars);
return new String(chars); // sorted chars as key
}));
// ── Top N elements ────────────────────────────────────────────────
// Min-heap of size N — O(n log k)
PriorityQueue<Integer> topN = new PriorityQueue<>(k); // min-heap
for (int num : nums) {
[Link](num);
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 55
if ([Link]() > k) [Link](); // remove smallest
}
// topN now contains k largest elements
// ── Word frequency map ─────────────────────────────────────────
Map<String, Long> freq = [Link](words)
.collect([Link](w -> w, [Link]()));
// Sort by frequency
[Link]().stream()
.sorted([Link].<String,Long>comparingByValue().reversed())
.limit(10)
.forEach(e -> [Link]([Link]() + ": " + [Link]()));
// ── FlatMap for nested lists ───────────────────────────────────
List<Integer> flat = [Link]()
.flatMap(Collection::stream)
.collect([Link]());
// ── String reversal (interview classic) ───────────────────────
String reversed = new StringBuilder(str).reverse().toString();
// ── Check palindrome ──────────────────────────────────────────
boolean isPalindrome = [Link](0, [Link]() / 2)
.allMatch(i -> [Link](i) == [Link]([Link]() - 1 - i));
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 56
SECTION 14 — Quick Reference Tables
14. Quick Reference — What to Use When
14.1 Collection Cheat Sheet
Collection Order Duplicates Thread-safe Best For
ArrayList Insertion Yes No Random access,
iteration
LinkedList Insertion Yes No Queue/Deque,
insert/delete ends
HashSet None No No Unique check, fast
lookup
LinkedHashSet Insertion No No Unique + preserve
order
TreeSet Sorted No No Sorted unique
elements
HashMap None Keys:No No Key-value, fast
lookup
LinkedHashMap Insertion Keys:No No LRU cache, ordered
map
TreeMap Key sorted Keys:No No Sorted key-value
ConcurrentHashMap None Keys:No Yes Concurrent key-value
PriorityQueue Priority Yes No Min/max heap
ArrayDeque Insertion Yes No Stack or Queue
14.2 Java Version Feature Timeline
Version Key Features
Java 5 Generics, Enums, Autoboxing, varargs, enhanced for, annotations
Java 7 try-with-resources, multi-catch, diamond <>, switch on strings, fork/join
Java 8 ⭐ Lambdas, Streams, Functional interfaces, Optional, Date/Time API, default methods
Java 9 Modules, [Link](), [Link]/dropWhile, private interface methods
Java 10 var (local type inference), toUnmodifiableList()
Java 11 [Link]/isBlank/lines/repeat, HttpClient, [Link]/writeString
Java 14 Switch expressions (stable), Records (preview), NullPointerException messages
Java 15 Text Blocks (stable), Sealed classes (preview)
Java 16 Records (stable), Pattern matching instanceof (stable), [Link]()
Java 17 Sealed classes (stable), Pattern matching switch (preview), RandomGenerators
LTS
☕ Java Mastery Guide — Core Java from Basic to Advanced Page 57
Java 21 Virtual Threads, Structured Concurrency, Pattern matching switch (stable), Sequenced Collections
LTS
14.3 Stream Operations Cheat Sheet
Operation Type Returns Example
filter Intermediate Stream<T> filter(n -> n > 5)
map Intermediate Stream<R> map(String::length)
flatMap Intermediate Stream<R> flatMap(Collection::s
tream)
distinct Intermediate Stream<T> distinct()
sorted Intermediate Stream<T> sorted([Link]
erseOrder())
limit/skip Intermediate Stream<T> skip(5).limit(10)
peek Intermediate Stream<T> peek([Link]::prin
tln)
collect Terminal R collect([Link]
List())
forEach Terminal void forEach([Link]::p
rintln)
count Terminal long count()
reduce Terminal Optional<T> / T reduce(0,
Integer::sum)
findFirst Terminal Optional<T> findFirst()
anyMatch Terminal boolean anyMatch(s ->
[Link]('A'))
min/max Terminal Optional<T> max([Link]
lOrder())
toArray Terminal T[] toArray(String[]::new
)
Understand the WHY behind every concept, not just the HOW. Top product companies
🏆 FINAL ask 'why is HashMap O(1)?' not just 'what does HashMap do?'. For every class you use,
TIP know its internal data structure, time complexity of each operation, and thread-safety
guarantees.
You are now a Java God. Go get that offer. ☕