Java Mastery

๐Ÿš€ Java: The Platform-Independent Powerhouse

Java is a high-level, statically typed, object-oriented programming language designed for platform independence. The core philosophy is "Write Once, Run Anywhere (WORA)", achieved through compilation into platform-neutral bytecode executed by the Java Virtual Machine (JVM).

๐ŸŽฏ Java's Execution Model

Unlike interpreted languages, Java uses a two-step execution model: source code โ†’ bytecode (via javac) โ†’ JVM execution. The JVM then uses Just-In-Time (JIT) compilation to convert hot code paths into native machine code, delivering near-native performance.

๐Ÿข Industry Applications

Java powers enterprise systems, banking software, cloud platforms, Android apps, distributed systems, and large-scale backend services. It prioritizes reliability, security, and maintainability.

๐Ÿ“ˆ Java Versions & LTS

Java follows a six-month release cycle with Long-Term Support (LTS) versions every 3 years: Java 8 LTS, Java 11 LTS, Java 17 LTS, and Java 21 LTS. Each LTS receives updates for years, making them ideal for enterprise production.

๐Ÿ“Œ Write Once, Run Anywhere ๐Ÿ“Œ JIT Compilation ๐Ÿ“Œ Automatic Garbage Collection ๐Ÿ“Œ Strong Type Safety

Why Java Dominates Enterprise Development

Platform independence means you develop on Windows, deploy on Linux servers, and run on any JVM-enabled platform. Automatic memory management via garbage collection eliminates manual memory errors like memory leaks and dangling pointers. Multi-threading support is built into the language, enabling efficient concurrent applications.

Java's ecosystem includes Spring Framework (enterprise), Hibernate (ORM), Maven/Gradle (build tools), and thousands of libraries for every imaginable use case.

// Java Hello World with comprehensive explanation public class JavaBasics { /** * The main method is the entry point for all Java applications. * The JVM calls this method when the program starts. * * @param args Command-line arguments passed to the program */ public static void main(String[] args) { // System.out is a PrintStream connected to standard output System.out.println("โ˜• Java Mastery Track Loaded"); System.out.println("Java Version: " + System.getProperty("java.version")); System.out.println("JVM Name: " + System.getProperty("java.vm.name")); System.out.println("OS: " + System.getProperty("os.name")); // Demonstrate type inference with 'var' (Java 10+) var message = "Java is platform-independent!"; System.out.println(message); } }

โš™๏ธ JVM Architecture & Memory Management

The Java Virtual Machine (JVM) is the cornerstone of Java's platform independence. It's an abstract execution engine that runs Java bytecode, providing memory management, garbage collection, security, and runtime optimization.

๐Ÿ“‚ JVM Memory Architecture

  • Heap: Stores all objects and arrays (shared across threads). Divided into Young Generation (Eden + Survivor spaces) and Old Generation.
  • Stack: Each thread has its own stack containing method frames. Each frame stores local variables, operand stack, and frame data.
  • Method Area (MetaSpace): Stores class metadata, static variables, constants pool, and method bytecode.
  • PC Register: Each thread has a program counter pointing to current instruction.
  • Native Method Stack: Used for native methods written in C/C++.

โ™ป๏ธ Garbage Collection

Java's automatic garbage collection identifies and removes objects no longer referenced. Modern GC algorithms (G1, ZGC, Shenandoah) provide predictable pause times, making Java suitable for real-time applications.

๐Ÿ”ง JRE vs JDK

  • JRE (Java Runtime Environment): JVM + Core Libraries (for running Java apps)
  • JDK (Java Development Kit): JRE + Development Tools (javac, javadoc, jar, jdb, jconsole)
  • JVM: Runtime execution engine only

โšก JIT Compilation

The Just-In-Time compiler identifies frequently executed code ("hot spots") and compiles them to native machine code. This combines the portability of bytecode with near-native execution speed. JIT can optimize code based on actual runtime behavior.

๐Ÿ“Œ Heap Memory ๐Ÿ“Œ Garbage Collection ๐Ÿ“Œ JIT Compilation ๐Ÿ“Œ Class Loading

Understanding the Class Loading Process

The Class Loader Subsystem has three phases: Loading (finding and loading bytecode), Linking (verification, preparation, and resolution), and Initialization (executing static initializers). The Bootstrap Class Loader loads core Java classes, Extension Class Loader loads extension libraries, and Application Class Loader loads user classes. This hierarchical delegation ensures security and prevents class conflicts.

// JVM Architecture Demonstration public class JVMDemo { // Static block - executes during class initialization static { System.out.println("Class loaded by: " + JVMDemo.class.getClassLoader()); } public static void main(String[] args) { // Show available processors System.out.println("Available processors: " + Runtime.getRuntime().availableProcessors()); // Show memory information System.out.println("Total memory: " + Runtime.getRuntime().totalMemory() / 1024 / 1024 + " MB"); System.out.println("Free memory: " + Runtime.getRuntime().freeMemory() / 1024 / 1024 + " MB"); System.out.println("Max memory: " + Runtime.getRuntime().maxMemory() / 1024 / 1024 + " MB"); // Force garbage collection (advisory) System.gc(); System.out.println("GC requested"); // Show Java system properties System.out.println("\n=== JVM Properties ==="); System.out.println("java.vm.name: " + System.getProperty("java.vm.name")); System.out.println("java.vm.version: " + System.getProperty("java.vm.version")); System.out.println("java.vm.vendor: " + System.getProperty("java.vm.vendor")); } } // Run with memory options: // java -Xms256m -Xmx1024m JVMDemo

๐Ÿ“ฆ Variables & Data Types Deep Dive

Java is statically typed - every variable must have a declared type at compile time. This enables early error detection and optimized memory allocation.

๐Ÿ“Š Primitive Types (8 types)

  • byte: 8-bit signed (-128 to 127) - efficient for arrays
  • short: 16-bit signed (-32,768 to 32,767)
  • int: 32-bit signed (-2ยณยน to 2ยณยน-1) - default for integers
  • long: 64-bit signed (suffix L) - for large numbers
  • float: 32-bit IEEE 754 (suffix F)
  • double: 64-bit IEEE 754 - default for decimals
  • char: 16-bit Unicode (0 to 65,535)
  • boolean: true/false (not 0/1 like C)

๐Ÿ“ฆ Reference Types

Reference types store memory addresses pointing to objects on the heap:

  • String: Immutable sequence of characters (interned for efficiency)
  • Arrays: Fixed-size collections (covariant type system)
  • Classes & Objects: User-defined types with fields and methods
  • Interfaces: Abstract types defining contracts

๐Ÿ’พ Variable Scope & Lifetime

  • Local variables: Declared in methods, stack-allocated, scope limited to method
  • Instance variables: Belong to objects, heap-allocated, exist with object
  • Static variables: Class-level, method area, exist for program lifetime

๐Ÿ”’ Constants with 'final'

The final keyword creates immutable references. For primitives, the value cannot change; for references, the reference cannot change (object can still be modified).

๐Ÿ“Œ Static Typing ๐Ÿ“Œ Primitive vs Reference ๐Ÿ“Œ Stack vs Heap ๐Ÿ“Œ Type Conversion

Memory Efficiency of Primitives

Primitive types store values directly on the stack, making them extremely fast for operations. Reference types incur additional overhead (8-16 bytes per reference + object header). For large data structures, consider using primitive arrays or specialized collections like ArrayList<Integer> which auto-box primitives (though this adds overhead).

Type promotion: In expressions, smaller types are automatically promoted to larger types: byte โ†’ short โ†’ int โ†’ long โ†’ float โ†’ double. Casting can force conversion but may lose precision.

