Back Back

Java Programming Complete Guide

Master Java from its history and basic concepts to advanced object-oriented programming with practical examples, detailed explanations, and interactive quizzes.

History of Java

Definition

Java's history traces its development as a versatile programming language designed for portability and reliability across platforms.

Key Milestones

Java was developed by Sun Microsystems, with significant contributions from James Gosling, often called the "father of Java." Here's a brief timeline:

  • 1991: Project Green began at Sun Microsystems to create a language for consumer electronic devices.
  • 1995: Java 1.0 was officially released, introducing "Write Once, Run Anywhere" (WORA) with the Java Virtual Machine (JVM).
  • 1997: Java gained popularity for applets in web browsers.
  • 2006: Java SE 5 introduced major features like generics and annotations.
  • 2010: Oracle acquired Sun Microsystems, continuing Java's development.
  • 2023: Java 21 introduced virtual threads and improved performance features.

Java's evolution continues with regular updates, making it a cornerstone for enterprise applications, Android development, and more.

Introduction to Java

Definition

Java is a high-level, class-based, object-oriented programming language designed to be platform-independent and robust, with minimal implementation dependencies.

What is Java?

Java is widely used for building enterprise-level applications, mobile apps, and web services due to its versatility and portability.

Key features:

  • Platform Independent: Code runs on any device with a JVM.
  • Object-Oriented: Based on OOP principles like encapsulation and inheritance.
  • Secure: Features like bytecode verification ensure safety.
  • Multithreaded: Supports concurrent execution of tasks.
  • High Performance: Optimized by the JVM's Just-In-Time (JIT) compiler.

Java Hello World Program

The traditional first program in Java demonstrates basic syntax:


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

Explanation:

  • public class HelloWorld: Defines a class named HelloWorld.
  • public static void main(String[] args): The entry point of the program.
  • System.out.println(): Outputs text to the console.

Java Basics

Data Types

Definition: Data types specify the type and size of data that can be stored in a variable.

Java has two categories of data types:

Primitive Types:

  • byte: 8-bit integer (-128 to 127)
  • short: 16-bit integer (-32,768 to 32,767)
  • int: 32-bit integer (-2^31 to 2^31-1)
  • long: 64-bit integer (-2^63 to 2^63-1)
  • float: 32-bit floating-point
  • double: 64-bit floating-point
  • char: 16-bit Unicode character
  • boolean: true or false

Reference Types:

  • Objects: Instances of classes
  • Arrays: Collections of elements
  • Strings: Immutable sequences of characters

int age = 25;
double price = 19.99;
char grade = 'A';
boolean isJavaFun = true;
String name = "Alice";
                    

Variables and Tokens

Definition: Variables are named memory locations for storing data, and tokens are the smallest units in a Java program.

Variable Declaration:


// Declaration and initialization
int count = 10;

// Declaration only
double temperature;

// Multiple variables
int x = 5, y = 10, z = 15;
                    

Java Tokens:

  • Keywords: Reserved words (e.g., class, public)
  • Identifiers: Names for variables, methods, or classes
  • Literals: Fixed values (e.g., 100, "Hello")
  • Operators: Symbols for operations (e.g., +, -, *)
  • Separators: Punctuation (e.g., ;, ,, {})

Operators

Definition

Operators are symbols that perform operations on variables and values.

Types of Operators

Arithmetic Operators

Perform mathematical operations.

  • +: Addition
  • -: Subtraction
  • *: Multiplication
  • /: Division
  • %: Modulus (remainder)

int a = 10, b = 3;
System.out.println(a + b); // 13
System.out.println(a % b); // 1
                            

Relational Operators

Compare two values.

  • ==: Equal to
  • !=: Not equal to
  • >: Greater than
  • <: Less than
  • >=: Greater than or equal to
  • <=: Less than or equal to

int x = 5, y = 10;
System.out.println(x > y); // false
System.out.println(x <= y); // true
                            

Logical Operators

Combine boolean expressions.

  • &&: Logical AND
  • ||: Logical OR
  • !: Logical NOT

boolean a = true, b = false;
System.out.println(a && b); // false
System.out.println(a || b); // true
                            

Assignment Operators

Assign values to variables.

  • =: Assign
  • +=: Add and assign
  • -=: Subtract and assign
  • *=: Multiply and assign
  • /=: Divide and assign

int x = 10;
x += 5; // x = 15
                            

