Complete Java Programming Tutorial

Master Java - a powerful, object-oriented programming language used for enterprise applications, Android development, and more

Introduction to Java

Java is a high-level, class-based, object-oriented programming language developed by Sun Microsystems (now owned by Oracle) in 1995. Java is designed to be platform-independent, with its "write once, run anywhere" (WORA) capability.

Simple Java Program
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

Why Learn Java?

  • Platform Independent - Runs on any device with JVM
  • Object-Oriented - Promotes clean, modular code
  • Robust Ecosystem - Vast collection of libraries and frameworks
  • High Performance - JIT compilation enables near-native speed
  • Multithreading - Built-in support for concurrent programming
  • High Demand - Widely used in enterprise and Android development

Key Features of Java

  • Simple and easy to learn
  • Object-oriented programming support
  • Platform independent (JVM)
  • Secure (no explicit pointers, bytecode verification)
  • Multithreaded
  • High performance
  • Distributed computing support
  • Dynamic (reflection, runtime type information)

Environment Setup

To start programming in Java, you need to install the Java Development Kit (JDK) and optionally set up an Integrated Development Environment (IDE).

1. Installing Java

  1. Download JDK from Oracle's website
  2. Run the installer
  3. Set JAVA_HOME environment variable
  4. Add Java to system PATH
  5. Verify installation: java -version and javac -version

2. Development Environments

Option Description
Command Line Compile with javac, run with java
IntelliJ IDEA Powerful Java IDE by JetBrains
Eclipse Popular open-source Java IDE
VS Code Lightweight editor with Java extensions
NetBeans Another popular Java IDE

3. Running Java Code

  • Compile: javac HelloWorld.java
  • Run: java HelloWorld
Testing Java Installation
// Create HelloWorld.java
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Java is working!");
    }
}

// Compile and run:
// javac HelloWorld.java
// java HelloWorld

Basic Syntax

Java syntax is similar to C/C++ but with stricter object-oriented principles.

Java Program Structure
// Single-line comment
/*
 * Multi-line comment
 */

package com.example;  // Package declaration

import java.util.*;   // Import statements

public class MyClass {  // Class declaration

    // Class variable
    private static int classVar = 10;

    // Instance variable
    private String instanceVar;

    // Constructor
    public MyClass(String value) {
        this.instanceVar = value;
    }

    // Method
    public void printMessage() {
        System.out.println("Message: " + this.instanceVar);
    }

    // Main method - program entry point
    public static void main(String[] args) {
        MyClass obj = new MyClass("Hello");
        obj.printMessage();
    }
}

Key Components

Component Description Example
Classes Blueprints for objects public class MyClass {}
Methods Functions defined in classes public void myMethod() {}
Variables Data storage int x = 5;
Statements Instructions System.out.println();
Blocks Code between {} { int y = 10; }
Comments Non-executable notes // This is a comment

First Java Program

import java.util.Scanner;

public class SimpleCalculator {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.print("Enter first number: ");
        double num1 = scanner.nextDouble();

        System.out.print("Enter second number: ");
        double num2 = scanner.nextDouble();

        System.out.println("Sum: " + (num1 + num2));
        System.out.println("Product: " + (num1 * num2));

        scanner.close();
    }
}
Enter first number: 5 Enter second number: 3 Sum: 8.0 Product: 15.0

Data Types

Java is a statically-typed language, meaning all variables must be declared with a specific type.

Primitive Data Types

Data Type Size Description Example
byte 1 byte Very small integer byte b = 100;
short 2 bytes Small integer short s = 10000;
int 4 bytes Standard integer int i = 100000;
long 8 bytes Large integer long l = 100000L;
float 4 bytes Single-precision decimal float f = 3.14f;
double 8 bytes Double-precision decimal double d = 3.14159;
char 2 bytes Single character char c = 'A';
boolean 1 bit True/false value boolean flag = true;

Reference Data Types

  • Objects: Instances of classes
  • Arrays: Collections of elements
  • Strings: Sequences of characters (technically objects)
  • Interfaces: Abstract types