// Comprehensive Variables & Data Types Example public class VariablesDemo { // Static variable (class-level) static String className = "JavaBasics"; // Instance variables private int instanceCount; private String instanceName; // Constants public static final double PI = 3.141592653589793; private static final int MAX_RETRIES = 3; public static void main(String[] args) { // Primitive type declarations byte age = 25; // -128 to 127 short year = 2024; // -32,768 to 32,767 int population = 800000000; // up to 2 billion long worldPopulation = 8000000000L; // suffix L required float price = 99.99F; // suffix F required double pi = 3.14159265359; // default for decimals char grade = 'A'; // single quotes boolean isActive = true; // true or false only // Type conversion int largeNumber = 1000; byte smallNumber = (byte) largeNumber; // Explicit casting - may overflow System.out.println("Cast overflow: " + smallNumber); // Automatic type promotion byte a = 10, b = 20; int sum = a + b; // bytes promoted to int System.out.println("Sum: " + sum); // Reference types String message = "Hello, Java!"; // String literal (interned) String newString = new String("Hello"); // Creates new object // String immutability demonstration String s1 = "Hello"; String s2 = s1; s1 = s1 + " World"; // Creates new String, s2 unchanged System.out.println("s2: " + s2); // Still "Hello" // Type inference with var (Java 10+) var inferredString = "Type inferred as String"; var inferredInt = 42; // var inferredNull = null; // ERROR: cannot infer type from null // Boxing and unboxing Integer boxedInt = Integer.valueOf(100); // Explicit boxing int unboxedInt = boxedInt; // Auto-unboxing System.out.println("Boxed: " + boxedInt); // Array declaration int[] numbers = {1, 2, 3, 4, 5}; String[] names = new String[10]; names[0] = "Alice"; // Multi-dimensional array int[][] matrix = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} }; System.out.println("Matrix[1][1]: " + matrix[1][1]); // 5 } }

๐Ÿ”ข Java Operators: Complete Reference

Operators perform operations on variables and values. Java supports a rich set of operators with well-defined precedence and associativity rules.

๐Ÿ“ Operator Categories

  • Arithmetic: +, -, *, /, %, ++, -- (prefix/postfix)
  • Relational: ==, !=, >, <, >=, <= (return boolean)
  • Logical: && (AND), || (OR), ! (NOT) - short-circuit evaluation
  • Bitwise: &, |, ^ (XOR), ~ (complement), <<, >>, >>> (unsigned shift)
  • Assignment: =, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=, >>>=
  • Ternary: condition ? value1 : value2
  • Instanceof: checks object type at runtime

โš ๏ธ Operator Precedence (Highest to Lowest)

Postfix (expr++ expr--) โ†’ Unary (++expr --expr +expr -expr ~ !) โ†’ Multiplicative (* / %) โ†’ Additive (+ -) โ†’ Shift (<< >> >>>) โ†’ Relational (< > <= >= instanceof) โ†’ Equality (== !=) โ†’ Bitwise AND (&) โ†’ Bitwise XOR (^) โ†’ Bitwise OR (|) โ†’ Logical AND (&&) โ†’ Logical OR (||) โ†’ Ternary (?:) โ†’ Assignment (= += -= etc.)

๐ŸŽฏ Important Notes

  • Integer Division: 10 / 3 = 3 (truncates toward zero)
  • Modulus with negatives: -10 % 3 = -1 (sign follows dividend)
  • Short-circuit: false && expr2 (expr2 never evaluated)
  • Bitwise vs Logical: & and | evaluate both operands; && and || short-circuit
๐Ÿ“Œ Short-circuit Evaluation ๐Ÿ“Œ Bitwise Operations ๐Ÿ“Œ Ternary Operator ๐Ÿ“Œ instanceof

Understanding Bitwise Operations

Bitwise operators work at the binary level, making them extremely fast for flags, permissions, and low-level optimizations. & (AND) is used for masking, | (OR) for setting bits, ^ (XOR) for toggling, and << / >> for efficient multiplication/division by powers of 2.

Unsigned right shift (>>>) shifts zeros into the leftmost position, useful for treating numbers as unsigned. The instanceof operator prevents ClassCastException by checking type before casting.

// Comprehensive Operators Demo public class OperatorsDemo { public static void main(String[] args) { // Arithmetic operators int a = 10, b = 3; System.out.println("a + b = " + (a + b)); // 13 System.out.println("a - b = " + (a - b)); // 7 System.out.println("a * b = " + (a * b)); // 30 System.out.println("a / b = " + (a / b)); // 3 (integer division) System.out.println("a % b = " + (a % b)); // 1 (remainder) // Increment/Decrement int x = 5; System.out.println("x++ = " + (x++)); // 5 (post-increment) System.out.println("++x = " + (++x)); // 7 (pre-increment) // Relational operators System.out.println("a > b: " + (a > b)); // true System.out.println("a == 10: " + (a == 10)); // true // Logical operators with short-circuit boolean condition1 = false; boolean condition2 = true; // Short-circuit AND - second operand not evaluated if (condition1 && condition2) { System.out.println("This won't execute"); } // Short-circuit OR if (condition1 || condition2) { System.out.println("OR short-circuit: true"); } // Bitwise operators int flags = 0b1010; // 10 in binary int mask = 0b0110; // 6 in binary System.out.println("flags & mask = " + (flags & mask)); // 2 (0010) System.out.println("flags | mask = " + (flags | mask)); // 14 (1110) System.out.println("flags ^ mask = " + (flags ^ mask)); // 12 (1100) System.out.println("~flags = " + (~flags)); // -11 // Shift operators int value = 8; // 1000 binary System.out.println("value << 2 = " + (value << 2)); // 32 (multiply by 4) System.out.println("value >> 1 = " + (value >> 1)); // 4 (divide by 2) // Negative shift demonstration int negative = -8; System.out.println("negative >> 1 = " + (negative >> 1)); // -4 (sign preserved) System.out.println("negative >>> 1 = " + (negative >>> 1)); // Large positive // Ternary operator int score = 85; String grade = (score >= 90) ? "A" : (score >= 80) ? "B" : (score >= 70) ? "C" : "F"; System.out.println("Grade: " + grade); // instanceof operator Object obj = "Hello"; System.out.println("obj instanceof String: " + (obj instanceof String)); System.out.println("obj instanceof Integer: " + (obj instanceof Integer)); // Assignment operators int num = 10; num += 5; // num = num + 5 num *= 2; // num = num * 2 System.out.println("After assignments: " + num); // Compound assignments with bitwise int bitField = 0b0101; bitField |= 0b0010; // Set bit System.out.println("BitField: " + Integer.toBinaryString(bitField)); } }

๐Ÿ”€ Control Flow: Decision Making in Java

Control flow statements determine execution paths based on conditions. Java provides if-else, switch, and enhanced switch expressions (Java 14+).

๐Ÿ“‹ if-else Statements

Used for conditional branching with boolean conditions. Supports if, if-else, and if-else if chains. Conditions are evaluated in order until a true condition is found.

๐ŸŽฏ Switch Statements (Traditional)

Switch works with int, char, String, enum, and wrapper types. Each case must have a break to prevent fall-through (unless intended). The default case handles unmatched values.

โšก Switch Expressions (Java 14+)

Enhanced switch with arrow syntax (case โ†’ value), multiple case labels, and yield for returning values. Switch expressions are more concise and prevent fall-through bugs.

๐Ÿท๏ธ Pattern Matching (Java 17+)

Pattern matching for switch allows type checking and variable capture in a single expression, reducing boilerplate instanceof checks.

๐Ÿ“Œ if-else Chain ๐Ÿ“Œ Switch Expressions ๐Ÿ“Œ Pattern Matching ๐Ÿ“Œ Nested Conditions

When to Use Switch vs If-Else

Use switch when comparing a single variable against multiple constant values. Use if-else for range checks, complex boolean expressions, or when conditions involve multiple variables. Switch expressions with arrow syntax (Java 14+) are more readable and eliminate accidental fall-through.

Performance note: For many cases, the JVM optimizes switch statements using tableswitch (contiguous values) or lookupswitch (non-contiguous), making them as fast as or faster than if-else chains.