Bitwise Operators

Operate on bits of integers.

  • &: Bitwise AND
  • |: Bitwise OR
  • ^: Bitwise XOR
  • ~: Bitwise NOT
  • <<: Left shift
  • >>: Right shift

int a = 5; // 0101
int b = 3; // 0011
System.out.println(a & b); // 1 (0001)
                            

Other Operators

Include ternary and instanceof operators.

  • ?:: Ternary (conditional)
  • instanceof: Checks object type

int age = 20;
String result = age >= 18 ? "Adult" : "Minor";
System.out.println(result); // Adult
                            

Control Structures

Conditional Statements

Definition: Conditional statements control program flow based on boolean conditions.

Types of conditional statements:


// if statement
if (age >= 18) {
    System.out.println("You are an adult");
}

// if-else statement
if (score >= 50) {
    System.out.println("Pass");
} else {
    System.out.println("Fail");
}

// if-else-if ladder
if (score >= 90) {
    System.out.println("A");
} else if (score >= 80) {
    System.out.println("B");
} else {
    System.out.println("C or below");
}

// switch statement
switch (day) {
    case 1: System.out.println("Monday"); break;
    case 2: System.out.println("Tuesday"); break;
    default: System.out.println("Invalid day");
}

// Nested if
if (age >= 18) {
    if (hasLicense) {
        System.out.println("Can drive");
    }
}
                    

Loops

Definition: Loops execute a block of code repeatedly based on a condition.

Types of loops:


// for loop (known number of iterations)
for (int i = 0; i < 5; i++) {
    System.out.println(i);
}

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

// while loop (condition-based)
int j = 0;
while (j < 5) {
    System.out.println(j);
    j++;
}

// do-while loop (executes at least once)
int k = 0;
do {
    System.out.println(k);
    k++;
} while (k < 5);
                    

Object-Oriented Programming (OOP)

Introduction to OOP

Overview: Object-Oriented Programming (OOP) is a programming paradigm centered around objects rather than functions. It organizes software design around data, or objects, and their interactions, promoting modularity, reusability, and maintainability.

Key Benefits:

  • Modularity: Encapsulating data and behavior into objects reduces complexity.
  • Reusability: Inheritance and polymorphism enable code reuse.
  • Scalability: OOP makes it easier to maintain and expand large codebases.
  • Flexibility: Abstraction allows for flexible and adaptable designs.

Classes and Objects

Definition: A class defines the structure and behavior of objects, acting as a blueprint. Objects are instances of a class, representing specific entities with attributes (data) and methods (behavior).

Example: Below is a comprehensive example of a Car class with attributes, a constructor, and methods.


public class Car {
    // Attributes
    private String model;
    private int year;
    private double speed;

    // Constructor
    public Car(String model, int year) {
        this.model = model;
        this.year = year;
        this.speed = 0.0;
    }

    // Methods
    public void accelerate(double increment) {
        if (increment > 0) {
            speed += increment;
            System.out.println(model + " is now moving at " + speed + " km/h");
        }
    }

    public void displayInfo() {
        System.out.println("Model: " + model + ", Year: " + year + ", Speed: " + speed + " km/h");
    }

    // Main method for testing
    public static void main(String[] args) {
        Car myCar = new Car("Toyota", 2020);
        myCar.displayInfo();
        myCar.accelerate(50.0);
        myCar.displayInfo();
    }
}
            

Explanation: The Car class includes private attributes, a constructor to initialize objects, and methods to manipulate and display data. The main method demonstrates object creation and usage.

OOP Principles

Overview: OOP is built on four core principles: Encapsulation, Inheritance, Polymorphism, and Abstraction. These principles enable robust and flexible software design.

Encapsulation

Definition: Encapsulation bundles data and methods within a class, restricting direct access to some components to ensure data integrity.

Benefits: Protects data, enhances maintainability, and reduces system complexity.


public class BankAccount {
    private double balance;
    private String accountNumber;

    // Constructor
    public BankAccount(String accountNumber, double initialBalance) {
        this.accountNumber = accountNumber;
        this.balance = initialBalance > 0 ? initialBalance : 0;
    }