Data Type Example
public class DataTypeExample {
    public static void main(String[] args) {
        // Primitive types
        int age = 25;
        double price = 19.99;
        char grade = 'A';
        boolean isJavaFun = true;

        // Reference types
        String name = "Alice";
        int[] numbers = {1, 2, 3};

        System.out.println("Age: " + age);
        System.out.println("Price: " + price);
        System.out.println("Grade: " + grade);
        System.out.println("Is Java fun? " + isJavaFun);
        System.out.println("Name: " + name);
        System.out.println("First number: " + numbers[0]);
    }
}

Variables

Variables are containers for storing data values. In Java, each variable must be declared with a specific type.

Variable Declaration

type variableName = value;
Variable Examples
// Different variable types
String name = "Alice";       // String
int age = 25;            // Integer
double height = 5.9;      // Double
boolean isStudent = true; // Boolean
char grade = 'A';        // Character

Variable Types in Java

  • Local variables: Declared inside methods
  • Instance variables: Declared in a class outside any method (non-static)
  • Class variables: Declared with static keyword (shared among all instances)

Variable Naming Rules

  • Must start with a letter, $, or _
  • Can contain letters, digits, $, and _
  • Case-sensitive
  • Cannot be Java keywords
  • Use camelCase for variable names
  • Use meaningful, descriptive names
Variable Scope Example
public class VariableScope {
    // Instance variable
    int instanceVar = 10;

    // Class variable
    static int classVar = 20;

    public void myMethod() {
        // Local variable
        int localVar = 30;
        System.out.println(localVar);
    }

    public static void main(String[] args) {
        VariableScope obj = new VariableScope();
        System.out.println(obj.instanceVar);
        System.out.println(classVar);
        obj.myMethod();
    }
}

Operators

Java provides various operators for performing operations on variables and values.

Arithmetic Operators

Operator Description Example
+ Addition 5 + 3 → 8
- Subtraction 5 - 3 → 2
* Multiplication 5 * 3 → 15
/ Division 5 / 3 → 1
% Modulus 5 % 3 → 2
++ Increment x++
-- Decrement x--

Assignment Operators

int x = 10;
x += 5;  // x = x + 5 → 15
x -= 3;  // x = x - 3 → 12
x *= 2;  // x = x * 2 → 24
x /= 4;  // x = x / 4 → 6

Comparison Operators

Operator Description Example
== Equal to 5 == 3 → false
!= Not equal 5 != 3 → true
> Greater than 5 > 3 → true
< Less than 5 < 3 → false
>= Greater than or equal 5 >= 3 → true
<= Less than or equal 5 <= 3 → false

Logical Operators

Operator Description Example
&& Logical AND true && false → false
|| Logical OR true || false → true
! Logical NOT !true → false

Operator Example

public class OperatorExample {
    public static void main(String[] args) {
        int a = 10;
        int b = 20;

        System.out.println("a + b = " + (a + b));
        System.out.println("a < b: " + (a < b));
        System.out.println("a == 10 && b == 20: " + (a == 10 && b == 20));

        // Ternary operator
        String result = (a > b) ? "a is greater" : "b is greater";
        System.out.println(result);
    }
}
a + b = 30 a < b: true a == 10 && b == 20: true b is greater

Conditional Statements

Conditional statements are used to perform different actions based on different conditions.

if Statement

if (condition) {
    // code to execute if condition is true
}

if-else Statement

if (condition) {
    // code if true
} else {
    // code if false
}

if-else-if Ladder

if (condition1) {
    // code if condition1 true
} else if (condition2) {
    // code if condition2 true
} else {
    // code if all false
}

switch Statement

switch (expression) {
    case value1:
        // code
        break;
    case value2:
        // code
        break;
    default:
        // default code
}
Conditional Example
public class ConditionalExample {
    public static void main(String[] args) {
        int score = 85;
        char grade;

        if (score >= 90) {
            grade = 'A';
        } else if (score >= 80) {
            grade = 'B';
        } else if (score >= 70) {
            grade = 'C';
        } else {
            grade = 'F';
        }

        System.out.println("Grade: " + grade);

        // Switch example
        int day = 3;
        String dayName;

        switch (day) {
            case 1: dayName = "Monday"; break;
            case 2: dayName = "Tuesday"; break;
            case 3: dayName = "Wednesday"; break;
            default: dayName = "Invalid day";
        }

        System.out.println("Day: " + dayName);
    }
}

