0% found this document useful (0 votes)
2 views20 pages

Java Complete Notes

The document provides comprehensive notes on Java and concurrent programming, covering fundamental concepts such as JVM, JRE, and JDK, as well as advanced topics like object-oriented programming, exception handling, generics, and collections. It includes explanations of key programming principles including classes, inheritance, polymorphism, and lambda expressions. The notes serve as a complete guide for learners from basic to advanced levels in Java programming.

Uploaded by

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

Java Complete Notes

The document provides comprehensive notes on Java and concurrent programming, covering fundamental concepts such as JVM, JRE, and JDK, as well as advanced topics like object-oriented programming, exception handling, generics, and collections. It includes explanations of key programming principles including classes, inheritance, polymorphism, and lambda expressions. The notes serve as a complete guide for learners from basic to advanced levels in Java programming.

Uploaded by

rohit.rays24
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

Java & Concurrent Programming — Complete Notes

Java & Concurrent Programming


Complete Study Notes — Basic to Advanced
Classes • OOP • Threads • Lambda • Generics • Collections • Streams

Page 1
Java & Concurrent Programming — Complete Notes

SECTION 1 — Java Fundamentals

1. JVM, JRE & JDK


Understanding the Java platform is the first step.

JVM — Java Virtual Machine


The JVM is the engine that executes Java bytecode. It is platform-specific (Windows/Linux/Mac
each have their own JVM) but the bytecode it runs is platform-independent.
Source (.java) → javac compiler → Bytecode (.class) → JVM → OS/Hardware

JRE — Java Runtime Environment


JRE = JVM + standard libraries ([Link], [Link], etc). Needed to RUN Java programs. End-
users install JRE.

JDK — Java Development Kit


JDK = JRE + javac compiler + javadoc + debugger + tools. Needed to WRITE and COMPILE Java
programs. Developers install JDK.
📝 NOTE: Memory trick: JDK ⊃ JRE ⊃ JVM. Each is inside the previous.

2. Data Types
Primitive Types (8 total)
byte b = 100; // 8-bit, -128 to 127
short s = 30000; // 16-bit
int i = 1000000; // 32-bit ← most common
long l = 9999999999L; // 64-bit (needs L suffix)
float f = 3.14f; // 32-bit decimal (needs f)
double d = 3.14159; // 64-bit decimal ← most common
char c = 'A'; // 16-bit Unicode character
boolean flag = true; // true or false only

Reference Types
Everything else — String, arrays, objects. They store a memory address (reference), not the actual
value.
String name = "Alice"; // reference to String object
int[] nums = {1, 2, 3}; // reference to array
💡 TIP: Use double for money calculations (or better: BigDecimal). Never use float for financial
data — it has rounding errors.

Wrapper Classes
Each primitive has an Object version (used in Collections):
int → Integer double → Double
char → Character boolean → Boolean

Integer x = 5; // autoboxing: int → Integer


int y = x; // unboxing: Integer → int

Page 2
Java & Concurrent Programming — Complete Notes

SECTION 2 — Object-Oriented Programming

3. Classes & Objects


A class is a blueprint. An object is a real instance of that blueprint.
class Car {
// Fields (state)
String brand;
int speed;

// Constructor
Car(String brand, int speed) {
[Link] = brand; // 'this' = current object
[Link] = speed;
}

// Method (behaviour)
void drive() {
[Link](brand + " going " + speed + " km/h");
}
}

// Creating objects
Car myCar = new Car("Toyota", 120);
[Link](); // Output: Toyota going 120 km/h

Constructors — Key Rules


• Same name as class, no return type
• Called automatically when 'new' is used
• If you don't write one, Java provides a default empty constructor
• You can have multiple constructors (constructor overloading)
class Box {
int width, height;

Box() { width = 10; height = 10; } // default


Box(int w, int h) { width = w; height = h; } // parameterized
}

this keyword
'this' refers to the current object. Used to distinguish fields from parameters, or to call another
constructor.
class Person {
String name;
Person(String name) {
[Link] = name; // [Link] = field, name = parameter
}
Person() {
this("Unknown"); // calls Person(String) constructor
}
}

Page 3
Java & Concurrent Programming — Complete Notes

