Java Programming
A Deep & Comprehensive Guide
Syntax · OOP · Generics · Streams · Concurrency · Modern Features
1. What is Java?
Java is a high-level, class-based, object-oriented programming language designed by James Gosling
at Sun Microsystems (now Oracle) and released in 1995. Its core philosophy is "Write Once, Run
Anywhere" (WORA) — compiled Java code can run on any platform that has a Java Virtual Machine (JVM)
without recompilation.
Java is statically typed, strongly typed, compiled (to bytecode), and garbage-collected. It powers Android
development, enterprise backend systems, big data platforms (Hadoop, Spark), and embedded systems.
2. How Java Works: The Execution Model
Java source files (.java) are compiled by javac into platform-independent bytecode (.class files). The JVM
(Java Virtual Machine) then executes the bytecode, using a JIT (Just-In-Time) compiler to convert hot
code paths into native machine instructions at runtime, giving near-native performance.
Your .java file
↓ javac compiler
.class file (bytecode)
↓ JVM (interprets + JIT compiles)
Machine code runs on the OS
The JDK (Java Development Kit) bundles the compiler, JVM, and standard libraries. The JRE (Java
Runtime Environment) contains just the JVM and libraries needed to run programs.
3. Basic Structure of a Java Program
// File must be named [Link]
public class HelloWorld {
public static void main(String[] args) {
[Link]("Hello, World!");
}
}
public class HelloWorld — every Java file contains at least one public class matching the filename. public
static void main(String[] args) is the entry point: static means no instance needed; void means no return
value; String[] args holds command-line arguments. [Link] prints to stdout followed by a
newline.
4. Data Types
4.1 Primitive Types
Primitive types are stored directly on the stack. Java has exactly eight:
Type Size Default Range / Notes
byte 8 bits 0 -128 to 127
short 16 bits 0 -32,768 to 32,767
int 32 bits 0 ~±2.1 billion
long 64 bits 0L ~±9.2 quintillion (suffix L)
float 32 bits 0.0f ~±3.4×10^38 (suffix f)
double 64 bits 0.0 ~±1.8×10^308
char 16 bits '\u0000' Unicode 0–65535
boolean ~1 bit false true / false
int age = 25;
long population = 8_000_000_000L; // underscores for readability (Java 7+)
float price = 9.99f;
double pi = 3.141592653589793;
char grade = 'A';
boolean isJavaFun = true;
4.2 Reference Types
All non-primitive types — classes, arrays, interfaces — are reference types. A variable holds a reference
(pointer) to an object on the heap, not the object itself. The default value for any reference variable is null.
4.3 Wrapper Classes & Autoboxing
Each primitive has a corresponding wrapper class (int → Integer, double → Double, char → Character,
etc.) needed for generics and collections. Java automatically converts between them:
Integer x = 42; // autoboxing : int → Integer
int y = x; // unboxing : Integer → int
5. Variables
5.1 Kinds of Variables
Local variables — inside a method; no default value, must be initialised before use. Instance variables
(fields) — inside a class; default to 0/false/null. Static variables — shared across all instances of the class.
public class Counter {
static int totalCount = 0; // shared across all instances
int id; // unique per instance
Counter() { id = ++totalCount; }
}
5.2 var (Java 10+)
var message = "Hello"; // inferred as String
var list = new ArrayList<String>(); // inferred as ArrayList<String>
var only works for local variables where the type is unambiguous from the right-hand side. Java remains
statically typed — this is compile-time inference, not dynamic typing.
5.3 final (Constants)
final double TAX_RATE = 0.08;
// TAX_RATE = 0.09; // ERROR — final variable cannot be reassigned
6. Operators
Arithmetic
int a = 10, b = 3;
a + b // 13 a - b // 7
a * b // 30 a / b // 3 (integer division — truncates)
a % b // 1 (remainder)
Increment / Decrement
int x = 5;
x++; // post-increment: returns 5, then x becomes 6
++x; // pre-increment: x becomes 6, then returns 6
x--; // post-decrement
--x; // pre-decrement
Comparison & Logical
a == b // equal to a != b // not equal
a > b // greater than a < b // less than
a >= b // >= a <= b // <=
true && false // AND → false (short-circuits: skips right if left is false)
true || false // OR → true (short-circuits: skips right if left is true)
!true // NOT → false
Bitwise
a & b // AND a | b // OR a ^ b // XOR
~a // NOT a << 2 // left shift (*4)
a >> 2 // signed right shift (/4) a >>> 2 // unsigned right shift
Ternary Operator
int max = (a > b) ? a : b;
// Equivalent to: if (a > b) max = a; else max = b;
instanceof (Java 16+ pattern matching)
if (obj instanceof String str) {
[Link]([Link]()); // str is already cast
}
7. Control Flow
if / else if / else
int score = 85;
if (score >= 90) [Link]("A");
else if (score >= 80) [Link]("B");
else if (score >= 70) [Link]("C");
else [Link]("F");
switch Statement & Switch Expressions (Java 14+)
// Classic switch
switch (day) {
case 1: [Link]("Monday"); break;
case 2: [Link]("Tuesday"); break;
default: [Link]("Other");
}
// Modern switch expression — arrow syntax, no fall-through, returns a value
String name = switch (day) {
case 1 -> "Monday";
case 2 -> "Tuesday";
default -> "Unknown";
};
Loops
// for loop
for (int i = 0; i < 5; i++) [Link](i);
// enhanced for-each (iterates any array or Iterable)
for (int n : numbers) [Link](n);
// while — checks condition BEFORE each iteration
while (i < 5) { [Link](i++); }
// do-while — checks AFTER; always runs at least once
do { [Link](i++); } while (i < 5);
break, continue, and Labeled Loops
for (int i = 0; i < 10; i++) {
if (i == 5) break; // exit loop entirely
if (i % 2 == 0) continue; // skip to next iteration
[Link](i + " "); // prints: 1 3
}
// Labeled break — exits both loops at once
outer:
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
if (i == 1 && j == 1) break outer;
8. Arrays
Arrays are fixed-size, ordered, zero-indexed collections of a single type. They are reference types stored on
the heap.
int[] arr = new int[5]; // {0,0,0,0,0} — default values
int[] arr2 = {10, 20, 30, 40, 50}; // array literal
String[] names = new String[3]; // {null, null, null}
arr[0] = 100;
int x = arr2[2]; // 30
int len = [Link]; // 5 (field, not a method)
// 2-D array
int[][] matrix = {{1,2,3},{4,5,6}};
int val = matrix[1][2]; // 6
// Utility methods
[Link](arr2);
[Link]([Link](arr2)); // [10, 20, 30, 40, 50]
int idx = [Link](arr2, 30); // 2
9. Strings
String is an immutable class — every operation creates a new String object. String literals are cached in
the string pool; use equals(), never ==, to compare contents.
String s = "Hello, World!";
[Link]() // 13
[Link](0) // 'H'
[Link]("World") // 7
[Link](7, 12) // "World"
[Link]() // "HELLO, WORLD!"
[Link]() // strips leading/trailing whitespace
[Link]("World","Java") // "Hello, Java!"
[Link]("Hello") // true
[Link](", ") // ["Hello", "World!"]
[Link]() // false (Java 11+)
[Link](42) // "42"
// ALWAYS compare content with equals(), not ==
"hello".equals("hello") // true
"hello".equalsIgnoreCase("HELLO") // true
StringBuilder (mutable, not thread-safe)
StringBuilder sb = new StringBuilder();
[Link]("Hello").append(", ").append("World");
[Link](5, "!");
[Link](5, 6);
String result = [Link](); // "Hello, World"
// Use StringBuilder in loops — far faster than + concatenation
Text Blocks (Java 15+)
String json = """
{
"name": "Alice",
"age": 30
}
""";
10. Object-Oriented Programming (OOP)
OOP organises code around objects that bundle state (fields) and behaviour (methods). Java supports all
four OOP pillars: Encapsulation, Inheritance, Polymorphism, and Abstraction.
10.1 Classes and Objects
public class Dog {
// fields (state)
String name;
int age;
// constructor
public Dog(String name, int age) {
[Link] = name; // 'this' = current instance
[Link] = age;
}
// method (behaviour)
public void bark() {
[Link](name + " says: Woof!");
}
public int getAgeInHumanYears() { return age * 7; }
}
// Creating and using an object
Dog myDog = new Dog("Buddy", 3); // 'new' allocates on heap, calls constructor
[Link](); // "Buddy says: Woof!"
[Link]([Link]()); // 21
10.2 Constructors
A constructor has the same name as the class and no return type. Multiple constructors with different
parameter lists = constructor overloading. Use this(...) to chain them.
public class Rectangle {
int width, height;
Rectangle() { this(1, 1); } // delegates to 2-arg ctor
Rectangle(int side) { this(side, side); }
Rectangle(int w, int h) { width = w; height = h; }
}
10.3 Access Modifiers
Modifier Same Class Same Package Subclass Everywhere
private ✓ ✗ ✗ ✗
(default) ✓ ✓ ✗ ✗
protected ✓ ✓ ✓ ✗
public ✓ ✓ ✓ ✓
10.4 Encapsulation
Hide internal data behind private fields and expose it through getter/setter methods that can validate or
transform values.
public class BankAccount {
private double balance; // hidden
public double getBalance() { return balance; }
public void deposit(double amount) {
if (amount > 0) balance += amount;
}
public void withdraw(double amount) {
if (amount > 0 && amount <= balance) balance -= amount;
}
}
10.5 Inheritance
A class extends another to inherit its fields and methods, establishing an IS-A relationship. Java supports
single inheritance for classes.
public class Animal {
String name;
Animal(String name) { [Link] = name; }
public void eat() { [Link](name + " is eating."); }
public void makeSound() { [Link]("..."); }
}
public class Cat extends Animal {
String color;
Cat(String name, String color) {
super(name); // calls Animal's constructor — must be first line
[Link] = color;
}
@Override
public void makeSound() { // overrides Animal's version
[Link](name + " says: Meow!");
}
public void purr() { [Link](name + " purrs."); }
}
10.6 Polymorphism
A parent-type reference can point to a child-type object. The correct overridden method is chosen at
runtime via dynamic dispatch.
Animal a = new Cat("Whiskers", "orange"); // upcasting
[Link](); // "Whiskers says: Meow!" ← runtime decision
// Downcasting — safe with instanceof
if (a instanceof Cat c) {
[Link]();
}
10.7 Abstract Classes
public abstract class Shape {
String color;
Shape(String color) { [Link] = color; }
public abstract double area(); // subclasses MUST implement
public abstract double perimeter();
public void printInfo() { // concrete — shared behaviour
[Link]("Area: " + area());
}
}
public class Circle extends Shape {
double radius;
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; }
}
10.8 Interfaces
An interface is a contract — defines what a class must do without specifying how. A class can implement
multiple interfaces.
public interface Flyable {
void fly();
void land();
default void checkWeather() { // default method (Java 8+) — has a body
[Link]("Checking weather...");
}
}
public interface Swimmable {
void swim();
}
public class Duck extends Animal implements Flyable, Swimmable {
Duck(String name) { super(name); }
@Override public void fly() { [Link](name + " is flying."); }
@Override public void land() { [Link](name + " is landing."); }
@Override public void swim() { [Link](name + " is swimming."); }
@Override public void makeSound() { [Link]("Quack!"); }
}
10.9 Records (Java 16+)
Concise, immutable data carriers. Auto-generates constructor, accessors, equals(), hashCode(), toString().
public record Point(int x, int y) {}
Point p = new Point(3, 4);
p.x() // 3
p.y() // 4
p // Point[x=3, y=4]
11. Static Members
public class MathHelper {
public static final double PI = 3.14159; // constant
public static int square(int x) { return x * x; }
}
// Access without creating an instance
double pi = [Link];
int sq = [Link](5); // 25
// Static initialiser block — runs once when class is first loaded
static {
[Link]("Class loaded!");
}
12. Enumerations (Enum)
public enum Season { SPRING, SUMMER, AUTUMN, WINTER }
Season s = [Link];
String str = [Link](); // "SUMMER"
int idx = [Link](); // 1
// Enums with fields and methods
public enum Planet {
MERCURY(3.303e+23, 2.4397e6),
EARTH (5.976e+24, 6.37814e6);
private final double mass, radius;
Planet(double mass, double radius) { [Link]=mass; [Link]=radius; }
double surfaceGravity() {
return 6.673E-11 * mass / (radius * radius);
}
}
13. Generics
Generics allow type-safe, reusable code by parameterising over types — detected at compile time, avoiding
ClassCastException.
// Generic class
public class Pair<A, B> {
private A first;
private B second;
Pair(A first, B second) { [Link]=first; [Link]=second; }
A getFirst() { return first; }
B getSecond() { return second; }
}
Pair<String, Integer> p = new Pair<>("Alice", 30);
// Generic method with bounded type parameter
public static <T extends Comparable<T>> T max(T a, T b) {
return [Link](b) >= 0 ? a : b;
}
// Wildcards
void printList(List<?> list) { ... } // unbounded
double sum(List<? extends Number> list) { ... } // upper bounded
void add(List<? super Integer> list) { ... } // lower bounded
14. Collections Framework
The Java Collections Framework ([Link]) provides standard data structures and algorithms.
Interface Implementation Characteristics
List ArrayList Dynamic array; O(1) random access; ordered; allows duplicates
List LinkedList Doubly-linked; O(1) insert/delete at ends
Set HashSet Fastest; no order; no duplicates
Set LinkedHashSet Insertion-ordered set
Set TreeSet Sorted natural order; O(log n) ops
Map HashMap Fastest key-value store; no order
Map LinkedHashMap Insertion-ordered map
Map TreeMap Sorted by key
Queue ArrayDeque Double-ended; use as stack or queue
List<String> list = new ArrayList<>();
[Link]("Alice"); [Link]("Bob"); [Link](0); // "Alice"
[Link](list);
Set<String> set = new HashSet<>();
[Link]("Apple"); [Link]("Apple"); // duplicate ignored; size = 1
Map<String, Integer> map = new HashMap<>();
[Link]("Alice", 30);
[Link]("Eve", 0); // 0
for ([Link]<String, Integer> e : [Link]()) {
[Link]([Link]() + ": " + [Link]());
}
15. Exception Handling
Exception Hierarchy
Throwable
■■■ Error (JVM-level — don't catch: OutOfMemoryError)
■■■ Exception
■■■ RuntimeException (UNCHECKED — optional to handle)
■ ■■■ NullPointerException
■ ■■■ ArrayIndexOutOfBoundsException
■ ■■■ ClassCastException
■ ■■■ ArithmeticException
■■■ Checked Exceptions (MUST handle/declare: IOException, SQLException)
try-catch-finally
try {
int result = 10 / 0; // ArithmeticException
} catch (ArithmeticException e) {
[Link]("Math error: " + [Link]());
} catch (Exception e) { // broader catch comes LAST
[Link]();
} finally {
[Link]("Always runs."); // cleanup code here
}
// Multi-catch (Java 7+)
catch (IOException | SQLException e) { ... }
try-with-resources (Java 7+)
try (FileReader fr = new FileReader("[Link]");
BufferedReader br = new BufferedReader(fr)) {
String line = [Link]();
}
// fr and br are auto-closed — even if an exception is thrown
Throwing & Custom Exceptions
// Throwing
public void setAge(int age) {
if (age < 0) throw new IllegalArgumentException("Negative age: " + age);
[Link] = age;
}
// Custom checked exception
public class InsufficientFundsException extends Exception {
private double shortfall;
InsufficientFundsException(double shortfall) {
super("Short by: " + shortfall);
[Link] = shortfall;
}
double getShortfall() { return shortfall; }
}
public void withdraw(double amount) throws InsufficientFundsException {
if (amount > balance) throw new InsufficientFundsException(amount - balance);
balance -= amount;
}
16. Functional Programming (Java 8+)
Lambda Expressions
// Old: anonymous class
Runnable r = new Runnable() {
@Override public void run() { [Link]("Running!"); }
};
// Lambda (concise equivalent)
Runnable r = () -> [Link]("Running!");
// Lambda with parameters
Comparator<String> byLength = (a, b) -> [Link]() - [Link]();
[Link](byLength);
// Block body
Runnable multiLine = () -> {
[Link]("Line 1");
[Link]("Line 2");
};
Functional Interfaces ([Link])
Interface Signature Use
Function<T,R> T→R transform a value
Predicate<T> T → boolean test/filter
Consumer<T> T → void side effects
Supplier<T> () → T produce a value
BiFunction<A,B,R> A,B → R combine two values
UnaryOperator<T> T→T transform same type
BinaryOperator<T> T,T → T combine same type
Method References
Integer::parseInt // static method ref
[Link]::println // instance method ref (specific instance)
String::toUpperCase // instance method ref (arbitrary instance)
ArrayList::new // constructor ref
Stream API
Streams process sequences of elements in a functional style. They are lazy (nothing runs until a terminal
operation), non-destructive (original collection untouched), and can be parallel.
List<Integer> numbers = [Link](1,2,3,4,5,6,7,8,9,10);
int sumOfSquaresOfEvens = [Link]()
.filter(n -> n % 2 == 0) // [2,4,6,8,10] — intermediate
.map(n -> n * n) // [4,16,36,64,100]
.reduce(0, Integer::sum); // 220 — terminal
List<String> names = [Link]("Alice","Bob","Charlie","Anna");
List<String> result = [Link]()
.filter(n -> [Link]("A"))
.map(String::toUpperCase)
.sorted()
.collect([Link]()); // ["ALICE", "ANNA"]
// groupingBy
Map<Integer, List<String>> byLength = [Link]()
.collect([Link](String::length));
Optional
Optional<String> opt = [Link]("Hello");
Optional<String> empty = [Link]();
[Link]() // true
[Link]() // "Hello"
[Link]("default") // "Hello"
[Link]("default") // "default"
[Link](String::length) // Optional[5]
[Link]([Link]::println);
[Link](s -> [Link]() > 3); // Optional[Hello]
17. I/O Streams
// Write to file
try (PrintWriter pw = new PrintWriter(new FileWriter("[Link]"))) {
[Link]("Hello, file!");
}
// Read from file
try (BufferedReader br = new BufferedReader(new FileReader("[Link]"))) {
String line;
while ((line = [Link]()) != null) [Link](line);
}
// Java NIO (Java 7+) — simpler for small files
Path path = [Link]("[Link]");
[Link](path, "Hello NIO!"); // write
String content = [Link](path); // read all
List<String> lines = [Link](path); // read as list
18. Multithreading & Concurrency
Creating Threads
// Method 1 — extend Thread
class MyThread extends Thread {
@Override public void run() {
[Link]("Thread: " + getName());
}
}
new MyThread().start();
// Method 2 — implement Runnable (preferred)
Runnable task = () -> [Link]("Running in thread!");
new Thread(task).start();
Synchronization
public class Counter {
private int count = 0;
public synchronized void increment() { count++; }
public synchronized int getCount() { return count; }
}
// Synchronized block (finer granularity)
synchronized (this) { count++; }
ExecutorService (Modern Approach)
ExecutorService executor = [Link](4);
[Link](() -> [Link]("Task 1"));
[Link](() -> [Link]("Task 2"));
[Link]();
[Link](5, [Link]);
// Callable returns a value
Callable<Integer> task = () -> { [Link](1000); return 42; };
Future<Integer> future = [Link](task);
Integer result = [Link](); // blocks until ready
Atomic Variables & volatile
AtomicInteger counter = new AtomicInteger(0);
[Link](); // thread-safe
[Link](1, 10); // CAS operation
private volatile boolean running = true;
// volatile ensures variable is always read/written from main memory
19. Nested & Inner Classes
// Static nested class — no reference to outer instance
static class StaticNested { void display() { [Link](x); } }
[Link] obj = new [Link]();
// Inner class — holds reference to outer instance
class Inner { void display() { [Link](x); } }
[Link] inner = [Link] Inner();
// Anonymous class — one-off implementation
Runnable r = new Runnable() {
@Override public void run() { [Link]("Anonymous!"); }
};
20. Annotations
@Override // compiler checks you're actually overriding
@Deprecated // marks a method as outdated
@SuppressWarnings("unchecked")
@FunctionalInterface // ensures interface has exactly one abstract method
// Custom annotation
@interface MyAnnotation {
String value() default "default";
int priority() default 1;
}
@MyAnnotation(value = "test", priority = 2)
public void myMethod() { }
21. Packages & Imports
package [Link]; // must be first statement
import [Link]; // single import
import [Link].*; // wildcard
import static [Link]; // static import
import static [Link].*; // all static members of Math
22. Modern Java Features Summary
Version Feature
Java 8 Lambdas, Stream API, Optional, [Link], default methods
Java 10 var keyword (local variable type inference)
Java 11 [Link]/isBlank/lines, [Link]
Java 14 Switch expressions (standard)
Java 15 Text Blocks
Version Feature
Java 16 Records (standard), instanceof pattern matching
Java 17 Sealed classes
Java 21 Pattern matching in switch, virtual threads (Project Loom)
Sealed Classes (Java 17)
public sealed class Shape permits Circle, Rectangle, Triangle {}
public final class Circle extends Shape { }
public final class Rectangle extends Shape { }
public non-sealed class Triangle extends Shape { } // can be freely extended
Pattern Matching in switch (Java 21)
String result = switch (obj) {
case Integer i -> "Integer: " + i;
case String s when [Link]() > 3 -> "Long string: " + s;
case String s -> "Short string: " + s;
case null -> "Null!";
default -> "Other";
};
23. Important Standard Library Classes
// Math
[Link](-5) // 5 [Link](3, 7) // 7
[Link](16) // 4.0 [Link](2, 10) // 1024.0
[Link](3.9) // 3.0 [Link](3.1) // 4.0
[Link]() // 0.0 – 1.0
// [Link] (Java 8+) — replaces Date/Calendar
LocalDate today = [Link]();
LocalDate birthday = [Link](1990, [Link], 15);
LocalDateTime now = [Link]();
ZonedDateTime zdt = [Link]([Link]("America/New_York"));
Duration d = [Link](start, end);
Period p = [Link](startDate, endDate);
DateTimeFormatter fmt = [Link]("yyyy-MM-dd");
String formatted = [Link](fmt);
24. Best Practices
Category Guideline
Naming Classes: PascalCase | Methods/variables: camelCase | Constants: UPPER_SNAKE_CASE
Strings Use equals() not ==; prefer StringBuilder in loops; use text blocks for multiline
Null safety Return Optional instead of null; check before dereferencing
Resources Always use try-with-resources for Closeable objects
Immutability Prefer final fields and records; immutable objects are thread-safe by default
Collections Declare as interface (List, not ArrayList); choose the right implementation
Exceptions Catch specific types first; never swallow exceptions silently; create custom exceptions for domain errors
OOP Design Favour composition over inheritance; program to interfaces
Concurrency Prefer ExecutorService over raw threads; use AtomicInteger/ConcurrentHashMap over synchronized
Streams Use streams for transformations; don't over-use — simple loops are fine for trivial iterations
Java is an incredibly rich language — mastery comes from building real projects, reading open-source code,
and practicing data structures and design patterns. This guide covers the full breadth of the language; every
concept here can be explored even further.