Loops

Loops are used to execute a block of code repeatedly.

while Loop

while (condition) {
    // code to execute
}

do-while Loop

do {
    // code to execute
} while (condition);

for Loop

for (initialization; condition; increment) {
    // code to execute
}

Enhanced for Loop (for-each)

for (type variable : collection) {
    // code to execute
}

Loop Control Statements

  • break - Terminates the loop
  • continue - Skips current iteration

Loop Examples

public class LoopExamples {
    public static void main(String[] args) {
        // while loop
        int i = 1;
        while (i <= 5) {
            System.out.println(i);
            i++;
        }

        // do-while loop
        int j = 1;
        do {
            System.out.println(j);
            j++;
        } while (j <= 5);

        // for loop
        for (int k = 1; k <= 5; k++) {
            if (k == 3) continue;
            System.out.println(k);
        }

        // enhanced for loop
        int[] numbers = {1, 2, 3, 4, 5};
        for (int num : numbers) {
            System.out.println(num);
        }
    }
}
1 2 3 4 5 1 2 3 4 5 1 2 4 5 1 2 3 4 5

Methods

Methods are blocks of code that perform a specific task and can be reused.

Method Definition

modifier returnType methodName(parameters) {
    // method body
    return value;
}

Method Call

methodName(arguments);
Method Example
public class MethodExample {

    // Method definition
    public static String greet(String name) {
        return "Hello, " + name + "!";
    }

    // Method with no return value
    public static void printMessage(String message) {
        System.out.println(message);
    }

    // Method overloading
    public static int add(int a, int b) {
        return a + b;
    }

    public static double add(double a, double b) {
        return a + b;
    }

    public static void main(String[] args) {
        // Method call
        String greeting = greet("Alice");
        printMessage(greeting);

        System.out.println("Sum (int): " + add(5, 3));
        System.out.println("Sum (double): " + add(5.5, 3.2));
    }
}

Method Parameters

  • Primitive types are passed by value (copy is made)
  • Objects are passed by reference (memory address is passed)

Variable Arguments (Varargs)

public static int sum(int... numbers) {
    int total = 0;
    for (int num : numbers) {
        total += num;
    }
    return total;
}

Recursion

public static int factorial(int n) {
    if (n == 0) return 1;
    return n * factorial(n - 1);
}

Arrays

Arrays are used to store multiple values in a single variable.

Array Declaration

// One-dimensional array
type[] arrayName = new type[size];
type[] arrayName = {value1, value2, ...};

// Two-dimensional array


                        

Array Operations

Operation Description Example
Access Get element by index arr[0]
Modify Change element arr[0] = 5
Length Number of elements arr.length
Loop Iterate through elements for (int num : arr)
Array Example
public class ArrayExample {
    public static void main(String[] args) {
        // One-dimensional array
        int[] numbers = {1, 2, 3, 4, 5};

        // Access elements
        System.out.println(numbers[1]);  // 2

        // Change element
        numbers[0] = 10;

        // Loop through array
        for (int num : numbers) {
            System.out.println(num);
        }

        // Two-dimensional array
        

        // Access 2D array
        System.out.println(matrix[0][1]);  // 2
    }
}

Arrays Class

The java.util.Arrays class provides useful methods for working with arrays:

Arrays.sort(arr);       // Sort array
Arrays.binarySearch(arr, key);  // Binary search
Arrays.fill(arr, value); // Fill array with value
Arrays.copyOf(arr, length);  // Copy array

Strings

Strings in Java are objects that represent sequences of characters.

String Creation

// Using string literal (stored in string pool)
String s1 = "Hello";

// Using new keyword (creates new object in heap)
String s2 = new String("Hello");

String Operations

Operation Description Example
Length Get string length str.length()
Concatenation Combine strings str1 + str2
Substring Extract part of string str.substring(1, 3)
Comparison Compare strings str1.equals(str2)
Search Find character/index str.indexOf('e')
Case Change case str.toUpperCase()
Trim Remove whitespace str.trim()

String Methods

String str = " Hello World! ";