    public void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
            System.out.println("Deposited: $" + amount);
        } else {
            System.out.println("Invalid deposit amount");
        }
    }

    public void withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
            System.out.println("Withdrawn: $" + amount);
        } else {
            System.out.println("Invalid withdrawal amount");
        }
    }

    public double getBalance() {
        return balance;
    }

    // Main method for testing
    public static void main(String[] args) {
        BankAccount account = new BankAccount("12345", 1000.0);
        account.deposit(500.0);
        account.withdraw(200.0);
        System.out.println("Balance: $" + account.getBalance());
    }
}
                    

Inheritance

Definition: Inheritance enables a class (subclass) to inherit attributes and methods from another class (superclass), promoting code reuse.

Benefits: Reduces redundancy and supports hierarchical relationships.


public class Vehicle {
    protected String brand;
    protected int year;

    public Vehicle(String brand, int year) {
        this.brand = brand;
        this.year = year;
    }

    public void honk() {
        System.out.println("Honk honk!");
    }
}

public class Car extends Vehicle {
    private String model;

    public Car(String brand, int year, String model) {
        super(brand, year);
        this.model = model;
    }

    public void displayInfo() {
        System.out.println("Brand: " + brand + ", Model: " + model + ", Year: " + year);
    }

    // Main method for testing
    public static void main(String[] args) {
        Car car = new Car("Honda", 2022, "Civic");
        car.honk();
        car.displayInfo();
    }
}
                    

Polymorphism

Definition: Polymorphism allows objects of different classes to be treated as objects of a common superclass, with methods behaving differently based on the object type.

Types: Compile-time (method overloading) and runtime (method overriding).


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

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

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

// Testing polymorphism
public class Main {
    public static void main(String[] args) {
        Animal animal1 = new Dog();
        Animal animal2 = new Cat();
        animal1.sound();
        animal2.sound();
    }
}
                    

Abstraction

Definition: Abstraction simplifies complex systems by exposing only essential features while hiding implementation details.

Implementation: Achieved using abstract classes or interfaces.


abstract class Shape {
    protected String color;

    public Shape(String color) {
        this.color = color;
    }

    abstract double area();
    abstract String getDescription();
}

class Circle extends Shape {
    double radius;

    public Circle(String color, double radius) {
        super(color);
        this.radius = radius;
    }

    @Override
    double area() {
        return Math.PI * radius * radius;
    }

    @Override
    String getDescription() {
        return "Circle with color " + color + " and radius " + radius;
    }
}

// Testing abstraction
public class Main {
    public static void main(String[] args) {
        Shape circle = new Circle("Red", 5.0);
        System.out.println(circle.getDescription());
        System.out.println("Area: " + circle.area());
    }
}
                    

Comprehensive Example: Library Management System

Scenario: A simple library system demonstrating all OOP principles with classes for books and a library.


// Abstract class for library items
abstract class LibraryItem {
    protected String title;
    protected String itemId;

    public LibraryItem(String title, String itemId) {
        this.title = title;
        this.itemId = itemId;
    }

    abstract void displayDetails();
}

// Book class inheriting LibraryItem
class Book extends LibraryItem {
    private String author;
    private boolean isAvailable;

    public Book(String title, String itemId, String author) {
        super(title, itemId);
        this.author = author;
        this.isAvailable = true;
    }

    @Override
    void displayDetails() {
        System.out.println("Book: " + title + ", ID: " + itemId + ", Author: " + author + ", Available: " + isAvailable);
    }

    public void borrow() {
        if (isAvailable) {
            isAvailable = false;
            System.out.println("Book borrowed: " + title);
        } else {
            System.out.println("Book is not available");
        }
    }

    public void returnBook() {
        isAvailable = true;
        System.out.println("Book returned: " + title);
    }
}

// Library class to manage books
class Library {
    private Book[] books;
    private int count;

    public Library(int capacity) {
        books = new Book[capacity];
        count = 0;
    }

    public void addBook(Book book) {
        if (count < books.length) {
            books[count++] = book;
            System.out.println("Added book: " + book.title);
        } else {
            System.out.println("Library is full");
        }
    }

    public void displayBooks() {
        for (int i = 0; i < count; i++) {
            books[i].displayDetails();
        }
    }
}

// Main class to test the library system
public class Main {
    public static void main(String[] args) {
        Library library = new Library(2);
        Book book1 = new Book("1984", "B001", "George Orwell");
        Book book2 = new Book("To Kill a Mockingbird", "B002", "Harper Lee");

        library.addBook(book1);
        library.addBook(book2);
        library.displayBooks();

        book1.borrow();
        library.displayBooks();
        book1.returnBook();
        library.displayBooks();
    }
}
                    