4. Access Modifiers
Control who can see your class members:
public → accessible everywhere
private → only inside the same class
protected → same class + subclasses + same package
(default) → only within the same package
class BankAccount {
private double balance; // nobody outside can touch directly

public void deposit(double amount) { // public method = safe gateway


if (amount > 0) balance += amount;
}

public double getBalance() { return balance; }


}
💡 TIP: Always make fields private and provide public getters/setters — this is Encapsulation.

5. Inheritance (extends)
Inheritance lets a child class reuse fields and methods of a parent class. Java supports single
inheritance (one parent only).
class Animal {
String name;
void eat() { [Link](name + " is eating"); }
}

class Dog extends Animal { // Dog inherits from Animal


void bark() { [Link](name + " says Woof!"); }
}

Dog d = new Dog();


[Link] = "Rex";
[Link](); // inherited from Animal
[Link](); // Dog's own method

super keyword
'super' calls parent class methods or constructors.
class Vehicle {
Vehicle(String type) { [Link]("Vehicle: " + type); }
void info() { [Link]("I am a vehicle"); }
}

class Bike extends Vehicle {


Bike() {
super("Bike"); // calls Vehicle(String) constructor FIRST
}
void info() {
[Link](); // calls parent method
[Link]("I am a Bike");
}
}
📝 NOTE: super() must be the FIRST statement inside a constructor if used.

Page 4
Java & Concurrent Programming — Complete Notes

6. Overloading vs Overriding
Method Overloading — Same name, different parameters (same class)
class Calculator {
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; } // overloaded
int add(int a, int b, int c) { return a + b + c;} // overloaded
}
// Java picks the right one based on arguments at COMPILE TIME

Method Overriding — Redefine parent method in child class


class Shape {
void draw() { [Link]("Drawing a shape"); }
}

class Circle extends Shape {


@Override
void draw() { [Link]("Drawing a circle"); } // overrides
}

Shape s = new Circle();


[Link](); // Output: Drawing a circle ← RUNTIME decides (polymorphism)
💡 TIP: Always use @Override annotation — it makes the compiler verify you're actually
overriding, not creating a new method.
Quick Comparison:
Feature | Overloading | Overriding
----------------|----------------------|---------------------------
Where | Same class | Parent → Child
Parameters | Must differ | Must be same
Return type | Can differ | Must be same (or covariant)
Resolved at | Compile time | Runtime
@Override | Not needed | Recommended

7. Abstract Class
An abstract class cannot be instantiated. It can have abstract methods (no body — child MUST
implement) and concrete methods (with body).
abstract class Shape {
String color;

abstract double area(); // no body — subclass must implement

void printColor() { // concrete method — shared by all


[Link]("Color: " + color);
}
}

class Circle extends Shape {


double radius;
Circle(double r) { [Link] = r; }

Page 5
Java & Concurrent Programming — Complete Notes

@Override
double area() { return [Link] * radius * radius; } // must implement
}

// Shape s = new Shape(); // ERROR — cannot instantiate abstract class


Shape c = new Circle(5);
[Link]([Link]()); // 78.53...

8. Interface
An interface is a pure contract — all methods are abstract by default (before Java 8). A class can
implement multiple interfaces.
interface Flyable {
void fly(); // implicitly public abstract
default void land() { // default method (Java 8+)
[Link]("Landing...");
}
}

interface Swimmable {
void swim();
}

class Duck implements Flyable, Swimmable { // multiple interfaces OK


public void fly() { [Link]("Duck flying"); }
public void swim() { [Link]("Duck swimming"); }
}
Abstract Class vs Interface:
Feature | Abstract Class | Interface
-------------------|-------------------------|---------------------------
Instantiate | No | No
Constructor | Yes | No
Fields | Any type | public static final only
Methods | Abstract + concrete | Abstract + default (J8+)
Multiple inherit | No (one class only) | Yes (many interfaces)
Use when | 'IS-A' shared base | 'CAN-DO' capability
📝 NOTE: Rule of thumb: Use interface for behaviours (Runnable, Comparable). Use abstract
class for a common base with shared code.