str.trim();         // "Hello World!"
str.toLowerCase();   // " hello world! "
str.toUpperCase();   // " HELLO WORLD! "
str.replace("H", "J");  // " Jello World! "
str.split(" ");      // ["", "Hello", "World!", ""]
str.indexOf("World"); // 6
String Example
public class StringExample {
    public static void main(String[] args) {
        String name = "Alice";
        int age = 25;

        // String concatenation
        String message = "My name is " + name + " and I'm " + age + " years old.";
        System.out.println(message);

        // String formatting
        String formatted = String.format("My name is %s and I'm %d years old.", name, age);
        System.out.println(formatted);

        // String methods
        String text = " Java is awesome! ";
        System.out.println(text.trim());
        System.out.println(text.toLowerCase());
        System.out.println(text.replace("awesome", "great"));
    }
}

StringBuilder

For mutable strings (better performance with frequent modifications):

StringBuilder sb = new StringBuilder("Hello");
sb.append(" World");  // "Hello World"
sb.insert(5, ", ");    // "Hello, World"
sb.reverse();        // "dlroW ,olleH"

Object-Oriented Programming

Java is fundamentally object-oriented, with all code written inside classes.

Four Pillars of OOP

Pillar Description Java Implementation
Encapsulation Bundling data with methods Private fields with public getters/setters
Inheritance Creating new classes from existing ones extends keyword
Polymorphism One interface, multiple implementations Method overriding, interfaces
Abstraction Hiding complex implementation Abstract classes, interfaces

Benefits of OOP

  • Modularity for easier maintenance
  • Reuse of code through inheritance
  • Flexibility through polymorphism
  • Effective problem solving by modeling real-world objects

Classes & Objects

A class is a blueprint for objects, and an object is an instance of a class.

Class Definition

public class ClassName {
    // Fields (instance variables)
    private type fieldName;

    // Constructor
    public ClassName(type parameter) {
        this.fieldName = parameter;
    }

    // Methods
    public returnType methodName(parameters) {
        // method body
    }
}

Creating Objects

ClassName objName = new ClassName(arguments);
Class and Object Example
public class Dog {
    // Fields
    private String name;
    private int age;