Explanation: This example demonstrates:

  • Abstraction: LibraryItem defines abstract behavior.
  • Inheritance: Book extends LibraryItem.
  • Encapsulation: Private attributes and public methods in Book and Library.
  • Polymorphism: displayDetails is overridden in Book.

Exception Handling

Definition

Exception handling in Java manages runtime errors to maintain normal program flow.

Try-Catch Block

The try block contains code that might throw an exception, and the catch block handles it.


try {
    int[] arr = {1, 2, 3};
    System.out.println(arr[10]); // ArrayIndexOutOfBoundsException
} catch (ArrayIndexOutOfBoundsException e) {
    System.out.println("Error: " + e.getMessage());
}
                    

Types of Exceptions

  • Checked Exceptions: Handled at compile time (e.g., IOException).
  • Unchecked Exceptions: Occur at runtime (e.g., NullPointerException).

try {
    String str = null;
    System.out.println(str.length()); // NullPointerException
} catch (NullPointerException e) {
    System.out.println("Error: Cannot call method on null object");
}
                    

Finally Block

The finally block executes regardless of whether an exception is thrown.


try {
    int result = 10 / 0; // ArithmeticException
} catch (ArithmeticException e) {
    System.out.println("Error: Division by zero");
} finally {
    System.out.println("This will always execute");
}
                    

Collections Framework

Definition

The Java Collections Framework provides a set of classes and interfaces to handle collections of objects, such as lists, sets, and maps.

Common Collections

ArrayList

Resizable array implementation of the List interface.


import java.util.ArrayList;

ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
System.out.println(list); // [Apple, Banana]
                            

HashMap

Stores key-value pairs.


import java.util.HashMap;

HashMap<String, Integer> map = new HashMap<>();
map.put("Alice", 25);
map.put("Bob", 30);
System.out.println(map); // {Alice=25, Bob=30}
                            

Input and Output in Java

Definition

Input and Output (I/O) in Java refers to the process of receiving data from the user (input) and displaying data to the user (output). Java provides multiple classes to handle I/O operations, with Scanner and BufferedReader being commonly used for reading input, and System.out for output.

Output in Java

Java uses the System.out object to send output to the console. The most common methods are print(), println(), and printf().

Key Output Methods:

  • System.out.print(): Prints text without a newline.
  • System.out.println(): Prints text with a newline.
  • System.out.printf(): Formats text using format specifiers (e.g., %d for integers, %s for strings).

public class OutputExample {
    public static void main(String[] args) {
        int age = 25;
        String name = "Alice";
        
        // Using print
        System.out.print("Hello, ");
        System.out.print(name); // Output: Hello, Alice
        
        // Using println
        System.out.println(); // Adds newline
        System.out.println("Age: " + age); // Output: Age: 25
        
        // Using printf
        System.out.printf("Name: %s, Age: %d", name, age); // Output: Name: Alice, Age: 25
    }
}
                    

Explanation:

  • print(): Outputs text without moving to the next line.
  • println(): Outputs text and adds a newline at the end.
  • printf(): Allows formatted output with placeholders like %s (String), %d (integer), %f (float).

Scanner Class

Definition: The Scanner class in the java.util package is used to read input from various sources, such as the console, files, or strings. It provides methods to parse different data types like integers, doubles, and strings.

Common Scanner Methods:

  • next(): Reads the next token (word) as a String.
  • nextLine(): Reads an entire line as a String.
  • nextInt(): Reads the next integer.
  • nextDouble(): Reads the next double.
  • nextBoolean(): Reads the next boolean.
  • hasNext(): Checks if more input is available.

Syntax:


import java.util.Scanner;

Scanner scanner = new Scanner(System.in);
                    

Example:


import java.util.Scanner;

public class ScannerExample {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        System.out.print("Enter your name: ");
        String name = scanner.nextLine();
        
        System.out.print("Enter your age: ");
        int age = scanner.nextInt();
        
        System.out.print("Enter your height (in meters): ");
        double height = scanner.nextDouble();
        
        System.out.printf("Name: %s, Age: %d, Height: %.2f meters", name, age, height);
        
        scanner.close(); // Close scanner to prevent resource leak
    }
}
                    

Explanation:

  • Scanner scanner = new Scanner(System.in): Creates a Scanner object to read from the console.
  • nextLine(): Reads a full line of text, including spaces.
  • nextInt() and nextDouble(): Parse numeric input.
  • scanner.close(): Frees system resources (good practice).