9. Static Keyword
Static members belong to the CLASS, not to any object. Shared across all instances.
class Counter {
static int count = 0; // shared by ALL Counter objects
int id;

Counter() {
count++; // increments the class-level counter
id = count;
}

Page 6
Java & Concurrent Programming — Complete Notes

static void showCount() { // static method — no 'this'


[Link]("Total: " + count);
}
}

Counter a = new Counter(); // count = 1


Counter b = new Counter(); // count = 2
[Link](); // Output: Total: 2
💡 TIP: Static methods cannot access instance (non-static) fields. If you try, you get a compile
error.

10. final Keyword


// final variable = constant (cannot reassign)
final double PI = 3.14159;
// PI = 3.0; // COMPILE ERROR

// final method = cannot be overridden


class Parent {
final void show() { [Link]("Cannot override this"); }
}

// final class = cannot be extended (e.g., String is final)


final class Immutable { }
// class Child extends Immutable { } // COMPILE ERROR

11. Polymorphism
Poly = many, morph = forms. One reference, many behaviours. Java resolves which method to call
at RUNTIME based on the actual object type.
class Animal {
void sound() { [Link]("Some sound"); }
}
class Cat extends Animal {
void sound() { [Link]("Meow"); }
}
class Dog extends Animal {
void sound() { [Link]("Woof"); }
}

Animal[] animals = { new Cat(), new Dog(), new Cat() };


for (Animal a : animals) {
[Link](); // Meow, Woof, Meow — same call, different outputs
}

instanceof — check type at runtime


Animal a = new Dog();
if (a instanceof Dog) {
Dog d = (Dog) a; // safe cast
[Link]();
}

Page 7
Java & Concurrent Programming — Complete Notes

// Java 16+ pattern matching (cleaner)


if (a instanceof Dog d) {
[Link](); // d is already cast
}

SECTION 3 — Exception Handling

12. Exceptions
An exception is an event that disrupts normal program flow. Java uses try-catch-finally to handle
them.
try {
int result = 10 / 0; // ArithmeticException
String s = null;
[Link](); // NullPointerException
} catch (ArithmeticException e) {
[Link]("Math error: " + [Link]());
} catch (NullPointerException e) {
[Link]("Null ref: " + [Link]());
} catch (Exception e) { // catch-all (must be last)
[Link]("Unexpected: " + [Link]());
} finally {
[Link]("Always runs — cleanup here");
}

Checked vs Unchecked Exceptions


Checked (must handle or declare with throws):
IOException, SQLException, ClassNotFoundException

Unchecked (RuntimeException — optional to handle):


NullPointerException, ArrayIndexOutOfBoundsException,
ClassCastException, ArithmeticException, NumberFormatException

Custom Exception
class InsufficientFundsException extends Exception {
InsufficientFundsException(String msg) { super(msg); }
}

void withdraw(double amount) throws InsufficientFundsException {


if (amount > balance)
throw new InsufficientFundsException("Balance too low!");
balance -= amount;
}

try-with-resources (Java 7+)


Automatically closes resources (files, connections) — no need for finally.
try (FileReader fr = new FileReader("[Link]");
BufferedReader br = new BufferedReader(fr)) {
String line = [Link]();
} catch (IOException e) {
[Link]();
}
// fr and br are automatically closed after try block

Page 8
Java & Concurrent Programming — Complete Notes

SECTION 4 — Generics & Collections

13. Generics
Generics allow you to write code that works with any type, while being type-safe at compile time.
// Generic class
class Box<T> {
T value;
Box(T value) { [Link] = value; }
T get() { return value; }
}

Box<Integer> intBox = new Box<>(42);


Box<String> strBox = new Box<>("Hello");
[Link]([Link]()); // 42

// Generic method
static <T> void printArray(T[] array) {
for (T item : array) [Link](item + " ");
}

Bounded Type Parameters


<T extends Number> // T must be Number or its subclass
<T extends Comparable> // T must implement Comparable

static <T extends Number> double sum(T a, T b) {


return [Link]() + [Link]();
}

14. Collections Framework


List — ordered, allows duplicates
List<String> list = new ArrayList<>();
[Link]("A"); [Link]("B"); [Link]("A");
[Link](0); // "A"
[Link](); // 3
[Link]("A"); // removes first occurrence

LinkedList<Integer> ll = new LinkedList<>(); // doubly-linked, better for