    // Constructor
    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // Methods
    public void bark() {
        System.out.println("Woof! Woof!");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

public class Main {
    public static void main(String[] args) {
        // Create object
        Dog myDog = new Dog("Buddy", 3);

        // Call methods
        myDog.bark();
        System.out.println("Dog's name: " + myDog.getName());
    }
}

Constructors

  • Special method called when object is created
  • Same name as the class
  • No return type
  • Can be overloaded

this Keyword

Refers to the current object instance. Used to:

  • Differentiate instance variables from parameters
  • Call one constructor from another
  • Pass current object as parameter

Inheritance

Inheritance allows a class to inherit properties and methods from another class.

extends Keyword

class ChildClass extends ParentClass {
    // Additional fields and methods
}

super Keyword

Used to:

  • Call parent class constructor
  • Access parent class methods
Inheritance Example
class Animal {
    protected String name;

    public Animal(String name) {
        this.name = name;
    }

    public void eat() {
        System.out.println(name + " is eating.");
    }
}

class Dog extends Animal {
    private String breed;

    public Dog(String name, String breed) {
        super(name);  // Call parent constructor
        this.breed = breed;
    }

    public void bark() {
        System.out.println(name + " is barking.");
    }

    @Override
    public void eat() {
        super.eat();  // Call parent method
        System.out.println("Dog food is yummy!");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog myDog = new Dog("Buddy", "Golden Retriever");
        myDog.eat();
        myDog.bark();
    }
}

Types of Inheritance

  • Single: One class extends another
  • Multilevel: Chain of inheritance
  • Hierarchical: Multiple classes extend one class
  • Multiple: Not supported in Java (use interfaces instead)

Method Overriding

When a subclass provides a specific implementation of a method already defined in its parent class.

  • Must have same name, parameters, and return type
  • Access modifier can't be more restrictive
  • Use @Override annotation

Polymorphism

Polymorphism allows objects of different classes to be treated as objects of a common superclass.

Runtime Polymorphism (Method Overriding)

class Animal {
    public void sound() {
        System.out.println("Animal makes a sound");
    }
}

class Dog extends Animal {
    @Override
    public void sound() {
        System.out.println("Dog barks");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal myAnimal = new Dog();  // Upcasting
        myAnimal.sound();  // Calls Dog's sound()
    }
}

Compile-time Polymorphism (Method Overloading)

class Calculator {
    public int add(int a, int b) {
        return a + b;
    }

    public double add(double a, double b) {
        return a + b;
    }
}

Polymorphism Benefits

  • Code reusability
  • Flexibility
  • Simplified interface
  • Easier maintenance

Interfaces

Interfaces define contracts that classes must implement. They contain abstract methods (Java 8+ can have default and static methods).

Interface Definition

interface InterfaceName {
    // Constant fields (implicitly public static final)
    type CONSTANT_NAME = value;

    // Abstract methods (implicitly public abstract)
    returnType methodName(parameters);

    // Default methods (Java 8+)
    default returnType methodName() {
        // implementation
    }

    // Static methods (Java 8+)
    static returnType utilityMethod() {
        // implementation
    }
}

Implementing Interfaces

class ClassName implements InterfaceName {
    // Must implement all abstract methods
}
Interface Example
interface Drawable {
    String COLOR = "Black";  // public static final

    void draw();  // public abstract

    default void printColor() {
        System.out.println("Color: " + COLOR);
    }
}

class Circle implements Drawable {
    @Override
    public void draw() {
        System.out.println("Drawing a circle");
    }
}

public class Main {
    public static void main(String[] args) {
        Circle circle = new Circle();
        circle.draw();
        circle.printColor();
        System.out.println("Interface constant: " + Drawable.COLOR);
    }
}

Multiple Inheritance with Interfaces

interface A {
    void methodA();
}

interface B {
    void methodB();
}

class C implements A, B {
    public void methodA() { /* implementation */ }
    public void methodB() { /* implementation */ }
}

Functional Interfaces (Java 8+)

Interfaces with exactly one abstract method, used with lambda expressions:

@FunctionalInterface
interface Calculator {
    int calculate(int a, int b);
}

// Using lambda expression
Calculator add = (a, b) -> a + b;
System.out.println(add.calculate(5, 3));  // 8

Exception Handling

Exceptions are events that disrupt normal program flow. Java provides try-catch blocks to handle exceptions gracefully.

Try-Catch Block

try {
    // Code that might throw exception
} catch (ExceptionType e) {
    // Handle exception
} finally {
    // Code that always executes
}

Exception Hierarchy

  • Throwable - Superclass of all exceptions
  • Error - Serious problems (e.g., OutOfMemoryError)
  • Exception - Problems that can be handled
    • RuntimeException - Unchecked exceptions (e.g., NullPointerException)
    • Checked exceptions - Must be handled (e.g., IOException)

Common Exceptions

Exception Description
NullPointerException Accessing null object reference
ArrayIndexOutOfBoundsException Invalid array index
ClassCastException Invalid type casting
IllegalArgumentException Invalid argument passed
IOException Input/output operation failure
Exception Handling Example
import java.util.Scanner;

public class ExceptionExample {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        try {
            System.out.print("Enter a number: ");
            int num = scanner.nextInt();
            int result = 10 / num;
            System.out.println("Result: " + result);
        } catch (ArithmeticException e) {
            System.out.println("Cannot divide by zero!");
        } catch (Exception e) {
            System.out.println("An error occurred: " + e.getMessage());
        } finally {
            scanner.close();
            System.out.println("Scanner closed.");
        }
    }
}

Custom Exceptions

class InvalidAgeException extends Exception {
    public InvalidAgeException(String message) {
        super(message);
    }
}

public class Main {
    static void validateAge(int age) throws InvalidAgeException {
        if (age < 0) {
            throw new InvalidAgeException("Age cannot be negative");
        }
    }