BufferedReader Class

Definition: The BufferedReader class in the java.io package reads text from a character-input stream, buffering characters to reduce access to the underlying system. It is efficient for reading large amounts of text and is commonly used with InputStreamReader for console input.

Common BufferedReader Methods:

  • readLine(): Reads a line of text as a String.
  • read(): Reads a single character as an integer.
  • close(): Closes the stream and releases resources.

Syntax:


import java.io.BufferedReader;
import java.io.InputStreamReader;

BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
                    

Example:


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class BufferedReaderExample {
    public static void main(String[] args) {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            
            System.out.print("Enter your name: ");
            String name = reader.readLine();
            
            System.out.print("Enter your age: ");
            String ageInput = reader.readLine();
            int age = Integer.parseInt(ageInput);
            
            System.out.print("Enter your height (in meters): ");
            String heightInput = reader.readLine();
            double height = Double.parseDouble(heightInput);
            
            System.out.printf("Name: %s, Age: %d, Height: %.2f meters", name, age, height);
            
            reader.close(); // Close reader to prevent resource leak
        } catch (IOException e) {
            System.out.println("Error reading input: " + e.getMessage());
        }
    }
}
                    

Explanation:

  • BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)): Creates a BufferedReader to read from the console.
  • readLine(): Reads a full line of text.
  • Integer.parseInt() and Double.parseDouble(): Convert string input to numeric types.
  • try-catch: Handles IOException, which is required for BufferedReader operations.
  • reader.close(): Frees system resources.

Scanner vs BufferedReader

Both Scanner and BufferedReader are used for input, but they have different use cases:

  • Scanner: Easier to use, supports parsing of different data types directly, but slower for large inputs due to regular expression parsing.
  • BufferedReader: More efficient for reading large amounts of text, requires manual parsing for non-string data, and needs exception handling.

When to use:

  • Use Scanner for simple programs or when parsing multiple data types is needed.
  • Use BufferedReader for performance-critical applications or when reading large text inputs.

Test Your Knowledge

1. What is the correct way to declare a Java main method?

A) public static int main(String[] args)
B) public static void main(String[] args)
C) public void main(String[] args)
D) static void main(String[] args)

2. Which of these is NOT a primitive data type in Java?

A) int
B) float
C) String
D) boolean

3. What is the output of this code?


public class Test {
    public static void main(String[] args) {
        int x = 5;
        System.out.println(x++); // Post-increment
        System.out.println(++x); // Pre-increment
    }
}
                
A) 5 then 6
B) 5 then 7
C) 6 then 6
D) 6 then 7

4. Which keyword is used to inherit a class in Java?

A) implements
B) extends
C) super
D) this

5. What is the output of this code?


public class Test {
    public static void main(String[] args) {
        String str = "Hello";
        System.out.println(str.substring(1, 4));
    }
}
                
A) Hell
B) ello
C) Hel
D) lo

Try It Yourself

Practice Online

Try these exercises in an online Java compiler:

Exercise 1: Calculator

Create a simple calculator that can add, subtract, multiply, and divide two numbers.


public class Calculator {
    public static void main(String[] args) {
        // Implement calculator logic
    }
}
                        

Exercise 2: Student Class

Create a Student class with name, age, and grade fields, then create objects.


public class Student {
    // Fields
    // Constructor
    // Methods
}

public class Main {
    public static void main(String[] args) {
        // Create Student objects
    }
}
                        

Exercise 3: ArrayList Manipulation

Create an ArrayList of integers, add elements, and compute their sum.


import java.util.ArrayList;

public class ArrayListSum {
    public static void main(String[] args) {
        // Create ArrayList, add elements, compute sum
    }
}
                        

Exercise 4: Exception Handling

Write a program that handles a division by zero exception.


public class Division {
    public static void main(String[] args) {
        // Implement division with exception handling
    }
}
                        

Exercise 5: User Input Processor

Write a program that uses Scanner to read a user's name and age, then prints a formatted greeting using printf.


import java.util.Scanner;

public class InputProcessor {
    public static void main(String[] args) {
        // Implement Scanner-based input processing
    }
}
                        

Try our recommended online Java compiler:

Open Programiz Java Compiler

Download Basic Java Notes

View PDF Notes Download PDF Notes