insertions

Set — no duplicates, no index


Set<String> set = new HashSet<>(); // unordered
Set<String> sorted = new TreeSet<>(); // sorted alphabetically
Set<String> linked = new LinkedHashSet<>(); // insertion order preserved

[Link]("x"); [Link]("y"); [Link]("x");


[Link]([Link]()); // 2 (no duplicate 'x')

Page 9
Java & Concurrent Programming — Complete Notes

Map — key-value pairs


Map<String, Integer> map = new HashMap<>();
[Link]("Alice", 90);
[Link]("Bob", 85);
[Link]("Alice"); // 90
[Link]("Bob"); // true
[Link]("X", 0); // 0 (key not found)

for ([Link]<String, Integer> e : [Link]()) {


[Link]([Link]() + " → " + [Link]());
}

Queue & Deque


Queue<Integer> q = new LinkedList<>();
[Link](1); [Link](2); [Link](3);
[Link](); // removes & returns 1 (FIFO)
[Link](); // returns 2 without removing

Deque<Integer> dq = new ArrayDeque<>();


[Link](1); // add to front
[Link](2); // add to back
💡 TIP: ArrayList → fast random access. LinkedList → fast insert/delete at ends. HashMap →
fastest lookup. TreeMap → sorted keys.

SECTION 5 — Lambda & Functional Programming

15. Lambda Expressions (Java 8+)


A lambda is an anonymous function — a compact way to pass behaviour as data. Lambdas
implement functional interfaces (interfaces with exactly 1 abstract method).
// Traditional anonymous class
Runnable r1 = new Runnable() {
public void run() { [Link]("Running"); }
};

// Lambda equivalent (much shorter!)


Runnable r2 = () -> [Link]("Running");

// Syntax: (parameters) -> { body }


// If single expression, no braces needed
(int a, int b) -> a + b
x -> x * x
() -> [Link]("hello")

Common Functional Interfaces ([Link])


// Predicate<T> — takes T, returns boolean
Predicate<Integer> isEven = n -> n % 2 == 0;
[Link](4); // true

// Function<T, R> — takes T, returns R


Function<String, Integer> len = s -> [Link]();
[Link]("Hello"); // 5

// Consumer<T> — takes T, returns nothing

Page 10
Java & Concurrent Programming — Complete Notes

Consumer<String> print = s -> [Link](s);


[Link]("Hi");

// Supplier<T> — takes nothing, returns T


Supplier<Double> random = () -> [Link]();
[Link](); // 0.342...

// BiFunction<T, U, R> — takes T and U, returns R


BiFunction<Integer, Integer, Integer> add = (a, b) -> a + b;
[Link](3, 4); // 7

Method References
// Lambda: s -> [Link](s)
// Method ref: [Link]::println

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


[Link]([Link]::println); // instance method of arg

[Link](String::compareToIgnoreCase); // static method

// Constructor reference
Supplier<ArrayList> newList = ArrayList::new;
ArrayList list = [Link]();

16. Stream API (Java 8+)