    public static void main(String[] args) {
        try {
            validateAge(-5);
        } catch (InvalidAgeException e) {
            System.out.println(e.getMessage());
        }
    }
}

Collections Framework

The Java Collections Framework provides classes and interfaces for storing and manipulating groups of objects.

Core Interfaces

Interface Description Implementations
List Ordered collection, allows duplicates ArrayList, LinkedList, Vector
Set Collection with no duplicates HashSet, TreeSet, LinkedHashSet
Queue Collection designed for holding elements prior to processing PriorityQueue, LinkedList
Map Key-value pairs HashMap, TreeMap, LinkedHashMap

Common Collection Operations

// List example
List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.get(0);  // "Alice"

// Set example
Set<Integer> numbers = new HashSet<>();
numbers.add(1);
numbers.add(2);
numbers.add(1);  // Duplicate, not added

// Map example
Map<String, Integer> ages = new HashMap<>();
ages.put("Alice", 25);
ages.put("Bob", 30);
ages.get("Alice");  // 25
Collections Example
import java.util.*;

public class CollectionsExample {
    public static void main(String[] args) {
        // List
        List<String> fruits = new ArrayList<>();
        fruits.add("Apple");
        fruits.add("Banana");
        fruits.add("Cherry");

        // Enhanced for loop
        for (String fruit : fruits) {
            System.out.println(fruit);
        }

        // Set
        Set<Integer> uniqueNumbers = new HashSet<>();
        uniqueNumbers.add(1);
        uniqueNumbers.add(2);
        uniqueNumbers.add(1);  // Duplicate
        System.out.println("Set size: " + uniqueNumbers.size());  // 2

        // Map
        Map<String, Integer> inventory = new HashMap<>();
        inventory.put("Apples", 50);
        inventory.put("Oranges", 30);
        System.out.println("Apples in stock: " + inventory.get("Apples"));
    }
}

Collections Utility Class

The java.util.Collections class provides useful methods:

Collections.sort(list);       // Sort list
Collections.reverse(list);    // Reverse list
Collections.shuffle(list);    // Randomly shuffle list
Collections.max(collection);  // Find maximum element

File Handling

Java provides classes for reading from and writing to files.

File Reading

// Using BufferedReader
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
    String line;
    while ((line = reader.readLine()) != null) {
        System.out.println(line);
    }
} catch (IOException e) {
    e.printStackTrace();
}

File Writing

// Using BufferedWriter
try (BufferedWriter writer = new BufferedWriter(new FileWriter("file.txt"))) {
    writer.write("Hello World!");
    writer.newLine();
    writer.write("This is Java.");
} catch (IOException e) {
    e.printStackTrace();
}
File Handling Example
import java.io.*;