// Control Flow Comprehensive Examples public class ControlFlowDemo { public static void main(String[] args) { // 1. Basic if-else int score = 85; if (score >= 90) { System.out.println("Excellent!"); } else if (score >= 75) { System.out.println("Good job!"); } else if (score >= 60) { System.out.println("Passing"); } else { System.out.println("Need improvement"); } // 2. Nested if with logical operators int age = 25; boolean hasLicense = true; if (age >= 18) { if (hasLicense) { System.out.println("Can drive"); } else { System.out.println("Need license to drive"); } } else { System.out.println("Too young to drive"); } // 3. Traditional switch (fall-through) int day = 3; String dayName; switch (day) { case 1: dayName = "Monday"; break; case 2: dayName = "Tuesday"; break; case 3: dayName = "Wednesday"; break; case 4: dayName = "Thursday"; break; case 5: dayName = "Friday"; break; default: dayName = "Weekend"; } System.out.println("Day: " + dayName); // 4. Switch with String (Java 7+) String fruit = "Apple"; switch (fruit) { case "Apple": System.out.println("Red or green"); break; case "Banana": System.out.println("Yellow"); break; default: System.out.println("Unknown fruit"); } // 5. Switch expression (Java 14+) String grade = "B"; String message = switch (grade) { case "A", "A+" -> "Excellent performance!"; case "B", "B+" -> "Good work!"; case "C" -> "Satisfactory"; default -> { System.out.println("Need improvement"); yield "Please review your work"; } }; System.out.println("Message: " + message); // 6. Switch with yield (Java 14+) int number = 2; int result = switch (number) { case 1: yield 10; case 2: yield 20; default: yield 0; }; System.out.println("Result: " + result); // 7. Pattern matching for switch (Java 17+) Object obj = "Hello Java"; String typeInfo = switch (obj) { case String s -> "String of length: " + s.length(); case Integer i -> "Integer value: " + i; case Long l -> "Long value: " + l; case Double d -> "Double value: " + d; case null -> "null value"; default -> "Unknown type"; }; System.out.println("Type info: " + typeInfo); // 8. Guarded patterns (Java 17+) Object value = 42; String processed = switch (value) { case Integer i when i > 0 -> "Positive integer: " + i; case Integer i when i < 0 -> "Negative integer: " + i; case Integer i -> "Zero integer"; default -> "Not an integer"; }; System.out.println("Processed: " + processed); } }

๐Ÿ”„ Iteration: Loops and Control

Loops enable repeated execution of code blocks. Java provides four loop constructs optimized for different scenarios.

๐Ÿ“Š Loop Types

  • for loop: Best when iteration count is known (index-based)
  • enhanced for loop: Simplified iteration over arrays/collections
  • while loop: Condition-based, may execute zero times
  • do-while loop: Executes at least once before checking condition

๐ŸŽฎ Loop Control

  • break: Exits current loop immediately
  • continue: Skips current iteration, continues with next
  • labeled break/continue: Exits/skips specific nested loops
  • return: Exits method (also exits all loops)