Streams let you process collections in a declarative, pipeline style — like SQL for Java objects.
List<Integer> nums = [Link](1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

// Find sum of even numbers squared


int result = [Link]()
.filter(n -> n % 2 == 0) // keep evens: [2,4,6,8,10]
.map(n -> n * n) // square each: [4,16,36,64,100]
.reduce(0, Integer::sum); // sum all: 220

[Link](result); // 220

Key Stream Operations


// INTERMEDIATE (lazy, return Stream)
.filter(predicate) // keep elements that match
.map(function) // transform each element
.flatMap(function) // flatten nested streams
.sorted() // sort (natural or with Comparator)
.distinct() // remove duplicates
.limit(n) // take first n
.skip(n) // skip first n

// TERMINAL (eager, trigger processing)


.collect([Link]()) // gather into List
.collect([Link](...)) // gather into Map
.forEach(consumer) // perform action
.count() // number of elements
.findFirst() // Optional<T>
.anyMatch(predicate) // true if any matches
.allMatch(predicate) // true if all match

Page 11
Java & Concurrent Programming — Complete Notes

.min() / .max() // Optional<T>


// Group students by grade
Map<String, List<Student>> byGrade = [Link]()
.collect([Link](Student::getGrade));

// Names as comma-separated string


String result = [Link]()
.filter(n -> [Link]("A"))
.collect([Link](", "));

SECTION 6 — Concurrent Programming & Threads

17. Threads — Basics


A thread is the smallest unit of execution. Java supports multithreading — running multiple threads
in parallel.

Way 1: Extend Thread class


class MyThread extends Thread {
@Override
public void run() {
for (int i = 1; i <= 5; i++) {
[Link](getName() + " → " + i);
try { [Link](100); } catch (InterruptedException e) {}
}
}
}

MyThread t1 = new MyThread();


[Link]("Thread-A");
[Link](); // starts new thread (DON'T call run() directly!)

Way 2: Implement Runnable (preferred)


class Task implements Runnable {
public void run() {
[Link]([Link]().getName() + " working");
}
}

Thread t = new Thread(new Task());


[Link]();

// Or with lambda (cleanest)


Thread t2 = new Thread(() -> [Link]("Lambda thread"));
[Link]();
💡 TIP: Prefer Runnable over extending Thread. It separates task logic from threading
mechanism, and your class can still extend another class.

Thread Lifecycle
NEW → RUNNABLE → RUNNING → BLOCKED/WAITING/TIMED_WAITING → TERMINATED

new Thread(r) // NEW


[Link]() // RUNNABLE (ready to run)
thread runs // RUNNING (OS scheduler picks it)

Page 12
Java & Concurrent Programming — Complete Notes

[Link](ms) // TIMED_WAITING
[Link]() // WAITING (needs notify)
synchronized block // BLOCKED (waiting for lock)
run() finishes // TERMINATED

Important Thread Methods


[Link]() // start the thread
[Link]() // wait for thread to finish
[Link](1000) // wait max 1000ms
[Link](500) // pause current thread 500ms
[Link]() // request thread to stop
[Link]() // is thread still running?
[Link](1-10) // 1=min, 5=normal, 10=max
[Link]() // get reference to current thread

18. Synchronization — Race Conditions


When multiple threads access shared data simultaneously, you get race conditions.
Synchronization ensures only one thread accesses critical code at a time.

The Problem (Race Condition)


class Counter {
int count = 0;
void increment() { count++; } // NOT thread-safe! count++ is 3 ops
}
// Two threads incrementing simultaneously can lose updates

Solution 1: synchronized method


class SafeCounter {
int count = 0;

synchronized void increment() { // only one thread at a time


count++;
}

synchronized int getCount() { return count; }


}

Solution 2: synchronized block (finer-grained)


class SafeCounter {
int count = 0;
Object lock = new Object();

void increment() {
synchronized (lock) { // only lock this section
count++;
}
// rest of method runs without lock
}
}

Solution 3: Atomic Variables (fastest)


import [Link].*;

AtomicInteger count = new AtomicInteger(0);

Page 13
Java & Concurrent Programming — Complete Notes

[Link](); // thread-safe, no locks


[Link](5);
[Link](); // read

19. wait() / notify() / notifyAll()


Used for thread communication — one thread waits for a condition, another signals when it's ready.
class SharedBuffer {
List<Integer> buffer = new ArrayList<>();
int maxSize = 5;

synchronized void produce(int item) throws InterruptedException {


while ([Link]() == maxSize) {
wait(); // buffer full — release lock and wait
}
[Link](item);
[Link]("Produced: " + item);
notifyAll(); // wake up waiting consumers
}

synchronized int consume() throws InterruptedException {


while ([Link]()) {
wait(); // nothing to consume — wait
}
int item = [Link](0);
[Link]("Consumed: " + item);
notifyAll(); // wake up waiting producers
return item;
}
}
📝 NOTE: wait() and notify() MUST be called inside a synchronized block/method, otherwise you
get IllegalMonitorStateException.

20. volatile Keyword


volatile ensures that a variable's value is read from main memory, not a thread's local cache. Useful
for flags.
class StopFlag {
volatile boolean stop = false; // 'volatile' = always read from main memory

void stopTask() { stop = true; }

void doWork() {
while (!stop) { // without volatile, might never see the update
// doing work...
}
[Link]("Stopped!");
}
}
💡 TIP: volatile is NOT a replacement for synchronized. It ensures visibility but not atomicity. Use
AtomicInteger for compound operations.

Page 14
Java & Concurrent Programming — Complete Notes

21. Executor Framework (Java 5+)


Creating raw threads for every task is expensive. ExecutorService manages a pool of reusable
threads.
import [Link].*;

// Fixed pool of 4 threads


ExecutorService exec = [Link](4);

for (int i = 0; i < 10; i++) {


final int taskId = i;
[Link](() -> {
[Link]("Task " + taskId + " by " +
[Link]().getName());
});
}

[Link](); // no more tasks accepted


[Link](5, [Link]); // wait for completion

Callable & Future — get results from threads


Callable<Integer> task = () -> {
[Link](1000);
return 42;
};

ExecutorService exec = [Link]();


Future<Integer> future = [Link](task);

// Do other work here...

Integer result = [Link](); // blocks until task completes


[Link]("Result: " + result); // 42
[Link]();

Types of Executor Pools


[Link](n) // fixed n threads
[Link]() // grows/shrinks as needed
[Link]() // exactly 1 thread, tasks queue
[Link](n) // scheduled / periodic tasks

22. ReentrantLock (Advanced Locking)


[Link] provides more flexible locking than synchronized.
import [Link].*;

class SafeAccount {
private double balance;
private final Lock lock = new ReentrantLock();

void deposit(double amount) {

Page 15
Java & Concurrent Programming — Complete Notes

[Link]();
try {
balance += amount;
} finally {
[Link](); // ALWAYS unlock in finally!
}
}

boolean tryTransfer(double amount) {


if ([Link]()) { // non-blocking attempt
try { balance -= amount; return true; }
finally { [Link](); }
}
return false; // lock was busy
}
}

ReadWriteLock — multiple readers OR one writer


ReadWriteLock rwLock = new ReentrantReadWriteLock();

// Multiple threads can read simultaneously


[Link]().lock();
try { /* read data */ } finally { [Link]().unlock(); }

// Only one thread can write


[Link]().lock();
try { /* modify data */ } finally { [Link]().unlock(); }

23. Deadlock
Deadlock happens when two threads each hold a lock and wait for the other's lock — forever.
// Thread 1 holds Lock A, waits for Lock B
// Thread 2 holds Lock B, waits for Lock A
// → both stuck forever!

// Prevention: always acquire locks in the SAME ORDER


// Thread 1: lock A then B
// Thread 2: lock A then B ← consistent order prevents deadlock
💡 TIP: Use tryLock() with timeout to detect and recover from deadlocks. Or use higher-level
constructs like concurrent collections.

24. CountDownLatch & CyclicBarrier


CountDownLatch — wait for N tasks to finish
CountDownLatch latch = new CountDownLatch(3); // count = 3

// 3 worker threads
for (int i = 0; i < 3; i++) {
new Thread(() -> {
doWork();
[Link](); // decrement count

Page 16
Java & Concurrent Programming — Complete Notes

}).start();
}

[Link](); // main thread waits until count reaches 0


[Link]("All workers done!");

CyclicBarrier — all threads wait for each other at a point


CyclicBarrier barrier = new CyclicBarrier(3,
() -> [Link]("All reached barrier!")); // runs when all arrive

for (int i = 0; i < 3; i++) {


new Thread(() -> {
phase1Work();
[Link](); // wait for all threads
phase2Work(); // starts only when all are ready
}).start();
}

25. Concurrent Collections


Regular collections (ArrayList, HashMap) are NOT thread-safe. Use these instead:
// Thread-safe List
List<String> list = new CopyOnWriteArrayList<>();

// Thread-safe HashMap
Map<String, Integer> map = new ConcurrentHashMap<>();
[Link]("key", 1);
[Link]("key", k -> expensiveCompute(k));

// Thread-safe Queue (for producer-consumer)


BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(10);
[Link](1); // blocks if full
int item = [Link](); // blocks if empty
📝 NOTE: ConcurrentHashMap is much faster than [Link]() because it
uses segment-level locking, not a single lock for the whole map.

SECTION 7 — Advanced Java Concepts

26. Inner Classes & Anonymous Classes


Anonymous Class — one-time implementation
// Instead of creating a named class just for one use
Comparator<String> comp = new Comparator<String>() {
public int compare(String a, String b) {
return [Link]() - [Link](); // sort by length
}
};

// Same with lambda (Java 8+)


Comparator<String> comp2 = (a, b) -> [Link]() - [Link]();

Page 17
Java & Concurrent Programming — Complete Notes

Static Nested Class


class Outer {
static class StaticNested {
void show() { [Link]("Static nested"); }
}
}
[Link] obj = new [Link](); // no Outer instance needed

27. Enum
Enums are special classes representing a fixed set of constants.
enum Day {
MON, TUE, WED, THU, FRI, SAT, SUN;

public boolean isWeekend() {


return this == SAT || this == SUN;
}
}

Day today = [Link];


[Link]([Link]()); // false

switch (today) {
case MON: [Link]("Monday blues"); break;
case FRI: [Link]("TGIF!"); break;
}

28. Optional (Java 8+)


Optional wraps a value that might be null, forcing you to handle the absence explicitly — avoids
NullPointerException.
Optional<String> opt1 = [Link]("Hello");
Optional<String> opt2 = [Link]();
Optional<String> opt3 = [Link](null); // safe for null

[Link](); // true
[Link](); // "Hello" (throws if empty)
[Link]("default"); // "default"
[Link](() -> compute()); // lazy default
[Link](String::toUpperCase); // Optional<"HELLO">
[Link](s -> [Link]() > 3); // Optional<"Hello">

// Typical use
Optional<User> user = findUserById(id);
[Link](u -> [Link]([Link]()));

29. String — Important Methods


String s = "Hello World";

Page 18
Java & Concurrent Programming — Complete Notes

[Link]() // 11
[Link](0) // 'H'
[Link]('o') // 4
[Link](6) // "World"
[Link](0, 5) // "Hello"
[Link]() // "hello world"
[Link]() // "HELLO WORLD"
[Link]() // remove leading/trailing spaces
[Link]("World","Java") // "Hello Java"
[Link](" ") // ["Hello", "World"]
[Link]("World") // true
[Link]("He") // true
[Link]("Hello World") // true (use equals, NOT ==)
[Link]("HELLO WORLD") // true
[Link](42) // "42"
[Link]("42") // 42

StringBuilder — mutable String (efficient concatenation)


StringBuilder sb = new StringBuilder();
[Link]("Hello");
[Link](" ");
[Link]("World");
[Link](5, ",");
[Link]();
String result = [Link](); // convert back to String

// StringBuilder is NOT thread-safe


// StringBuffer is thread-safe (but slower)

SECTION 8 — Quick Reference & Cheatsheet

30. OOP Pillars Summary


ENCAPSULATION → Private fields + public getters/setters
Protects internal state

ABSTRACTION → Abstract classes & interfaces


Hide complexity, show only what's needed

INHERITANCE → extends keyword


Child reuses parent code; 'IS-A' relationship

POLYMORPHISM → Override + upcasting


One reference, multiple forms; resolved at runtime

31. Thread Safety Techniques Summary


1. synchronized method/block → simple mutual exclusion
2. volatile keyword → visibility guarantee
3. AtomicInteger/Long/Reference → lock-free atomic ops
4. ReentrantLock → advanced locking (tryLock, timeout)
5. ConcurrentHashMap/CopyOnWriteArrayList → thread-safe collections
6. BlockingQueue → producer-consumer pattern
7. CountDownLatch/CyclicBarrier → thread coordination

Page 19
Java & Concurrent Programming — Complete Notes

8. ExecutorService → manage thread pools

32. Common Java Pitfalls


• Using == to compare Strings (use .equals() instead)
• Calling run() instead of start() — run() executes in current thread!
• Not closing resources — use try-with-resources
• ConcurrentModificationException — don't modify a list while iterating it
• Integer overflow — int maxes at 2,147,483,647; use long for big numbers
• Deadlock — always acquire locks in consistent order
• Not handling InterruptedException — always restore interrupt flag
• Using float/double for exact currency — use BigDecimal
• Mutable objects in Set/Map keys — can break lookup after mutation

— End of Notes —
Java & Concurrent Programming — CT074-3-2

Page 20

You might also like