public class FileExample {
    public static void main(String[] args) {
        // Write to file
        try (BufferedWriter writer = new BufferedWriter(new FileWriter("example.txt"))) {
            writer.write("Line 1");
            writer.newLine();
            writer.write("Line 2");
            System.out.println("File written successfully.");
        } catch (IOException e) {
            e.printStackTrace();
        }

        // Read from file
        try (BufferedReader reader = new BufferedReader(new FileReader("example.txt"))) {
            System.out.println("File content:");
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

File Class

The java.io.File class provides methods for file operations:

File file = new File("test.txt");
file.exists();      // Check if file exists
file.createNewFile();  // Create new file
file.delete();      // Delete file
file.length();      // Get file size

Multithreading

Java supports multithreading - concurrent execution of two or more threads.

Creating Threads

There are two ways to create threads:

  1. Extend the Thread class
  2. Implement the Runnable interface
Thread Example
// Extending Thread class
class MyThread extends Thread {
    public void run() {
        for (int i = 1; i <= 5; i++) {
            System.out.println(Thread.currentThread().getName() + ": " + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

// Implementing Runnable interface
class MyRunnable implements Runnable {
    public void run() {
        for (int i = 1; i <= 5; i++) {
            System.out.println(Thread.currentThread().getName() + ": " + i);
        }
    }
}

public class ThreadExample {
    public static void main(String[] args) {
        // Thread class
        MyThread thread1 = new MyThread();
        thread1.start();

        // Runnable interface
        Thread thread2 = new Thread(new MyRunnable());
        thread2.start();

        // Main thread continues
        for (int i = 1; i <= 5; i++) {
            System.out.println("Main thread: " + i);
        }
    }
}

Thread Synchronization

When multiple threads access shared resources, synchronization is needed to prevent race conditions.

class Counter {
    private int count = 0;

    // Synchronized method
    public synchronized void increment() {
        count++;
    }

    public int getCount() {
        return count;
    }
}

public class SyncExample {
    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();

        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });

        t1.start();
        t2.start();
        t1.join();
        t2.join();

        System.out.println("Count: " + counter.getCount());  // 2000
    }
}

Generics

Generics enable types (classes and interfaces) to be parameters when defining classes, interfaces, and methods.

Generic Class

class Box<T> {
    private T content;

    public void setContent(T content) {
        this.content = content;
    }

    public T getContent() {
        return content;
    }
}

public class GenericExample {
    public static void main(String[] args) {
        Box<String> stringBox = new Box<>();
        stringBox.setContent("Hello");
        System.out.println(stringBox.getContent());

        Box<Integer> intBox = new Box<>();
        intBox.setContent(123);
        System.out.println(intBox.getContent());
    }
}

Generic Methods

public static <T> void printArray(T[] array) {
    for (T element : array) {
        System.out.print(element + " ");
    }
    System.out.println();
}

// Usage
Integer[] intArray = {1, 2, 3};
String[] stringArray = {"A", "B", "C"};
printArray(intArray);
printArray(stringArray);

Bounded Type Parameters

public static <T extends Number> double sum(T num1, T num2) {
    return num1.doubleValue() + num2.doubleValue();
}

Benefits of Generics

  • Stronger type checks at compile time
  • Elimination of casts
  • Enabling programmers to implement generic algorithms

Java Best Practices

Follow these best practices to write clean, efficient, and maintainable Java code.

Coding Standards

  • Follow Java naming conventions (camelCase, PascalCase)
  • Use meaningful names for classes, methods, and variables
  • Keep classes and methods small and focused
  • Use proper indentation and formatting
  • Write Javadoc comments for public APIs

Object-Oriented Principles

  • Favor composition over inheritance
  • Program to interfaces, not implementations
  • Follow SOLID principles:
    • Single Responsibility Principle
    • Open/Closed Principle
    • Liskov Substitution Principle
    • Interface Segregation Principle
    • Dependency Inversion Principle
  • Use immutable objects where possible

Exception Handling

  • Use specific exceptions rather than generic ones
  • Don't catch exceptions unless you can handle them
  • Don't ignore exceptions
  • Use try-with-resources for AutoCloseable resources
  • Include meaningful error messages

Performance Tips

  • Avoid creating unnecessary objects
  • Use StringBuilder for string concatenation in loops
  • Initialize collections with proper capacity
  • Use primitive types when possible
  • Consider concurrent collections for multi-threaded scenarios
Good Practice Example
/**
 * Calculates the area of a rectangle.
 *
 * @param  length the length of the rectangle
 * @param  width the width of the rectangle
 * @return  the area of the rectangle
 * @throws  IllegalArgumentException if length or width is negative
 */
public static double calculateArea(double length, double width) {
    if (length < 0 || width < 0) {
        throw new IllegalArgumentException("Dimensions cannot be negative");
    }
    return length * width;
}

// Using try-with-resources
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
    // Read file
} catch (IOException e) {
    System.err.println("Error reading file: " + e.getMessage());
}

Modern Java Features

  • Use var for local variables (Java 10+)
  • Use pattern matching for instanceof (Java 16+)
  • Use records for immutable data classes (Java 16+)
  • Use sealed classes for restricted hierarchies (Java 17+)
  • Use text blocks for multi-line strings (Java 15+)

Conclusion

Congratulations on completing this comprehensive Java programming guide! You've learned the fundamentals of Java including:

  • Java syntax and basic programming concepts
  • Object-oriented programming principles
  • Data structures and collections
  • Exception handling and file operations
  • Multithreading and concurrency
  • Generics and type safety
  • Java best practices and coding standards

Next Steps

To continue your Java journey:

  1. Practice regularly - Solve coding challenges on platforms like LeetCode or HackerRank
  2. Build projects - Apply your knowledge to real-world applications
  3. Explore Java ecosystems:
    • Enterprise Development (Spring, Jakarta EE)
    • Android Development
    • Big Data (Hadoop, Spark)
    • Web Development
  4. Contribute to open source - Collaborate on Java projects
  5. Stay updated - Follow Java Enhancement Proposals (JEPs)