โšก Performance Considerations

  • Cache array length in variable: for(int i=0, len=arr.length; i
  • Use enhanced for loop when index not needed
  • Avoid expensive operations in loop conditions
  • Consider parallel streams for large data sets (Java 8+)
๐Ÿ“Œ for vs while ๐Ÿ“Œ break & continue ๐Ÿ“Œ Nested Loops ๐Ÿ“Œ Infinite Loops

Choosing the Right Loop

Use for loop when iterating a known number of times, especially when you need the index. Use enhanced for for arrays/collections when index not needed (more readable, fewer errors). Use while when iteration depends on a condition that may change during execution. Use do-while when the loop body must execute at least once (e.g., user input validation).

Labeled breaks are essential for exiting nested loops - without labels, you'd need complex flags or multiple condition checks.

// Comprehensive Loop Examples public class LoopsDemo { public static void main(String[] args) { // 1. Traditional for loop System.out.println("=== Traditional for loop ==="); for (int i = 0; i < 5; i++) { System.out.println("i = " + i); } // 2. For loop with multiple variables System.out.println("\n=== Multiple variables ==="); for (int i = 0, j = 10; i < j; i++, j--) { System.out.println("i=" + i + ", j=" + j); } // 3. Enhanced for loop (foreach) System.out.println("\n=== Enhanced for loop ==="); String[] languages = {"Java", "Python", "JavaScript", "C++"}; for (String lang : languages) { System.out.println("Language: " + lang); } // 4. While loop System.out.println("\n=== While loop ==="); int count = 0; while (count < 3) { System.out.println("While count: " + count); count++; } // 5. Do-while loop (executes at least once) System.out.println("\n=== Do-while loop ==="); int attempts = 0; do { System.out.println("Attempt " + (attempts + 1)); attempts++; } while (attempts < 3); // 6. Infinite loop with break System.out.println("\n=== Break example ==="); int counter = 0; while (true) { System.out.println("Iteration: " + counter); counter++; if (counter >= 3) { break; // Exit infinite loop } } // 7. Continue statement System.out.println("\n=== Continue example ==="); for (int i = 0; i < 5; i++) { if (i % 2 == 0) { continue; // Skip even numbers } System.out.println("Odd number: " + i); } // 8. Nested loops System.out.println("\n=== Multiplication Table ==="); for (int i = 1; i <= 3; i++) { for (int j = 1; j <= 3; j++) { System.out.print((i * j) + " "); } System.out.println(); } // 9. Labeled break (exiting nested loops) System.out.println("\n=== Labeled break ==="); outerLoop: for (int i = 1; i <= 3; i++) { for (int j = 1; j <= 3; j++) { if (i == 2 && j == 2) { System.out.println("Breaking out of both loops at i=" + i + ", j=" + j); break outerLoop; } System.out.println("i=" + i + ", j=" + j); } } // 10. Labeled continue System.out.println("\n=== Labeled continue ==="); outer: for (int i = 1; i <= 3; i++) { for (int j = 1; j <= 3; j++) { if (i == 2) { System.out.println("Skipping row " + i); continue outer; } System.out.println("i=" + i + ", j=" + j); } } // 11. Iterating over arrays with index System.out.println("\n=== Array iteration with index ==="); int[] numbers = {10, 20, 30, 40, 50}; for (int i = 0; i < numbers.length; i++) { System.out.println("Index " + i + ": " + numbers[i]); } // 12. Reverse iteration System.out.println("\n=== Reverse iteration ==="); for (int i = numbers.length - 1; i >= 0; i--) { System.out.println("Reverse index " + i + ": " + numbers[i]); } // 13. While with complex condition System.out.println("\n=== Complex condition ==="); int n = 10; while (n > 0 && n % 2 == 0) { System.out.println("n = " + n); n -= 2; } // 14. For-each with primitive array System.out.println("\n=== For-each with array ==="); for (int num : numbers) { System.out.print(num + " "); } System.out.println(); } }

โš™๏ธ Methods: Building Reusable Code

Methods are blocks of code that perform specific tasks, promoting code reuse, modularity, and abstraction. Every Java method belongs to a class.

๐Ÿ”ง Method Components

  • Access Modifier: public, private, protected, or package-private (default)
  • Return Type: Primitive type, reference type, or void (no return)
  • Method Name: camelCase, descriptive (verb-noun pattern)
  • Parameters: Input values with types (zero or more)
  • Method Body: Code to execute (in curly braces)
  • Exceptions: Throws clause for checked exceptions

โšก Method Overloading

Multiple methods with the same name but different parameter lists (type, count, or order). The compiler selects the correct method at compile time based on arguments.

๐Ÿ“š Varargs (Variable Arguments)

Using Type... name syntax, methods can accept zero or more arguments of the same type. Varargs must be the last parameter.

๐Ÿ”„ Recursion

Methods can call themselves - useful for tree traversal, factorial, Fibonacci. Must have a base case to prevent infinite recursion.

๐Ÿ“Œ Method Overloading ๐Ÿ“Œ Varargs ๐Ÿ“Œ Return Types ๐Ÿ“Œ Recursion

Stack Frame Mechanics

When a method is called, the JVM creates a stack frame containing local variables, operand stack, and frame data. Recursion creates multiple frames, which can lead to StackOverflowError if too deep. Tail recursion optimization isn't guaranteed in Java, so iterative solutions are often preferred for large depths.

Method overloading vs overriding: Overloading is compile-time polymorphism (same name, different parameters). Overriding is runtime polymorphism (subclass redefines parent method).

// Comprehensive Methods Example public class MethodsDemo { // ========== Basic Methods ========== // Void method with parameters public static void greet(String name) { System.out.println("Hello, " + name + "!"); } // Method with return value public static int add(int a, int b) { return a + b; } // Method with double return public static double divide(double a, double b) { if (b == 0) { System.out.println("Warning: Division by zero"); return Double.NaN; } return a / b; } // ========== Method Overloading ========== // Overloaded - different parameter count public static int add(int a, int b, int c) { return a + b + c; } // Overloaded - different parameter type public static double add(double a, double b) { return a + b; } // Overloaded - different order public static String add(String a, int b) { return a + b; } // ========== Varargs Methods ========== // Variable arguments (must be last parameter) public static int sum(int... numbers) { int total = 0; for (int num : numbers) { total += num; } return total; } // Varargs with regular parameters public static void log(String level, String... messages) { System.out.print("[" + level + "] "); for (String msg : messages) { System.out.print(msg + " "); } System.out.println(); } // ========== Recursion Examples ========== // Factorial using recursion public static long factorial(int n) { if (n <= 1) return 1; return n * factorial(n - 1); } // Fibonacci using recursion public static long fibonacci(int n) { if (n <= 1) return n; return fibonacci(n - 1) + fibonacci(n - 2); } // Tail recursion (optimization not guaranteed) public static long factorialTail(int n, long accumulator) { if (n <= 1) return accumulator; return factorialTail(n - 1, n * accumulator); } // ========== Access Modifiers Demo ========== private static int privateCounter = 0; static int packagePrivateCounter = 0; // package-private (default) protected static int protectedCounter = 0; public static int publicCounter = 0; private static void privateMethod() { System.out.println("Private method called"); } public static void demonstrateAccess() { privateMethod(); // Can call private within same class privateCounter++; // Can access private variable System.out.println("Access demo complete"); } // ========== Main Method ========== public static void main(String[] args) { System.out.println("=== Method Demos ===\n"); // Basic methods greet("CodeOrbitPro"); System.out.println("Add: " + add(5, 3)); System.out.println("Divide: " + divide(10, 3)); // Method overloading System.out.println("\n=== Overloading ==="); System.out.println("add(int,int): " + add(5, 3)); System.out.println("add(int,int,int): " + add(5, 3, 2)); System.out.println("add(double,double): " + add(5.5, 3.2)); System.out.println("add(String,int): " + add("Value: ", 42)); // Varargs System.out.println("\n=== Varargs ==="); System.out.println("sum(1,2,3): " + sum(1, 2, 3)); System.out.println("sum(1,2,3,4,5): " + sum(1, 2, 3, 4, 5)); log("INFO", "Application", "started", "successfully"); log("ERROR", "Failed", "to", "connect"); // Recursion System.out.println("\n=== Recursion ==="); System.out.println("factorial(5): " + factorial(5)); System.out.println("factorial(10): " + factorial(10)); System.out.println("fibonacci(10): " + fibonacci(10)); // Tail recursion demo System.out.println("factorialTail(5): " + factorialTail(5, 1)); // Method chaining (fluent interface) System.out.println("\n=== Method Chaining ==="); StringBuilder sb = new StringBuilder(); sb.append("Hello") .append(" ") .append("World") .append("!") .append(" Java"); System.out.println(sb.toString()); // Access modifiers System.out.println("\n=== Access Modifiers ==="); demonstrateAccess(); System.out.println("publicCounter: " + publicCounter); } // ========== Static vs Instance Methods ========== static class Calculator { // Instance variable private int result; // Instance method (requires object) public void addToResult(int value) { this.result += value; } // Static method (called on class) public static int multiply(int a, int b) { return a * b; } // Getter public int getResult() { return result; } } }

๐Ÿ“š Arrays & Collections Framework

Arrays store fixed-size sequences of elements of the same type. Java's Collections Framework provides dynamic data structures like ArrayList, LinkedList, HashMap, and HashSet.

๐Ÿ“Š Arrays

Arrays are zero-indexed, fixed-size, and store contiguous memory. They provide O(1) access by index but cannot be resized. Multi-dimensional arrays are arrays of arrays.

๐Ÿ“ฆ Collections Framework

  • List: Ordered, allows duplicates (ArrayList, LinkedList)
  • Set: No duplicates (HashSet, TreeSet, LinkedHashSet)
  • Map: Key-value pairs (HashMap, TreeMap, LinkedHashMap)
  • Queue: FIFO operations (PriorityQueue, ArrayDeque)

โšก Utility Classes

java.util.Arrays provides sorting, searching, and copying. java.util.Collections provides synchronization, unmodifiable views, and utility methods.

๐Ÿ“Œ Array vs ArrayList ๐Ÿ“Œ HashMap vs TreeMap ๐Ÿ“Œ Generics ๐Ÿ“Œ Iterators

Choosing the Right Collection

ArrayList for indexed access with frequent reads. LinkedList for frequent insertions/deletions. HashSet for fast uniqueness checks. TreeSet for sorted unique elements. HashMap for fast key-value lookups. LinkedHashMap for insertion-ordered iteration.

Performance: ArrayList O(1) access, O(n) insertion; HashMap O(1) average for get/put; TreeMap O(log n) for operations. Collections utilities provide thread-safe wrappers and unmodifiable views.

// Arrays and Collections Framework import java.util.*; public class CollectionsDemo { public static void main(String[] args) { // ========== Arrays ========== System.out.println("=== Arrays ==="); // Array declaration and initialization int[] numbers = {10, 20, 30, 40, 50}; String[] names = new String[5]; names[0] = "Alice"; names[1] = "Bob"; // Multi-dimensional array int[][] matrix = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} }; System.out.println("Matrix[1][1]: " + matrix[1][1]); // 5 // Array traversal System.out.print("Numbers: "); for (int num : numbers) { System.out.print(num + " "); } System.out.println(); // Array utility methods Arrays.sort(numbers); System.out.println("Sorted: " + Arrays.toString(numbers)); int index = Arrays.binarySearch(numbers, 30); System.out.println("Index of 30: " + index); int[] copy = Arrays.copyOf(numbers, numbers.length); System.out.println("Array equal: " + Arrays.equals(numbers, copy)); // ========== ArrayList ========== System.out.println("\n=== ArrayList ==="); List list = new ArrayList<>(); // Adding elements list.add("Java"); list.add("Python"); list.add("JavaScript"); list.add(1, "C++"); // Insert at index // Accessing System.out.println("Element at index 2: " + list.get(2)); System.out.println("Size: " + list.size()); // Iteration System.out.print("List: "); for (String lang : list) { System.out.print(lang + " "); } System.out.println(); // Removal list.remove("Python"); list.remove(1); System.out.println("After removal: " + list); // ========== LinkedList ========== System.out.println("\n=== LinkedList ==="); LinkedList linkedList = new LinkedList<>(); linkedList.add("First"); linkedList.add("Second"); linkedList.addFirst("Zeroth"); linkedList.addLast("Last"); System.out.println("LinkedList: " + linkedList); System.out.println("First: " + linkedList.getFirst()); System.out.println("Last: " + linkedList.getLast()); // ========== HashSet ========== System.out.println("\n=== HashSet ==="); Set set = new HashSet<>(); set.add("Apple"); set.add("Banana"); set.add("Apple"); // Duplicate - ignored set.add("Orange"); System.out.println("Set: " + set); System.out.println("Contains 'Banana': " + set.contains("Banana")); // ========== TreeSet (Sorted) ========== System.out.println("\n=== TreeSet ==="); Set treeSet = new TreeSet<>(); treeSet.add(5); treeSet.add(2); treeSet.add(8); treeSet.add(1); System.out.println("Sorted TreeSet: " + treeSet); // ========== HashMap ========== System.out.println("\n=== HashMap ==="); Map map = new HashMap<>(); map.put("Alice", 25); map.put("Bob", 30); map.put("Charlie", 35); map.put("Alice", 26); // Overwrites previous value System.out.println("Alice's age: " + map.get("Alice")); System.out.println("Contains key 'Bob': " + map.containsKey("Bob")); System.out.println("All entries: " + map); // Iterating over Map for (Map.Entry entry : map.entrySet()) { System.out.println(entry.getKey() + " -> " + entry.getValue()); } // ========== TreeMap (Sorted by key) ========== System.out.println("\n=== TreeMap ==="); Map treeMap = new TreeMap<>(); treeMap.put("Zebra", 3); treeMap.put("Apple", 5); treeMap.put("Monkey", 2); System.out.println("Sorted TreeMap: " + treeMap); // ========== PriorityQueue ========== System.out.println("\n=== PriorityQueue ==="); Queue queue = new PriorityQueue<>(); queue.offer(10); queue.offer(5); queue.offer(20); queue.offer(1); System.out.print("PriorityQueue order: "); while (!queue.isEmpty()) { System.out.print(queue.poll() + " "); } System.out.println(); // ========== Stack (Deque) ========== System.out.println("\n=== Stack using Deque ==="); Deque stack = new ArrayDeque<>(); stack.push("First"); stack.push("Second"); stack.push("Third"); System.out.println("Pop: " + stack.pop()); System.out.println("Peek: " + stack.peek()); System.out.println("Stack after pops: " + stack); // ========== Collections Utilities ========== System.out.println("\n=== Collections Utilities ==="); List numList = Arrays.asList(3, 1, 4, 1, 5, 9, 2); Collections.sort(numList); System.out.println("Sorted list: " + numList); Collections.reverse(numList); System.out.println("Reversed: " + numList); Collections.shuffle(numList); System.out.println("Shuffled: " + numList); // Max and min System.out.println("Max: " + Collections.max(numList)); System.out.println("Min: " + Collections.min(numList)); // Frequency System.out.println("Frequency of 1: " + Collections.frequency(numList, 1)); // ========== Synchronized Collections ========== System.out.println("\n=== Synchronized Collections ==="); List syncList = Collections.synchronizedList(new ArrayList<>()); syncList.add("Thread-safe"); syncList.add("Collection"); System.out.println("Synchronized list: " + syncList); // ========== Unmodifiable Collections ========== List unmodifiable = Collections.unmodifiableList(list); // unmodifiable.add("New"); // Throws UnsupportedOperationException System.out.println("Unmodifiable list: " + unmodifiable); } }

๐Ÿ“ Strings & StringBuilder

Strings in Java are immutable objects stored in the String Pool for memory efficiency. StringBuilder and StringBuffer provide mutable alternatives for string manipulation.

๐Ÿ”ค String Immutability

String objects cannot be modified after creation. Any operation that appears to modify a string creates a new String object. This enables string interning and thread safety.

๐Ÿ’พ String Pool

String literals are stored in the String Pool (heap). When creating a literal, the JVM checks the pool first, reusing existing strings to save memory.

โšก StringBuilder vs StringBuffer

  • StringBuilder: Mutable, non-synchronized (faster) - use for single-threaded
  • StringBuffer: Mutable, synchronized (slower) - use for multi-threaded
๐Ÿ“Œ String Interning ๐Ÿ“Œ StringBuilder ๐Ÿ“Œ String Methods ๐Ÿ“Œ Regular Expressions

String Performance Optimization

String concatenation in loops creates many intermediate String objects. Use StringBuilder for repeated concatenation. The compiler optimizes simple concatenations (String s = "a" + "b" + "c") but not loops.

String interning: String.intern() manually adds strings to the pool. Use when many identical strings exist. Java 7+ stores interned strings in heap, not PermGen.

// Strings and StringBuilder Comprehensive Guide public class StringsDemo { public static void main(String[] args) { // ========== String Creation ========== System.out.println("=== String Creation ==="); // String literal (stored in String Pool) String s1 = "Hello"; String s2 = "Hello"; // Using new keyword (creates new object, not in pool) String s3 = new String("Hello"); System.out.println("s1 == s2: " + (s1 == s2)); // true (same reference) System.out.println("s1 == s3: " + (s1 == s3)); // false (different objects) System.out.println("s1.equals(s3): " + s1.equals(s3)); // true (same content) // ========== String Interning ========== String s4 = s3.intern(); // Adds to pool and returns pool reference System.out.println("After intern: " + (s1 == s4)); // true // ========== Common String Methods ========== System.out.println("\n=== String Methods ==="); String text = " Java Programming Language "; System.out.println("Length: " + text.length()); System.out.println("Trim: '" + text.trim() + "'"); System.out.println("Uppercase: " + text.toUpperCase()); System.out.println("Lowercase: " + text.toLowerCase()); System.out.println("Contains 'Java': " + text.contains("Java")); System.out.println("Starts with 'Java': " + text.trim().startsWith("Java")); System.out.println("Ends with 'Language': " + text.trim().endsWith("Language")); System.out.println("Index of 'Programming': " + text.indexOf("Programming")); // Substring String sub = text.substring(5, 15); System.out.println("Substring (5-15): '" + sub + "'"); // Replace System.out.println("Replace: " + text.replace("Java", "Python")); // Split String[] words = text.trim().split(" "); System.out.print("Split words: "); for (String word : words) { System.out.print(word + " | "); } System.out.println(); // Join String joined = String.join("-", words); System.out.println("Joined: " + joined); // Format String formatted = String.format("Name: %s, Age: %d, Score: %.2f", "Alice", 25, 92.5); System.out.println("Formatted: " + formatted); // ========== Character Operations ========== System.out.println("\n=== Character Operations ==="); char ch = text.charAt(5); System.out.println("Character at index 5: " + ch); char[] chars = text.toCharArray(); System.out.println("First 5 chars: " + new String(chars, 0, 5)); // ========== StringBuilder (Mutable Strings) ========== System.out.println("\n=== StringBuilder ==="); StringBuilder sb = new StringBuilder(); // Appending sb.append("Hello"); sb.append(" "); sb.append("World"); System.out.println("After append: " + sb); // Insert sb.insert(5, " Beautiful"); System.out.println("After insert: " + sb); // Replace sb.replace(6, 15, "Awesome"); System.out.println("After replace: " + sb); // Delete sb.delete(6, 13); System.out.println("After delete: " + sb); // Reverse sb.reverse(); System.out.println("Reversed: " + sb); sb.reverse(); // Back to original // Capacity and length System.out.println("Length: " + sb.length()); System.out.println("Capacity: " + sb.capacity()); // Set length (truncate) sb.setLength(5); System.out.println("After setLength(5): " + sb); // ========== Performance Comparison ========== System.out.println("\n=== Performance Comparison ==="); // Inefficient string concatenation (creates many objects) long start = System.nanoTime(); String result = ""; for (int i = 0; i < 10000; i++) { result += "a"; } long end = System.nanoTime(); System.out.println("String concatenation: " + (end - start) / 1_000_000 + " ms"); // Efficient StringBuilder (single object) start = System.nanoTime(); StringBuilder sb2 = new StringBuilder(); for (int i = 0; i < 10000; i++) { sb2.append("a"); } result = sb2.toString(); end = System.nanoTime(); System.out.println("StringBuilder: " + (end - start) / 1_000_000 + " ms"); // ========== Regular Expressions ========== System.out.println("\n=== Regular Expressions ==="); String email = "user@example.com"; String emailRegex = "^[A-Za-z0-9+_.-]+@(.+)$"; System.out.println("Email valid: " + email.matches(emailRegex)); // Pattern matching String logLine = "ERROR 2024-01-15: Connection failed"; boolean hasError = logLine.matches(".*ERROR.*"); System.out.println("Contains ERROR: " + hasError); // Replace with regex String phone = "123-456-7890"; String digits = phone.replaceAll("-", ""); System.out.println("Phone digits: " + digits); // ========== String Pool Demonstration ========== System.out.println("\n=== String Pool ==="); String str1 = "Java"; String str2 = "Java"; String str3 = new String("Java"); String str4 = new String("Java").intern(); System.out.println("str1 == str2: " + (str1 == str2)); // true System.out.println("str1 == str3: " + (str1 == str3)); // false System.out.println("str1 == str4: " + (str1 == str4)); // true // ========== Text Blocks (Java 13+) ========== System.out.println("\n=== Text Blocks ==="); String json = """ { "name": "Java", "version": "17", "features": ["text blocks", "records", "sealed classes"] } """; System.out.println("JSON: " + json); // ========== StringJoiner ========== System.out.println("\n=== StringJoiner ==="); StringJoiner joiner = new StringJoiner(", ", "[", "]"); joiner.add("Apple"); joiner.add("Banana"); joiner.add("Orange"); System.out.println("Joined list: " + joiner); } }

๐Ÿ›๏ธ Object-Oriented Programming Fundamentals

Java is a pure object-oriented language where everything is an object (except primitives). OOP principles enable modular, reusable, and maintainable code.

๐Ÿ“ฆ Classes and Objects

A class is a blueprint for creating objects. Objects have state (fields) and behavior (methods). Constructors initialize object state.

๐ŸŽญ Four Pillars of OOP

  • Encapsulation: Hiding internal state using private fields and public methods
  • Inheritance: Creating hierarchies with 'extends' (is-a relationship)
  • Polymorphism: Method overriding and overloading (compile-time and runtime)
  • Abstraction: Abstract classes and interfaces hiding implementation details

๐Ÿ”ง Access Modifiers

  • private: Accessible only within the same class
  • default (package-private): Accessible within same package
  • protected: Accessible within package + subclasses
  • public: Accessible from anywhere
๐Ÿ“Œ Encapsulation ๐Ÿ“Œ Inheritance ๐Ÿ“Œ Polymorphism ๐Ÿ“Œ Abstraction

Understanding Inheritance vs Composition

Inheritance (is-a) creates tight coupling - changes in parent affect all children. Composition (has-a) is more flexible: class Car { Engine engine; }. Favor composition over inheritance for better maintainability. Java supports single inheritance (one parent class) but multiple interfaces.

Polymorphism allows treating derived classes as base types, enabling flexible, extensible code through interfaces and abstract classes.

// Object-Oriented Programming Comprehensive Example public class OOPDemo { // ========== Encapsulation Example ========== static class BankAccount { // Private fields - encapsulation private String accountNumber; private double balance; private String ownerName; // Constructor public BankAccount(String accountNumber, String ownerName, double initialBalance) { this.accountNumber = accountNumber; this.ownerName = ownerName; this.balance = initialBalance; } // Public getters and setters (controlled access) public String getAccountNumber() { return accountNumber; } public String getOwnerName() { return ownerName; } public double getBalance() { return balance; } // Business logic with validation public void deposit(double amount) { if (amount > 0) { balance += amount; System.out.println("Deposited: $" + amount); } else { System.out.println("Invalid deposit amount"); } } public boolean withdraw(double amount) { if (amount > 0 && amount <= balance) { balance -= amount; System.out.println("Withdrawn: $" + amount); return true; } System.out.println("Insufficient funds"); return false; } public void displayInfo() { System.out.println("Account: " + accountNumber); System.out.println("Owner: " + ownerName); System.out.println("Balance: $" + balance); } } // ========== Inheritance Example ========== static class Animal { protected String name; protected int age; public Animal(String name, int age) { this.name = name; this.age = age; } public void eat() { System.out.println(name + " is eating"); } public void sleep() { System.out.println(name + " is sleeping"); } public void makeSound() { System.out.println(name + " makes a sound"); } public void displayInfo() { System.out.println("Name: " + name + ", Age: " + age); } } static class Dog extends Animal { private String breed; public Dog(String name, int age, String breed) { super(name, age); // Call parent constructor this.breed = breed; } // Method overriding (polymorphism) @Override public void makeSound() { System.out.println(name + " barks: Woof! Woof!"); } // Additional method public void fetch() { System.out.println(name + " is fetching the ball"); } @Override public void displayInfo() { super.displayInfo(); System.out.println("Breed: " + breed); } } static class Cat extends Animal { private String color; public Cat(String name, int age, String color) { super(name, age); this.color = color; } @Override public void makeSound() { System.out.println(name + " meows: Meow! Meow!"); } public void climb() { System.out.println(name + " is climbing"); } } // ========== Abstraction with Abstract Class ========== abstract static class Shape { protected String color; public Shape(String color) { this.color = color; } // Abstract methods - must be implemented by subclasses public abstract double area(); public abstract double perimeter(); // Concrete method public void displayColor() { System.out.println("Color: " + color); } } static class Circle extends Shape { private double radius; public Circle(String color, double radius) { super(color); this.radius = radius; } @Override public double area() { return Math.PI * radius * radius; } @Override public double perimeter() { return 2 * Math.PI * radius; } } static class Rectangle extends Shape { private double width; private double height; public Rectangle(String color, double width, double height) { super(color); this.width = width; this.height = height; } @Override public double area() { return width * height; } @Override public double perimeter() { return 2 * (width + height); } } // ========== Interface Example ========== interface Drawable { void draw(); // Default method (Java 8+) default void print() { System.out.println("Printing drawing"); } // Static method (Java 8+) static void info() { System.out.println("Drawable interface"); } } interface Resizable { void resize(double factor); } // Multiple interface implementation static class Drawing implements Drawable, Resizable { private String name; public Drawing(String name) { this.name = name; } @Override public void draw() { System.out.println("Drawing: " + name); } @Override public void resize(double factor) { System.out.println("Resizing " + name + " by factor " + factor); } } // ========== Polymorphism Example ========== static class AnimalShelter { private List animals = new ArrayList<>(); public void addAnimal(Animal animal) { animals.add(animal); } public void makeAllSounds() { for (Animal animal : animals) { animal.makeSound(); // Polymorphic call } } public void feedAll() { for (Animal animal : animals) { animal.eat(); // Polymorphic call } } } // ========== Main Demonstration ========== public static void main(String[] args) { System.out.println("=== Encapsulation ==="); BankAccount account = new BankAccount("12345", "Alice", 1000); account.deposit(500); account.withdraw(200); account.displayInfo(); // account.balance = 10000; // Error - private field System.out.println("\n=== Inheritance & Polymorphism ==="); Dog dog = new Dog("Max", 3, "Golden Retriever"); Cat cat = new Cat("Whiskers", 2, "Gray"); dog.eat(); dog.makeSound(); dog.fetch(); cat.makeSound(); cat.climb(); System.out.println("\n=== Polymorphic Behavior ==="); AnimalShelter shelter = new AnimalShelter(); shelter.addAnimal(dog); shelter.addAnimal(cat); shelter.makeAllSounds(); System.out.println("\n=== Abstraction ==="); Shape circle = new Circle("Red", 5.0); Shape rectangle = new Rectangle("Blue", 4.0, 6.0); System.out.println("Circle area: " + circle.area()); System.out.println("Circle perimeter: " + circle.perimeter()); circle.displayColor(); System.out.println("Rectangle area: " + rectangle.area()); System.out.println("Rectangle perimeter: " + rectangle.perimeter()); System.out.println("\n=== Interfaces ==="); Drawing drawing = new Drawing("Mountain Landscape"); drawing.draw(); drawing.resize(1.5); drawing.print(); Drawable.info(); System.out.println("\n=== Casting & instanceof ==="); // Upcasting (automatic) Animal animal = new Dog("Buddy", 2, "Beagle"); // Downcasting (explicit - requires check) if (animal instanceof Dog) { Dog downcastDog = (Dog) animal; downcastDog.fetch(); } System.out.println("\n=== Object Class Methods ==="); System.out.println("toString: " + dog.toString()); System.out.println("HashCode: " + dog.hashCode()); // equals comparison Dog dog1 = new Dog("Max", 3, "Golden"); Dog dog2 = new Dog("Max", 3, "Golden"); System.out.println("dog1 equals dog2: " + dog1.equals(dog2)); // Override to compare content } }

๐Ÿ›ก๏ธ Exception Handling: Robust Error Management

Exception handling separates error-handling code from regular logic, making programs more robust and maintainable. Java provides checked and unchecked exceptions.

๐Ÿ“‹ Exception Hierarchy

  • Throwable: Base class for all errors and exceptions
  • Error: Serious problems (OutOfMemoryError, StackOverflowError) - not meant to be caught
  • Exception: Conditions programs should catch
  • RuntimeException: Unchecked exceptions (programming errors) - not required to catch

๐Ÿ”ง Try-Catch-Finally

The try block contains code that might throw exceptions. Catch blocks handle specific exception types. Finally block always executes (resource cleanup).

๐Ÿ’ก Try-with-Resources (Java 7+)

Automatically closes resources implementing AutoCloseable. Eliminates need for explicit finally blocks.

โšก Custom Exceptions

Create application-specific exceptions by extending Exception (checked) or RuntimeException (unchecked).

๐Ÿ“Œ Checked vs Unchecked ๐Ÿ“Œ Try-with-Resources ๐Ÿ“Œ Exception Chaining ๐Ÿ“Œ Custom Exceptions

Checked vs Unchecked Exceptions

Checked exceptions (IOException, SQLException) must be caught or declared in throws clause - compile-time enforced. Unchecked exceptions (NullPointerException, IllegalArgumentException) are runtime errors indicating programming bugs.

Best practice: Use checked exceptions for recoverable conditions (file not found). Use unchecked for programming errors (invalid arguments). Try-with-resources is superior to try-finally for managing resources like files, sockets, and database connections.

// Exception Handling Comprehensive Guide import java.io.*; import java.nio.file.*; import java.util.*; public class ExceptionsDemo { // ========== Custom Exception ========== static class InsufficientFundsException extends Exception { private double amount; public InsufficientFundsException(String message, double amount) { super(message); this.amount = amount; } public double getAmount() { return amount; } } static class InvalidAgeException extends RuntimeException { public InvalidAgeException(String message) { super(message); } } // ========== BankAccount with custom exceptions ========== static class BankAccount { private double balance; public BankAccount(double initialBalance) { this.balance = initialBalance; } public void withdraw(double amount) throws InsufficientFundsException { if (amount > balance) { throw new InsufficientFundsException( "Insufficient funds. Needed: $" + amount + ", Available: $" + balance, amount - balance ); } balance -= amount; System.out.println("Withdrawn: $" + amount); } public double getBalance() { return balance; } } // ========== Person with validation ========== static class Person { private String name; private int age; public void setName(String name) { if (name == null || name.trim().isEmpty()) { throw new IllegalArgumentException("Name cannot be null or empty"); } this.name = name; } public void setAge(int age) { if (age < 0 || age > 150) { throw new InvalidAgeException("Age must be between 0 and 150"); } this.age = age; } @Override public String toString() { return "Person{name='" + name + "', age=" + age + "}"; } } // ========== Main Demonstration ========== public static void main(String[] args) { System.out.println("=== Basic Try-Catch-Finally ==="); try { int result = 10 / 0; System.out.println("Result: " + result); } catch (ArithmeticException e) { System.out.println("Caught ArithmeticException: " + e.getMessage()); } finally { System.out.println("Finally block always executes"); } System.out.println("\n=== Multiple Catch Blocks ==="); try { String str = null; System.out.println(str.length()); // NullPointerException } catch (NullPointerException e) { System.out.println("NullPointerException: " + e.getMessage()); } catch (Exception e) { System.out.println("Generic exception: " + e.getClass().getSimpleName()); } System.out.println("\n=== Multi-Catch (Java 7+) ==="); try { int[] arr = new int[3]; arr[5] = 10; // ArrayIndexOutOfBoundsException } catch (ArrayIndexOutOfBoundsException | NullPointerException e) { System.out.println("Multi-catch caught: " + e.getClass().getSimpleName()); } System.out.println("\n=== Try-with-Resources (AutoCloseable) ==="); // Traditional try-finally (verbose) BufferedReader reader = null; try { reader = new BufferedReader(new FileReader("test.txt")); String line = reader.readLine(); System.out.println("Line: " + line); } catch (FileNotFoundException e) { System.out.println("File not found: " + e.getMessage()); } catch (IOException e) { System.out.println("IO Error: " + e.getMessage()); } finally { try { if (reader != null) reader.close(); } catch (IOException e) { System.out.println("Error closing reader"); } } // Try-with-resources (cleaner) System.out.println("\nTry-with-resources (automatic close):"); try (BufferedReader reader2 = new BufferedReader(new FileReader("test.txt"))) { String line = reader2.readLine(); System.out.println("Line: " + line); } catch (FileNotFoundException e) { System.out.println("File not found: " + e.getMessage()); } catch (IOException e) { System.out.println("IO Error: " + e.getMessage()); } // Creating a file for demonstration try (FileWriter writer = new FileWriter("test.txt")) { writer.write("Hello, Java Exception Handling!"); } catch (IOException e) { System.out.println("Error writing file"); } System.out.println("\n=== Custom Checked Exception ==="); BankAccount account = new BankAccount(500); try { account.withdraw(100); // Success account.withdraw(500); // This will throw exception } catch (InsufficientFundsException e) { System.out.println("Exception: " + e.getMessage()); System.out.println("Shortfall: $" + e.getAmount()); } System.out.println("Final balance: $" + account.getBalance()); System.out.println("\n=== Custom Unchecked Exception ==="); Person person = new Person(); try { person.setName("Alice"); person.setAge(200); // Invalid age - throws RuntimeException System.out.println(person); } catch (InvalidAgeException e) { System.out.println("Validation error: " + e.getMessage()); } System.out.println("\n=== Exception Chaining ==="); try { try { throw new IOException("Original IO error"); } catch (IOException e) { throw new RuntimeException("Wrapper exception", e); } } catch (RuntimeException e) { System.out.println("Caught: " + e.getMessage()); System.out.println("Cause: " + e.getCause().getMessage()); } System.out.println("\n=== Finally Block Guarantee ==="); try { System.out.println("In try block"); return; // Even with return, finally executes } finally { System.out.println("Finally block - executes even with return!"); } System.out.println("\n=== Print Stack Trace ==="); try { throw new IllegalArgumentException("Invalid argument"); } catch (IllegalArgumentException e) { e.printStackTrace(); // Prints full stack trace for debugging } System.out.println("\n=== Suppressed Exceptions ==="); // In try-with-resources, exceptions from close() are suppressed try (CloseableResource resource = new CloseableResource()) { throw new IOException("Main exception"); } catch (IOException e) { System.out.println("Main: " + e.getMessage()); for (Throwable suppressed : e.getSuppressed()) { System.out.println("Suppressed: " + suppressed.getMessage()); } } System.out.println("\n=== Nested Try-Catch ==="); try { int[] numbers = {1, 2, 3}; try { System.out.println(numbers[5]); // Inner exception } catch (ArrayIndexOutOfBoundsException e) { System.out.println("Inner catch: " + e.getMessage()); throw new RuntimeException("Wrapped", e); // Re-throw } } catch (RuntimeException e) { System.out.println("Outer catch: " + e.getMessage()); } System.out.println("\n=== Throws Declaration ==="); try { methodThatThrows(); } catch (IOException e) { System.out.println("Caught from method: " + e.getMessage()); } } // Method declaring checked exception static void methodThatThrows() throws IOException { throw new IOException("Method declared to throw IOException"); } // Custom AutoCloseable resource static class CloseableResource implements AutoCloseable { @Override public void close() throws IOException { throw new IOException("Error while closing resource"); } } }

๐Ÿ’พ File I/O: Reading and Writing Files

Java provides multiple APIs for file operations: java.io (stream-based), java.nio (modern, buffer-based), and Files utility class (Java 7+).

๐Ÿ“ java.io Package

Stream-based I/O with FileReader, FileWriter, BufferedReader, BufferedWriter. Good for simple operations but less performant for large files.

โšก java.nio Package (NIO.2)

Modern file API with Path, Files, and Paths classes. Provides better performance, symbolic link handling, and file system operations.

๐Ÿ“Š Key Operations

  • Reading: Files.readAllLines(), BufferedReader, Scanner
  • Writing: Files.write(), BufferedWriter, PrintWriter
  • Directory: Files.list(), Files.walk(), FileVisitor
  • Operations: Copy, move, delete, create directories
๐Ÿ“Œ NIO vs IO ๐Ÿ“Œ FileVisitor ๐Ÿ“Œ WatchService ๐Ÿ“Œ Memory-Mapped Files

Choosing the Right I/O API

Use NIO.2 (Files class) for most operations - cleaner API, better performance, and powerful features like file tree walking. Use BufferedReader for reading text files line by line. Use Scanner for parsing structured data. Use ObjectInputStream for serialization.

Performance tip: Buffered I/O (BufferedReader/BufferedWriter) is 10-100x faster than unbuffered. For very large files, use memory-mapped files (FileChannel). Always use try-with-resources to ensure proper cleanup.

// File I/O Comprehensive Guide import java.io.*; import java.nio.file.*; import java.nio.charset.StandardCharsets; import java.util.*; import java.util.stream.Stream; public class FileIODemo { private static final String TEST_FILE = "sample.txt"; private static final String OUTPUT_FILE = "output.txt"; public static void main(String[] args) { System.out.println("=== java.io File Operations ==="); demoJavaIO(); System.out.println("\n=== java.nio.file File Operations ==="); demoNIO(); System.out.println("\n=== Directory Operations ==="); demoDirectoryOperations(); System.out.println("\n=== File Attributes ==="); demoFileAttributes(); System.out.println("\n=== File Searching ==="); demoFileSearch(); System.out.println("\n=== File Copying ==="); demoCopyOperations(); } static void demoJavaIO() { // ========== Writing with FileWriter ========== System.out.println("Writing with FileWriter:"); try (FileWriter writer = new FileWriter(TEST_FILE)) { writer.write("Hello, Java File I/O!\n"); writer.write("This is line 2\n"); writer.write("This is line 3\n"); System.out.println("File written successfully"); } catch (IOException e) { System.err.println("Error writing: " + e.getMessage()); } // ========== Writing with BufferedWriter (more efficient) ========== System.out.println("\nWriting with BufferedWriter:"); try (BufferedWriter bw = new BufferedWriter(new FileWriter(OUTPUT_FILE))) { for (int i = 1; i <= 5; i++) { bw.write("Line " + i + ": Java is powerful"); bw.newLine(); } System.out.println("Buffered write complete"); } catch (IOException e) { System.err.println("Error: " + e.getMessage()); } // ========== Reading with BufferedReader ========== System.out.println("\nReading with BufferedReader:"); try (BufferedReader br = new BufferedReader(new FileReader(TEST_FILE))) { String line; int lineNum = 1; while ((line = br.readLine()) != null) { System.out.println("Line " + lineNum + ": " + line); lineNum++; } } catch (IOException e) { System.err.println("Error reading: " + e.getMessage()); } // ========== Reading with Scanner ========== System.out.println("\nReading with Scanner:"); try (Scanner scanner = new Scanner(new File(TEST_FILE))) { while (scanner.hasNextLine()) { System.out.println("Scanner: " + scanner.nextLine()); } } catch (FileNotFoundException e) { System.err.println("File not found: " + e.getMessage()); } // ========== PrintWriter (formatted output) ========== System.out.println("\nPrintWriter (formatted output):"); try (PrintWriter pw = new PrintWriter(new FileWriter("formatted.txt"))) { pw.printf("Name: %s, Age: %d, Score: %.2f%n", "Alice", 25, 92.5); pw.printf("Name: %s, Age: %d, Score: %.2f%n", "Bob", 30, 88.3); System.out.println("Formatted file created"); } catch (IOException e) { System.err.println("Error: " + e.getMessage()); } } static void demoNIO() { Path path = Paths.get(TEST_FILE); // ========== Read all lines at once ========== System.out.println("Reading all lines (NIO):"); try { List lines = Files.readAllLines(path, StandardCharsets.UTF_8); for (String line : lines) { System.out.println("NIO: " + line); } } catch (IOException e) { System.err.println("Error: " + e.getMessage()); } // ========== Write lines with Files.write ========== System.out.println("\nWriting lines (NIO):"); List newLines = Arrays.asList( "NIO Line 1: Modern file API", "NIO Line 2: More efficient", "NIO Line 3: Built-in charset support" ); try { Path outputPath = Paths.get("nio_output.txt"); Files.write(outputPath, newLines, StandardCharsets.UTF_8); System.out.println("NIO file written"); } catch (IOException e) { System.err.println("Error: " + e.getMessage()); } // ========== Read as String (Java 11+) ========== System.out.println("\nReading entire file as String:"); try { String content = Files.readString(Path.of("nio_output.txt")); System.out.println("Content: " + content); } catch (IOException e) { System.err.println("Error: " + e.getMessage()); } // ========== Stream lines (memory efficient for large files) ========== System.out.println("\nStreaming lines (memory efficient):"); try (Stream lines = Files.lines(Paths.get(TEST_FILE))) { lines.filter(line -> line.contains("Java")) .forEach(line -> System.out.println("Contains Java: " + line)); } catch (IOException e) { System.err.println("Error: " + e.getMessage()); } // ========== FileChannel for binary operations ========== System.out.println("\nFileChannel operations:"); try (FileChannel channel = FileChannel.open(Paths.get("channel_test.txt"), StandardOpenOption.CREATE, StandardOpenOption.WRITE)) { String data = "Channel data"; channel.write(ByteBuffer.wrap(data.getBytes())); System.out.println("Channel write complete"); } catch (IOException e) { System.err.println("Error: " + e.getMessage()); } } static void demoDirectoryOperations() { Path dir = Paths.get("test_directory"); // ========== Create directory ========== System.out.println("Creating directory:"); try { if (!Files.exists(dir)) { Files.createDirectory(dir); System.out.println("Directory created: " + dir); } else { System.out.println("Directory already exists"); } } catch (IOException e) { System.err.println("Error creating directory: " + e.getMessage()); } // ========== Create nested directories ========== Path nestedDir = Paths.get("test_directory/subdir/nested"); try { Files.createDirectories(nestedDir); // Creates all parent directories System.out.println("Nested directory created: " + nestedDir); } catch (IOException e) { System.err.println("Error: " + e.getMessage()); } // ========== List directory contents ========== System.out.println("\nListing directory contents:"); try (Stream paths = Files.list(Paths.get("."))) { paths.filter(Files::isRegularFile) .forEach(p -> System.out.println("File: " + p.getFileName())); } catch (IOException e) { System.err.println("Error: " + e.getMessage()); } // ========== Walk directory tree ========== System.out.println("\nWalking directory tree:"); try (Stream walk = Files.walk(Paths.get("test_directory"))) { walk.forEach(p -> { String type = Files.isDirectory(p) ? "[DIR]" : "[FILE]"; System.out.println(type + " " + p); }); } catch (IOException e) { System.err.println("Error: " + e.getMessage()); } // ========== Delete directory recursively ========== System.out.println("\nDeleting directory tree:"); try { Files.walk(Paths.get("test_directory")) .sorted(Comparator.reverseOrder()) .forEach(p -> { try { Files.delete(p); System.out.println("Deleted: " + p); } catch (IOException e) { System.err.println("Failed to delete: " + p); } }); System.out.println("Directory tree deleted"); } catch (IOException e) { System.err.println("Error walking directory: " + e.getMessage()); } } static void demoFileAttributes() { Path path = Paths.get(TEST_FILE); try { // ========== Basic attributes ========== System.out.println("File: " + path); System.out.println("Exists: " + Files.exists(path)); System.out.println("Is readable: " + Files.isReadable(path)); System.out.println("Is writable: " + Files.isWritable(path)); System.out.println("Is executable: " + Files.isExecutable(path)); System.out.println("Is regular file: " + Files.isRegularFile(path)); System.out.println("Is directory: " + Files.isDirectory(path)); System.out.println("Size: " + Files.size(path) + " bytes"); System.out.println("Last modified: " + Files.getLastModifiedTime(path)); // ========== File owner and permissions ========== System.out.println("Owner: " + Files.getOwner(path)); System.out.println("Posix permissions: " + Files.getPosixFilePermissions(path, LinkOption.NOFOLLOW_LINKS)); } catch (IOException e) { System.err.println("Error getting attributes: " + e.getMessage()); } } static void demoFileSearch() { try { // ========== Find files by name pattern ========== System.out.println("Finding .java files:"); try (Stream paths = Files.find(Paths.get("."), 10, (p, attr) -> p.toString().endsWith(".java"))) { paths.limit(5).forEach(p -> System.out.println(" " + p.getFileName())); } // ========== Find files by size ========== System.out.println("\nFinding files larger than 1KB:"); try (Stream paths = Files.find(Paths.get("."), 5, (p, attr) -> attr.isRegularFile() && attr.size() > 1024)) { paths.limit(3).forEach(p -> System.out.println(" " + p.getFileName() + " (" + p.toFile().length() + " bytes)")); } // ========== Find files by modification date ========== System.out.println("\nFiles modified in last day:"); long oneDayAgo = System.currentTimeMillis() - (24 * 60 * 60 * 1000); try (Stream paths = Files.find(Paths.get("."), 3, (p, attr) -> attr.lastModifiedTime().toMillis() > oneDayAgo)) { paths.limit(5).forEach(p -> System.out.println(" " + p.getFileName())); } } catch (IOException e) { System.err.println("Error searching: " + e.getMessage()); } } static void demoCopyOperations() { Path source = Paths.get(TEST_FILE); Path target = Paths.get("copy_" + TEST_FILE); Path moveTarget = Paths.get("moved_" + TEST_FILE); try { // ========== Copy file ========== Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING); System.out.println("File copied to: " + target); // ========== Move/Rename file ========== Files.move(target, moveTarget, StandardCopyOption.REPLACE_EXISTING); System.out.println("File moved to: " + moveTarget); // ========== Delete file ========== Files.delete(moveTarget); System.out.println("File deleted: " + moveTarget); // ========== Create temporary file ========== Path tempFile = Files.createTempFile("temp", ".txt"); System.out.println("Temporary file created: " + tempFile); Files.write(tempFile, "Temporary content".getBytes()); // Delete on exit (cleanup) tempFile.toFile().deleteOnExit(); System.out.println("Temporary file will be deleted on exit"); } catch (IOException e) { System.err.println("Error in copy/move: " + e.getMessage()); } } }