Lecture 1 / 12
Lecture 01 · Foundations

What is Java?

No prerequisites

Introduction

Java is a high-level, class-based, object-oriented programming language that is designed to have as few implementation dependencies as possible. The slogan “Write Once, Run Anywhere” reflects its capability to run on any device that has a Java Virtual Machine (JVM).

Java was originally developed by Sun Microsystems and later acquired by Oracle Corporation. Over the years, Java became one of the most trusted programming languages for enterprise software, Android development, cloud applications, and large-scale systems.

Today, Java powers millions of applications worldwide — from banking systems and e-commerce platforms to desktop applications and backend APIs.

Why Learn Java?

  • Ubiquitous – used in Android, enterprise back-ends, desktop apps and big-data ecosystems.
  • Strong static typing helps catch many bugs at compile time.
  • Rich standard library and a huge ecosystem of third-party libraries.
  • Excellent tooling (IDEA, Eclipse, VS Code, Maven/Gradle, JUnit).

Java is also considered one of the best languages for beginners because its syntax is clean, structured, and widely documented. Learning Java builds a strong programming foundation that makes it easier to learn other languages later.

✅ Quick fact
The first public release of Java (JDK 1.0) appeared in 1996.

Where is Java Used?

  • Android Development: Many Android applications use Java.
  • Web Applications: Large-scale backend systems often use Java frameworks like Spring.
  • Desktop Software: Java can build cross-platform desktop applications.
  • Enterprise Systems: Banking, insurance, and large corporations rely heavily on Java.
  • Cloud & Big Data: Technologies like Hadoop and Apache Kafka are built using Java.
🌍 Industry Insight
Java consistently ranks among the world's most popular programming languages because of its stability, scalability, and massive developer ecosystem.

Hello World – Your First Java Program

Save the following as HelloWorld.java and run it from the command line:

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

Compile and run:

javac HelloWorld.java   # produces HelloWorld.class
java HelloWorld         # prints “Hello, World!”

Understanding the Program

Let us break down the program line by line:

  • public class HelloWorld → Defines a class named HelloWorld.
  • main() → The entry point where program execution starts.
  • System.out.println() → Prints output to the console.
  • String[] args → Stores command-line arguments.
💡 Important
In Java, the file name must match the public class name exactly. That is why the file is named HelloWorld.java.
🎯 Exercise 1.1

Install the latest JDK, create the HelloWorld.java file, compile it and run it. Verify the output in your terminal.

Key Features of Java

  • Object-Oriented: Everything in Java revolves around objects and classes.
  • Platform Independent: Java code is compiled into bytecode that runs on the JVM.
  • Secure: No direct pointer access and includes built-in security features.
  • Robust: Strong memory management and exception handling.
  • Multithreaded: Supports concurrent execution of two or more threads.

Additional Advantages of Java

  • Automatic Garbage Collection: Java automatically manages memory allocation and cleanup.
  • Large Community: Millions of developers contribute tutorials, libraries, and tools.
  • Backward Compatibility: Older Java applications often continue to work on newer JVM versions.
  • Performance: Modern JVM optimizations make Java extremely fast.

How Java Works

Java follows a two-step execution process:

  1. Compilation: The Java source file (.java) is compiled into bytecode (.class) using the Java compiler (javac).
  2. Execution: The JVM interprets or compiles the bytecode into machine code that your system can execute.
💡 Did you know?
The JVM acts like a translator between Java bytecode and your operating system, making Java platform-independent.

JDK vs JRE vs JVM

Beginners often confuse these three important Java components. Understanding them early will help you later.

  • JVM (Java Virtual Machine) → Runs Java bytecode.
  • JRE (Java Runtime Environment) → Contains the JVM and libraries needed to run Java programs.
  • JDK (Java Development Kit) → Includes tools required to develop Java applications such as javac.
🧠 Easy Memory Trick
JDK = Develop Java Programs
JRE = Run Java Programs
JVM = Execute Java Bytecode

Basic Structure of a Java Program

  • Class: The main building block of a Java program.
  • Main Method: Entry point where execution begins.
  • Statements: Instructions executed by the program.

Java Syntax Rules

  • Java is case-sensitive.
  • Every statement usually ends with a semicolon (;).
  • Curly braces { } define blocks of code.
  • Program execution starts from the main() method.
Example.java
public class Example {
    public static void main(String[] args) {
        System.out.println("Learning Java");
    }
}

Common Errors Beginners Make

  • Forgetting to match the file name with the class name.
  • Missing semicolons (;) at the end of statements.
  • Incorrect capitalization (Java is case-sensitive).
  • Not installing or configuring the JDK properly.
⚠️ Common Mistake
Writing system.out.println() instead of System.out.println() will produce an error because Java is case-sensitive.

Best Practices for Beginners

  • Practice writing code daily instead of only reading theory.
  • Use meaningful class and variable names.
  • Read compiler error messages carefully.
  • Experiment with small programs frequently.
  • Focus on understanding concepts instead of memorizing syntax.
🎯 Exercise 1.2

Modify the HelloWorld program to print your name instead of "Hello, World!".

🎯 Exercise 1.3

Try printing multiple lines using System.out.println() and observe how output is displayed.

🚀 Challenge Exercise

Create a program named AboutMe.java that prints:

  • Your name
  • Your city
  • Your favorite programming language

Summary

In this lecture, you learned what Java is, why it is widely used, and how to write and run your first Java program. You also explored its key features, execution process, Java components, and the basic structure of a Java application.

In the next lecture, we will dive deeper into setting up the development environment, installing the JDK correctly, and preparing your system for Java development.

Lecture 02 · Foundations

Setting up the JDK

Requires: Lecture 01

Introduction

Before writing larger Java applications, you need a proper Java development environment. This includes installing the JDK (Java Development Kit), configuring your system, and choosing a suitable code editor or IDE.

In this lecture, you will learn how to install Java correctly, verify the installation, and prepare your machine for Java development.

What is the JDK?

The Java Development Kit (JDK) is the complete package required to create, compile, and run Java applications.

The JDK includes:

  • JVM (Java Virtual Machine) → Executes Java bytecode.
  • JRE (Java Runtime Environment) → Provides libraries required to run programs.
  • Java Compiler (javac) → Converts Java source code into bytecode.
  • Development Tools → Debuggers, documentation generators, and more.
💡 Important
If you only install the JRE, you can run Java applications but cannot compile your own Java programs.

Download & Install

Head to Eclipse Adoptium or Oracle JDK and download the appropriate bundle for your operating system.

Choose the installer version that matches your system architecture:

  • Windows: Usually .msi or .exe
  • macOS: Usually .pkg
  • Linux: Usually .tar.gz or package manager installation
✅ Recommendation
Beginners usually prefer Eclipse Adoptium because it provides free OpenJDK builds that are simple to install.

Installing on Windows

  1. Download the JDK installer.
  2. Run the installer and follow the setup wizard.
  3. Allow the installer to configure environment variables if prompted.
  4. Finish installation and restart your terminal.

Installing on macOS

  1. Download the macOS package.
  2. Open the installer package.
  3. Follow the installation instructions.
  4. Open Terminal and verify the installation.

Installing on Linux

Many Linux distributions provide OpenJDK through package managers.

Ubuntu / Debian
sudo apt update
sudo apt install openjdk-21-jdk

Verify Installation

After installation, open your terminal or command prompt and run:

java -version
javac -version
ℹ️ Expected output

Both commands should print the version number (e.g. java 21.0.1) and indicate that the JDK is correctly configured on your PATH.

Understanding PATH Variables

The PATH environment variable allows your operating system to locate Java commands such as java and javac from any terminal window.

If the terminal says:

'java' is not recognized as an internal or external command

then Java may not be correctly added to your system PATH.

⚠️ Common Beginner Problem
Installing Java successfully does not always mean the PATH variable is configured correctly. This is one of the most common setup mistakes beginners face.

IDE Recommendation

For a smoother learning experience, choose a Java IDE or code editor:

  • IntelliJ IDEA Community – Rich refactoring, smart code completion, debugging, and Maven/Gradle integration.
  • Eclipse – A classic Java IDE with extensive plugin support.
  • VS Code – Lightweight editor with the Java Extension Pack.
💡 Beginner Suggestion
IntelliJ IDEA Community Edition is often considered the easiest and most beginner-friendly Java IDE.

Creating Your First Java Project

Once your IDE is installed:

  1. Create a new Java project.
  2. Create a new Java class named Main.
  3. Add a main() method.
  4. Run the program using the IDE's Run button.
Main.java
public class Main {
    public static void main(String[] args) {
        System.out.println("Java setup successful!");
    }
}

Command Line vs IDE

Beginners often wonder whether they should use the terminal or an IDE. Both are useful and important.

  • Command Line: Helps understand how Java compilation works internally.
  • IDE: Speeds up development with autocomplete, debugging, and project tools.
🧠 Best Practice
Learn both approaches. Professional developers frequently use IDEs, but understanding terminal commands builds stronger fundamentals.

Common Installation Problems

  • Installing only the JRE instead of the full JDK
  • Incorrect PATH configuration
  • Using an outdated Java version
  • Multiple Java versions conflicting on the same system
  • Restarting neither the terminal nor the computer after installation

Useful Java Commands

Terminal Commands
java -version     # Shows installed Java version
javac -version    # Shows Java compiler version
java Main         # Runs a compiled Java class
javac Main.java   # Compiles Java source code
🎯 Exercise 2.1

Install your favourite IDE, open a new project, create a Main.java file with a main method, and run the “Hello World” program inside the IDE.

🎯 Exercise 2.2

Open your terminal and run:

java -version
javac -version

Verify that both commands display version information correctly.

🚀 Challenge Exercise

Create a Java program named EnvironmentCheck.java that prints:

  • Your Java version
  • Your operating system
  • Your user name

Research how to access system properties using System.getProperty().

Summary

In this lecture, you learned how to install the Java Development Kit, verify your installation, configure the PATH variable, and choose an IDE for Java development.

You also explored the differences between JDK, JRE, and JVM, along with common installation mistakes beginners encounter.

In the next lecture, we will begin working with variables, data types, and user input in Java.

Lecture 03 · Foundations

Variables & Data Types

Requires: Lecture 02

Introduction

Variables are one of the most fundamental concepts in programming. A variable is simply a named storage location used to hold data in memory.

In Java, every variable must have a specific data type. The data type determines:

  • What kind of data can be stored
  • How much memory is allocated
  • What operations can be performed on the value
💡 Real-World Analogy
Think of variables as labeled containers. Different containers store different types of things — numbers, text, or true/false values.

Declaring Variables

In Java, variables are declared using the following syntax:

Syntax.java
dataType variableName = value;

Example:

Example.java
int age = 25;
double price = 99.99;
String name = "Alice";

Primitive Types

Java has 8 primitive data types. Primitive types store simple values directly in memory.

Type Size Example
byte 8 bit byte b = 100;
short 16 bit short s = 20000;
int 32 bit int i = 123456;
long 64 bit long l = 123456789L;
float 32 bit float f = 3.14f;
double 64 bit double d = 3.14159;
char 16 bit (Unicode) char c = 'A';
boolean 1 bit (logical) boolean ok = true;

Integer Types

Integer types are used to store whole numbers without decimal points.

  • byte → Small memory usage
  • short → Slightly larger integers
  • int → Most commonly used integer type
  • long → Very large integer values
✅ Best Practice
Most Java programs use int for integers unless very large numbers are required.

Floating-Point Types

Floating-point types are used to store decimal numbers.

  • float → Less precision, uses less memory
  • double → Higher precision, more commonly used
⚠️ Important
Decimal numbers are treated as double by default. Add f at the end when using a float.
FloatExample.java
float value = 3.14f;
double pi = 3.1415926535;

Character Type

The char type stores a single Unicode character.

CharExample.java
char grade = 'A';
char symbol = '#';

Boolean Type

The boolean type stores only two values: true or false.

BooleanExample.java
boolean isLoggedIn = true;
boolean hasPermission = false;

Reference Types

Anything that is not a primitive type is called a reference type.

Reference types store memory addresses that point to objects.

Examples include:

  • String
  • Arrays
  • Classes and objects
  • Collections
🧠 Important Concept
Primitive variables store actual values directly, while reference variables store references to objects in memory.

Strings in Java

Strings are used to store text. In Java, strings are objects of the String class.

StringExample.java
String city = "London";
String message = "Welcome to Java";

VariablesDemo.java

VariablesDemo.java
public class VariablesDemo {
    public static void main(String[] args) {
        int age = 30;
        double price = 19.99;
        boolean isMember = true;
        String name = "Alice";

        System.out.println(name + ", age " + age);
    }
}

Type Conversion

Sometimes values must be converted from one data type to another.

Implicit Conversion

Java automatically converts smaller types into larger compatible types.

ImplicitConversion.java
int num = 100;
double result = num;

Explicit Conversion (Casting)

Larger types can be manually converted into smaller types using casting.

CastingExample.java
double value = 9.78;
int result = (int) value;
⚠️ Warning
Explicit casting may cause data loss. For example, converting 9.78 to int removes the decimal part.

Variable Naming Rules

  • Variable names are case-sensitive.
  • Names cannot start with numbers.
  • Spaces are not allowed.
  • Use meaningful names for readability.
GoodNaming.java
int studentAge = 20;
double accountBalance = 1500.75;

Common Beginner Mistakes

  • Using variables before initialization
  • Assigning incorrect data types
  • Forgetting quotes around strings
  • Using single quotes for strings instead of double quotes
  • Confusing = with ==
🎯 Exercise 3.1

Create a program that declares one variable of each primitive type, prints them, then swaps two integer values without using a third temporary variable.

🎯 Exercise 3.2

Create variables for:

  • Your name
  • Your age
  • Your height
  • Whether you are a student

Print all values using System.out.println().

🚀 Challenge Exercise

Create a simple billing program that stores:

  • Product name
  • Price
  • Quantity

Then calculate and print the total bill amount.

Summary

In this lecture, you learned about variables, primitive data types, reference types, type conversion, and variable naming rules.

Understanding data types is essential because every Java program relies heavily on storing and manipulating data correctly.

In the next lecture, we will explore operators and expressions in Java.

Lecture 04 · Foundations

Control Flow

Requires: Lecture 03

Introduction

Control flow determines how a program makes decisions and repeats tasks. Without control flow, Java programs would execute statements one after another without any logic or flexibility.

Using conditions and loops, programs can:

  • Make decisions
  • Repeat actions
  • Handle different situations dynamically
  • Process large amounts of data efficiently
💡 Real-World Analogy
Traffic lights are an example of control flow: if the light is green → move, else if yellow → slow down, else → stop.

Conditional Statements

Conditional statements allow programs to execute code only when certain conditions are true.

If / else

The if statement checks a condition. If the condition evaluates to true, the code block executes.

IfDemo.java
int score = 85;

if (score >= 90) {
    System.out.println("Grade A");
} else if (score >= 80) {
    System.out.println("Grade B");
} else {
    System.out.println("Needs improvement");
}

Understanding the Logic

  • if → Executes when the first condition is true
  • else if → Checks additional conditions
  • else → Executes if none of the conditions are true
✅ Best Practice
Use indentation and braces properly to make conditions easier to read and debug.

Nested If Statements

An if statement can exist inside another if statement. This is called nesting.

NestedIf.java
int age = 20;
boolean hasTicket = true;

if (age >= 18) {
    if (hasTicket) {
        System.out.println("Entry allowed");
    }
}

Comparison Operators

Conditions usually rely on comparison operators.

Operator Meaning
== Equal to
!= Not equal to
> Greater than
< Less than
>= Greater than or equal to
<= Less than or equal to

Logical Operators

Logical operators combine multiple conditions.

Operator Description
&& Logical AND
|| Logical OR
! Logical NOT
LogicalDemo.java
int age = 22;
boolean isStudent = true;

if (age >= 18 && isStudent) {
    System.out.println("Eligible for student discount");
}

Switch Statement

The switch statement is useful when comparing one value against multiple possible cases.

Switch (Java 17+ enhanced switch)

SwitchDemo.java
String day = "MONDAY";

String result = switch (day) {
    case "MONDAY", "TUESDAY", "WEDNESDAY" -> "Mid-week";
    case "THURSDAY", "FRIDAY" -> "Almost weekend";
    case "SATURDAY", "SUNDAY" -> "Weekend";
    default -> "Invalid day";
};

System.out.println(result);
🧠 Modern Java
Java 17 introduced enhanced switch expressions that are cleaner and safer than older switch syntax.

Loops

Loops allow code to repeat automatically until a condition becomes false.

  • for loop → Best for counting and fixed repetitions
  • enhanced for loop → Best for arrays and collections
  • while loop → Repeats while a condition is true
  • do-while loop → Executes at least once before checking the condition

For Loop

ForLoop.java
for (int i = 1; i <= 5; i++) {
    System.out.println(i);
}

Enhanced For Loop

Enhanced for loops simplify iteration through arrays and collections.

LoopDemo.java
int[] numbers = { 2, 4, 6, 8 };
int sum = 0;

for (int n : numbers) {
    sum += n;
}

System.out.println("Sum = " + sum);

While Loop

A while loop executes as long as its condition remains true.

WhileDemo.java
int count = 1;

while (count <= 5) {
    System.out.println(count);
    count++;
}

Do-While Loop

A do-while loop executes the block first, then checks the condition.

DoWhileDemo.java
int number = 1;

do {
    System.out.println(number);
    number++;
} while (number <= 3);

Break and Continue

Java provides special statements to control loop execution.

  • break → Exits the loop immediately
  • continue → Skips the current iteration
BreakContinue.java
for (int i = 1; i <= 10; i++) {

    if (i == 5) {
        continue;
    }

    if (i == 8) {
        break;
    }

    System.out.println(i);
}

Common Beginner Mistakes

  • Using = instead of == in conditions
  • Creating infinite loops accidentally
  • Forgetting curly braces in nested conditions
  • Using incorrect loop conditions
  • Confusing break and continue
⚠️ Infinite Loop Warning
Always ensure loop conditions eventually become false, otherwise the program may run forever.
🎯 Exercise 4.1

Write a program that prints the first 20 Fibonacci numbers using a while loop.

🎯 Exercise 4.2

Write a program that checks whether a number is even or odd using an if-else statement.

🎯 Exercise 4.3

Create a multiplication table generator using a for loop.

🚀 Challenge Exercise

Create a number guessing game where:

  • The program stores a secret number
  • The user repeatedly guesses the number
  • The program prints whether the guess is too high or too low
  • The loop ends when the correct number is guessed

Summary

In this lecture, you learned how Java programs make decisions and repeat tasks using conditions and loops.

You explored:

  • if-else statements
  • switch expressions
  • for, while, and do-while loops
  • break and continue statements

In the next lecture, we will begin working with methods and modular programming in Java.

Lecture 05 · Foundations

Methods

Requires: Lecture 04

Introduction

Methods are reusable blocks of code that perform specific tasks. They help organize programs into smaller, manageable pieces.

Instead of writing the same code repeatedly, developers create methods and call them whenever needed.

💡 Real-World Analogy
Think of a method like a coffee machine button. Pressing the button performs a predefined task automatically.

Why Methods Matter

  • Reduce code duplication
  • Improve readability
  • Make debugging easier
  • Encourage modular programming
  • Allow code reuse across projects

Method Syntax

A method in Java consists of: modifiers returnType name(parameters) { body }

MethodSyntax.java
accessModifier returnType methodName(parameters) {

    // method body

}

Understanding Method Components

Component Description
public Access modifier
static Belongs to the class instead of an object
int Return type
add Method name
(int a, int b) Parameters

Creating Methods

MathUtils.java
public class MathUtils {

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

    public static double average(int[] values) {

        int sum = 0;

        for (int v : values) {
            sum += v;
        }

        return (double) sum / values.length;
    }
}

Calling Methods

Methods do nothing until they are called.

MethodCall.java
int result = MathUtils.add(5, 10);

System.out.println(result);

Return Values

Methods can return values back to the caller using the return keyword.

The return type determines what type of value the method sends back.

✅ Important
If a method does not return anything, use the void return type.
VoidMethod.java
public static void greet() {
    System.out.println("Welcome!");
}

Method Parameters

Parameters allow methods to receive input values.

ParametersDemo.java
public static void displayName(String name) {

    System.out.println("Hello " + name);

}

Method Arguments vs Parameters

Term Meaning
Parameter Variable in the method definition
Argument Actual value passed to the method

Parameter Passing

  • Primitives are passed by value — the method receives a copy.
  • Objects are passed by reference value — the method receives a copy of the reference, allowing it to modify the object.
🧠 Key Concept
Changing a primitive inside a method does not affect the original variable outside the method.

Method Overloading

Method overloading allows multiple methods to share the same name but use different parameter lists.

Java identifies overloaded methods based on:

  • Number of parameters
  • Parameter types
  • Order of parameters
OverloadDemo.java
public class OverloadDemo {

    static int max(int a, int b) {
        return (a > b) ? a : b;
    }

    static double max(double a, double b) {
        return (a > b) ? a : b;
    }
}

Recursive Methods

A recursive method is a method that calls itself.

Recursion is commonly used for mathematical problems, trees, and algorithms.

RecursionDemo.java
public static int factorial(int n) {

    if (n == 1) {
        return 1;
    }

    return n * factorial(n - 1);
}
⚠️ Warning
Recursive methods must include a stopping condition, otherwise they can cause infinite recursion and stack overflow errors.

Scope of Variables

Variables declared inside methods are called local variables.

They can only be accessed within that method.

ScopeDemo.java
public static void test() {

    int number = 10;

    System.out.println(number);
}

Main Method

Every Java application starts execution from the main() method.

MainMethod.java
public static void main(String[] args) {

    System.out.println("Program started");

}

Common Beginner Mistakes

  • Forgetting the return statement
  • Using the wrong return type
  • Calling non-static methods incorrectly
  • Passing incorrect arguments
  • Creating recursive methods without a base case
🎯 Exercise 5.1

Write a utility class that provides overloaded factorial methods for int and long. Add a simple main method that demonstrates both.

🎯 Exercise 5.2

Create a method called isEven() that returns true if a number is even, otherwise returns false.

🎯 Exercise 5.3

Write a calculator program that uses separate methods for:

  • Addition
  • Subtraction
  • Multiplication
  • Division
🚀 Challenge Exercise

Build a menu-driven banking simulation using methods.

Include methods for:

  • Deposit
  • Withdraw
  • Check balance
  • Exit program

Summary

In this lecture, you learned how methods help organize and reuse code in Java.

You explored:

  • Method syntax
  • Parameters and return values
  • Method overloading
  • Recursion
  • Variable scope

Methods are one of the most important building blocks in Java programming. They are heavily used in every real-world application.

In the next lecture, we will begin learning Object-Oriented Programming (OOP) concepts in Java.

Lecture 06 · Core Concepts

Object-Oriented Programming

Requires: Lecture 05

Introduction

Object-Oriented Programming (OOP) is a programming paradigm based on the concept of objects.

Objects combine both:

  • Data → variables and fields
  • Behavior → methods and actions

Java is primarily an object-oriented programming language, and most real-world Java applications are built using OOP principles.

💡 Real-World Analogy
A car is an object. It has properties like color and speed, and behaviors like start(), brake(), and accelerate().

Why OOP Matters

  • Improves code organization
  • Encourages code reuse
  • Makes applications easier to maintain
  • Supports scalable software development
  • Helps teams collaborate efficiently

Core Pillars

  • Encapsulation – hide internal state behind private fields and expose behaviour via methods.
  • Inheritance – reuse code with extends.
  • Polymorphism – treat objects of different subclasses uniformly, often via interfaces.
  • Abstraction – define contracts with abstract classes or interfaces.

Classes and Objects

A class is a blueprint used to create objects.

An object is an instance of a class.

✅ Important
Classes define structure and behavior, while objects represent actual data in memory.

Class definition

Person.java
public class Person {

    private String name;
    private int age;

    public Person(String name, int age) {

        this.name = name;
        this.age = age;

    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public void birthday() {
        age++;
    }
}

Creating Objects

Objects are created using the new keyword.

ObjectDemo.java
Person person = new Person("Alice", 25);

System.out.println(person.getName());

Encapsulation

Encapsulation means hiding internal data and controlling access through methods.

In Java, this is commonly done using:

  • private fields
  • Getter methods
  • Setter methods
🧠 Why Encapsulation?
Encapsulation protects objects from invalid or unsafe modifications.

Getter and Setter Methods

GettersSetters.java
private double balance;

public double getBalance() {
    return balance;
}

public void setBalance(double value) {

    if (value >= 0) {
        balance = value;
    }
}

Constructors

Constructors are special methods used to initialize objects.

A constructor:

  • Has the same name as the class
  • Does not have a return type
  • Runs automatically when an object is created
✅ Constructor Tip
Constructors help ensure objects start in a valid state.

Inheritance

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

The child class uses the extends keyword.

Inheritance example

Employee.java
public class Employee extends Person {

    private String department;

    public Employee(String name,
                    int age,
                    String dept) {

        super(name, age);

        department = dept;
    }

    public String getDepartment() {
        return department;
    }
}

The super Keyword

The super keyword refers to the parent class.

It is commonly used to:

  • Call parent constructors
  • Access parent methods
  • Reuse inherited functionality

Method Overriding

Method overriding allows subclasses to provide their own implementation of inherited methods.

OverrideDemo.java
class Animal {

    void sound() {
        System.out.println("Animal sound");
    }
}

class Dog extends Animal {

    @Override
    void sound() {
        System.out.println("Bark");
    }
}

Polymorphism

Polymorphism allows one interface or parent class reference to represent many different object types.

PolymorphismDemo.java
Animal pet = new Dog();

pet.sound();
🧠 Dynamic Method Dispatch
Java decides which overridden method to execute at runtime, not compile time.

Abstraction

Abstraction focuses on hiding implementation details and showing only essential behavior.

Java supports abstraction using:

  • Abstract classes
  • Interfaces

Abstract Class Example

Shape.java
abstract class Shape {

    abstract double area();

}

Interface Example

Vehicle.java
interface Vehicle {

    void start();

}

Access Modifiers

Modifier Accessibility
public Accessible everywhere
private Accessible only within the same class
protected Accessible in subclasses and same package
default Accessible only within the same package

Composition vs Inheritance

Inheritance represents an "is-a" relationship, while composition represents a "has-a" relationship.

Example:

  • A Dog is an Animal → inheritance
  • A Car has an Engine → composition

Common Beginner Mistakes

  • Making everything public
  • Confusing classes and objects
  • Forgetting constructors
  • Using inheritance unnecessarily
  • Ignoring encapsulation principles
⚠️ OOP Advice
Good object-oriented design focuses on simplicity, readability, and maintainability.
🎯 Exercise 6.1

Model a simple library system: create a base class Item (with id, title) and subclasses Book and Magazine.

Add a method printInfo() that is overridden in each subclass.

🎯 Exercise 6.2

Create a class called BankAccount with:

  • Private balance field
  • Deposit method
  • Withdraw method
  • Getter method for balance
🎯 Exercise 6.3

Create an abstract class called Employee and subclasses:

  • Developer
  • Manager

Override a method called work().

🚀 Challenge Exercise

Build a mini school management system using OOP concepts.

Include:

  • Student class
  • Teacher class
  • Course class
  • Inheritance and polymorphism
  • Encapsulation using private fields

Summary

In this lecture, you explored the foundations of Object-Oriented Programming in Java.

You learned about:

  • Classes and objects
  • Encapsulation
  • Inheritance
  • Polymorphism
  • Abstraction
  • Constructors and access modifiers

OOP is one of the most important concepts in modern software development and is heavily used in enterprise Java applications, Android development, and backend systems.

In the next lecture, we will begin working with collections and advanced data handling in Java.

Lecture 07 · Core Concepts

Collections Framework

Requires: Lecture 06

Introduction to the Collections Framework

The Java Collections Framework is a powerful set of classes and interfaces used to store, organize, and manage groups of objects efficiently. Instead of manually creating arrays and complex data structures, Java provides ready-made implementations for common programming needs.

The framework includes dynamic lists, sets, maps, queues, iterators, sorting utilities, and algorithms that are optimized and widely used in real-world software development.

💡 Key Concept
Collections are dynamic data structures that can grow and shrink automatically during program execution.

Why Collections?

They provide well-tested, efficient implementations of common data structures (lists, sets, maps) plus a rich set of utility methods.

  • Dynamic sizing unlike fixed-size arrays
  • Built-in algorithms for sorting and searching
  • Improved code readability
  • Reusable and optimized implementations
  • Support for generics and type safety

Collection Hierarchy Overview

The Collections Framework is built using interfaces and classes.

Collection
 ├── List
 │    ├── ArrayList
 │    └── LinkedList
 │
 ├── Set
 │    ├── HashSet
 │    └── TreeSet
 │
 └── Queue
      └── PriorityQueue

Map
 ├── HashMap
 └── TreeMap

Different collection types are designed for different use cases.

Generics in Collections

Collections usually use Generics to specify the type of data they store.

ArrayList<String> names = new ArrayList<>();

This ensures type safety and prevents storing incorrect object types.

✅ Best Practice
Always use generics with collections to avoid unnecessary type casting and runtime errors.

List – ordered, duplicates allowed

A List stores elements in insertion order and allows duplicate values.

ListDemo.java
import java.util.*; // List, ArrayList

public class ListDemo {

    public static void main(String[] args) {

        List<String> names = new ArrayList<>();

        names.add("Alice");
        names.add("Bob");
        names.add("Alice");   // duplicate allowed

        for (String n : names) {
            System.out.println(n);
        }
    }
}

Common List Methods

names.add("Charlie");
names.remove("Bob");
names.get(0);
names.size();
names.contains("Alice");
Method Purpose
add() Adds an element
remove() Removes an element
get() Accesses an element by index
size() Returns collection size
contains() Checks if an element exists

ArrayList vs LinkedList

ArrayList LinkedList
Fast random access Fast insertions/removals
Uses dynamic arrays Uses linked nodes
Better for reading data Better for modifying data frequently

Set – unique elements

A Set stores unique elements and automatically removes duplicates.

SetDemo.java
import java.util.*; // HashSet

public class SetDemo {

    public static void main(String[] args) {

        Set<Integer> primes = new HashSet<>();

        primes.add(2);
        primes.add(3);
        primes.add(2);  // ignored – duplicate

        System.out.println(primes);
    }
}

HashSet vs TreeSet

HashSet TreeSet
Unordered Sorted automatically
Faster operations Slightly slower
Uses hashing Uses tree structure

Map – key/value pairs

A Map stores data as key-value pairs.

MapDemo.java
import java.util.*; // Map, HashMap

public class MapDemo {

    public static void main(String[] args) {

        Map<String, Integer> scores = new HashMap<>();

        scores.put("Alice", 90);
        scores.put("Bob", 85);
        scores.put("Alice", 95); // overwrites previous

        System.out.println(scores);
    }
}

Common Map Methods

scores.put("Charlie", 88);
scores.get("Alice");
scores.remove("Bob");
scores.containsKey("Alice");
scores.containsValue(95);

HashMap vs TreeMap

HashMap TreeMap
Unordered keys Sorted keys
Faster performance Maintains natural ordering
Uses hashing Uses balanced trees

Iterating Through Collections

Collections can be traversed using loops or iterators.

for (String name : names) {
    System.out.println(name);
}

Enhanced for-loops are cleaner and easier to read.

Sorting Collections

The Collections utility class provides sorting methods.

Collections.sort(names);

You can also sort in reverse order:

Collections.sort(names, Collections.reverseOrder());

Queue Interface

A Queue processes elements in FIFO (First In First Out) order.

Queue<Integer> queue = new LinkedList<>();

queue.add(10);
queue.add(20);

System.out.println(queue.poll());

poll() removes and returns the first element.

Collections Utility Class

The Collections class provides useful helper methods.

Collections.max(numbers);
Collections.min(numbers);
Collections.shuffle(numbers);

Common Beginner Mistakes

  • Using raw collections without generics
  • Choosing the wrong collection type
  • Forgetting that Sets remove duplicates
  • Accessing invalid indexes in Lists
  • Confusing HashMap ordering behavior
🚀 Real-World Insight
The Collections Framework is heavily used in backend systems, Android apps, enterprise software, APIs, databases, and game development.
🎯 Exercise 7.1

Implement a simple phone-book using a HashMap<String, String> where the key is a person’s name and the value is a phone number. Add methods to add, lookup and remove entries.

🎯 Exercise 7.2

Create an ArrayList<Integer> and write a program that sorts numbers in ascending and descending order.

🎯 Exercise 7.3

Create a HashSet<String> to store usernames and prevent duplicate registrations.

Lecture 08 · Core Concepts

Generics

Requires: Lecture 07

Introduction to Generics

Generics are one of Java’s most powerful features. They allow classes, interfaces, and methods to work with different data types while maintaining type safety.

Before Generics were introduced in Java 5, developers had to store objects using the Object class, which required manual casting and increased the chance of runtime errors.

💡 Key Concept
Generics allow you to write reusable and type-safe code that works with many different data types.

Why Generics?

They let you write type-safe collections and APIs without casting.

  • Improves code reusability
  • Eliminates unnecessary type casting
  • Provides compile-time type checking
  • Makes code cleaner and easier to maintain
  • Used heavily in the Collections Framework

Problem Without Generics

Before Generics, collections stored data as Object types.

WithoutGenerics.java
import java.util.*;

public class WithoutGenerics {

    public static void main(String[] args) {

        ArrayList list = new ArrayList();

        list.add("Hello");
        list.add(100);

        String text = (String) list.get(0);

        System.out.println(text);
    }
}

This approach is unsafe because incorrect casting can cause runtime exceptions.

Using Generics Properly

With Generics, you specify the exact type of data allowed.

GenericList.java
import java.util.*;

public class GenericList {

    public static void main(String[] args) {

        ArrayList<String> names = new ArrayList<>();

        names.add("Alice");
        names.add("Bob");

        String first = names.get(0);

        System.out.println(first);
    }
}

Now Java automatically ensures only String values can be stored.

✅ Best Practice
Always use Generics with collections to avoid unsafe casting and runtime type errors.

Generic Type Parameters

Generic classes use placeholder type names inside angle brackets <>.

Type Parameter Meaning
T Type
E Element
K Key
V Value
N Number

Simple generic class

Box.java
public class Box<T> {

    private T value;

    public Box(T value) {
        this.value = value;
    }

    public T get() {
        return value;
    }

    public void set(T value) {
        this.value = value;
    }
}

Creating Generic Objects

Box<String> textBox = new Box<>("Hello");
Box<Integer> numberBox = new Box<>(100);

System.out.println(textBox.get());
System.out.println(numberBox.get());

The same class works with multiple data types.

Generic Methods

Methods can also use Generics independently of the class.

GenericMethod.java
public class GenericMethod {

    public static <T>
    void printData(T value) {

        System.out.println(value);
    }

    public static void main(String[] args) {

        printData("Java");
        printData(500);
        printData(3.14);
    }
}

Using bounded type parameters

Restrict a type to subclasses of a given class or interface.

NumberUtils.java
public class NumberUtils {

    public static <T extends Number>
    double sum(List<T> list) {

        double total = 0;

        for (T n : list) {
            total += n.doubleValue();
        }

        return total;
    }
}

This method only accepts numeric types such as Integer, Double, or Float.

Wildcards in Generics

Wildcards make Generics more flexible.

List<?> items;

The ? symbol means “unknown type”.

Wildcard Description
? Any type
? extends Number Number or subclass
? super Integer Integer or parent class

Generic Interfaces

Interfaces can also use Generics.

interface Storage<T> {
    void save(T item);
    T load();
}

Type Erasure

Java implements Generics using a concept called Type Erasure.

During compilation, generic type information is removed and converted into regular Java bytecode. This means Generics provide compile-time safety but do not exist at runtime.

⚠️ Important Limitation
Because of type erasure, you cannot create objects like new T() directly inside generic classes.

Common Beginner Mistakes

  • Using raw types instead of generic types
  • Forgetting angle brackets <>
  • Using incorrect type parameters
  • Mixing incompatible generic types
  • Assuming Generics exist at runtime

Real-World Usage of Generics

Generics are heavily used throughout modern Java development.

  • Collections Framework
  • Spring Boot applications
  • REST APIs
  • Database frameworks like Hibernate
  • Reusable utility libraries
🎯 Exercise 8.1

Create a generic Pair<K,V> class that stores two values. Write a short demo that creates a Pair<String,Integer> and prints both elements.

🎯 Exercise 8.2

Create a generic method called display() that prints arrays of different types such as integers, strings, and doubles.

🎯 Exercise 8.3

Create a generic class called Storage<T> that stores and retrieves one object of any type.

Lecture 09 · Advanced

Streams & Lambdas (Java 8+)

Requires: Lecture 08

Introduction to Functional Programming in Java

Java 8 introduced one of the biggest upgrades in Java history: Lambda Expressions and the Stream API. These features allow developers to write cleaner, shorter, and more expressive code using a functional programming style.

Instead of manually writing loops and temporary variables, Streams allow operations such as filtering, mapping, sorting, and collecting data in a concise pipeline.

💡 Key Concept
Lambdas define behavior, while Streams process collections of data using that behavior.

What is a Lambda Expression?

A lambda expression is an anonymous function that can be passed as data.

It allows you to write compact code without creating separate classes for simple operations.

Lambda syntax

A lambda expression is an anonymous function that can be treated as an instance of a functional interface.

LambdaDemo.java
import java.util.function.*;

public class LambdaDemo {

    public static void main(String[] args) {

        Predicate<Integer> isEven = n -> n % 2 == 0;

        System.out.println(
            isEven.test(42)
        ); // true
    }
}

Understanding Lambda Structure

(parameters) -> expression
Part Purpose
(parameters) Input values
-> Lambda operator
expression Code to execute

More Lambda Examples

() -> System.out.println("Hello")

x -> x * x

(a, b) -> a + b

Lambdas become especially powerful when combined with collections and streams.

Functional Interfaces

A lambda expression works with a functional interface, which is an interface containing only one abstract method.

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

You can then provide implementations using lambdas:

Calculator add = (a, b) -> a + b;

System.out.println(add.operate(5, 3));

Common Built-in Functional Interfaces

Interface Purpose
Predicate<T> Returns true or false
Function<T,R> Transforms data
Consumer<T> Consumes data without returning
Supplier<T> Provides data

What is the Stream API?

The Stream API processes collections of data in a declarative and functional way.

Streams do not store data themselves — they operate on existing collections like lists and sets.

✅ Important
Streams are designed for data processing, not data storage.

Stream pipeline

Streams enable functional-style processing of sequences of elements.

StreamDemo.java
import java.util.stream.*;
import java.util.*;

public class StreamDemo {

    public static void main(String[] args) {

        List<Integer> numbers = Arrays.asList(
            1, 2, 3, 4, 5
        );

        int sum = numbers.stream()
                           .filter(n -> n % 2 == 0)
                           .mapToInt(n -> n * n)
                           .sum();

        System.out.println(
            "Result = " + sum
        );
    }
}

Understanding Stream Operations

Operation Purpose
filter() Select matching elements
map() Transform elements
sorted() Sort elements
collect() Store results
forEach() Iterate through elements

Filtering Data

List<Integer> nums = Arrays.asList(1,2,3,4,5,6);

nums.stream()
    .filter(n -> n % 2 == 0)
    .forEach(System.out::println);

The filter() method keeps only matching elements.

Mapping Data

The map() method transforms each element.

names.stream()
     .map(String::toUpperCase)
     .forEach(System.out::println);

Sorting Streams

numbers.stream()
       .sorted()
       .forEach(System.out::println);

You can also use custom comparators with lambdas.

numbers.stream()
       .sorted((a, b) -> b - a)
       .forEach(System.out::println);

Collecting Results

The collect() method converts stream results into collections.

List<String> result = names.stream()
                           .map(String::toUpperCase)
                           .collect(Collectors.toList());

Method References

Method references are a shorter form of lambdas.

names.forEach(System.out::println);

This is equivalent to:

names.forEach(name -> System.out.println(name));

Stream Pipeline Stages

A stream pipeline usually has three stages:

  1. Source → collection or array
  2. Intermediate operations → filter, map, sorted
  3. Terminal operation → collect, sum, forEach

Advantages of Streams

  • Cleaner and shorter code
  • Less manual looping
  • Easier data transformations
  • Supports parallel processing
  • Improved readability

Parallel Streams

Java can process streams in parallel using multiple CPU cores.

numbers.parallelStream()
       .forEach(System.out::println);
⚡ Performance Insight
Parallel streams can improve performance for large datasets, but they may introduce overhead for small tasks.

Common Beginner Mistakes

  • Trying to reuse a stream after a terminal operation
  • Using streams for extremely simple tasks unnecessarily
  • Confusing map() with filter()
  • Overusing parallel streams
  • Writing overly complex lambda expressions

Real-World Usage

Streams and Lambdas are heavily used in modern Java applications.

  • Spring Boot applications
  • REST APIs
  • Data processing systems
  • Backend enterprise software
  • Big-data pipelines
🎯 Exercise 9.1

Read a list of words from an array, convert them to uppercase, filter those longer than 5 characters, sort them alphabetically and print each on its own line — all using the Stream API.

🎯 Exercise 9.2

Create a list of integers and use streams to calculate the sum of all odd numbers.

🎯 Exercise 9.3

Create a lambda expression that checks whether a number is positive, negative, or zero.

Lecture 10 · Advanced

Exception Handling

Requires: Lecture 09

Checked vs Unchecked

  • Checked – compiler forces you to handle or declare (IOException, SQLException).
  • Unchecked – subclasses of RuntimeException (e.g. NullPointerException) need not be declared.

Try‑catch‑finally

ExceptionDemo.java
import java.io.*;

public class ExceptionDemo {
    public static void main(String[] args) {
        try {
            BufferedReader br = new BufferedReader(new FileReader("missing.txt"));
            System.out.println(br.readLine());
        } catch (FileNotFoundException e) {
            System.err.println("File not found!");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            System.out.println("Cleanup if necessary");
        }
    }
}

Custom exception

InvalidAgeException.java
public class InvalidAgeException extends Exception {
    public InvalidAgeException(String message) {
        super(message);
    }
}
🎯 Exercise 10.1

Create a BankAccount class with a withdraw(double amount) method. Throw a custom InsufficientFundsException when the balance would become negative, and write a driver program that catches and reports the error.

Lecture 11 · Advanced

Concurrency

Requires: Lecture 10

Threads basics

Two ways to create a thread:

  1. Extend Thread and override run().
  2. Implement Runnable (or Callable) and pass it to a Thread or an ExecutorService.
ThreadDemo.java
class MyTask implements Runnable {
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("Thread " + Thread.currentThread().getName() + ": " + i);
            try { Thread.sleep(500); } catch (InterruptedException e) { }
        }
    }
}

public class ThreadDemo {
    public static void main(String[] args) {
        Thread t1 = new Thread(new MyTask(), "Worker‑1");
        Thread t2 = new Thread(new MyTask(), "Worker‑2");
        t1.start();
        t2.start();
    }
}

Executor framework

Higher‑level API for managing thread pools.

ExecutorDemo.java
import java.util.concurrent.*;

public class ExecutorDemo {
    public static void main(String[] args) {
        ExecutorService pool = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 10; i++) {
            int id = i;
            pool.submit(() -> {
                System.out.println("Task " + id + " executed by " + Thread.currentThread().getName());
            });
        }
        pool.shutdown();
    }
}
🎯 Exercise 11.1

Implement a simple producer‑consumer pipeline using a BlockingQueue and two threads (one producing numbers, the other consuming and printing them). Use an ExecutorService to run both.

Lecture 12 · Swing FULL INTERFACE

Java Swing GUI Development

Requires: All Lectures
What is Swing?

Swing is Java's built-in GUI (Graphical User Interface) toolkit. It allows developers to create windows, buttons, menus, forms, tables, dialogs, and complete desktop applications.

Swing is part of the javax.swing package and works on Windows, Linux, and macOS.

Why Use Swing?

  • Create desktop applications.
  • Build forms and data-entry systems.
  • Create calculators and management systems.
  • Develop educational software.
  • Build database-driven applications.

Common Swing Components

Component Purpose
JFrame Main application window
JPanel Container for components
JButton Clickable button
JLabel Display text
JTextField Single-line input
JPasswordField Password input
JTextArea Multi-line input
JCheckBox Selection box
JRadioButton Single-choice option
JComboBox Dropdown menu
JTable Display tabular data

Your First Swing Program

import javax.swing.*;

public class Main {
    public static void main(String[] args) {

        JFrame frame = new JFrame("My First Window");

        frame.setSize(500, 300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

Understanding JFrame

Method Purpose
setSize() Set window size
setTitle() Set title
setVisible() Show window
setLocationRelativeTo() Center window
setResizable() Enable/disable resizing
add() Add component

Adding a Label

import javax.swing.*;

public class Main {

    public static void main(String[] args) {

        JFrame frame = new JFrame();

        JLabel label =
            new JLabel("Welcome to Swing");

        frame.add(label);

        frame.setSize(400,200);
        frame.setVisible(true);
    }
}

Creating a Button

import javax.swing.*;

public class Main {

    public static void main(String[] args) {

        JFrame frame = new JFrame();

        JButton btn =
            new JButton("Click Me");

        frame.add(btn);

        frame.setSize(400,200);
        frame.setVisible(true);
    }
}

Event Handling

Event handling allows Swing applications to react when users click buttons, type text, select menu items, or interact with components.

import javax.swing.*;
import java.awt.event.*;

public class Main {

    public static void main(String[] args) {

        JFrame frame = new JFrame();

        JButton btn =
            new JButton("Click");

        btn.addActionListener(
            new ActionListener() {

                public void actionPerformed(
                        ActionEvent e) {

                    JOptionPane.showMessageDialog(
                        null,
                        "Button Clicked!"
                    );
                }
            });

        frame.add(btn);

        frame.setSize(400,200);
        frame.setVisible(true);
    }
}

JTextField Example

import javax.swing.*;

public class Main {

    public static void main(String[] args) {

        JFrame frame = new JFrame();

        JTextField txt =
            new JTextField();

        txt.setBounds(50,50,200,30);

        frame.add(txt);

        frame.setLayout(null);
        frame.setSize(400,300);
        frame.setVisible(true);
    }
}

Layouts

Layout Managers automatically position components.

Layout Purpose
FlowLayout Left to right
BorderLayout North, South, East, West, Center
GridLayout Rows and columns
BoxLayout Vertical or horizontal arrangement
null Layout Manual positioning

FlowLayout Example

import javax.swing.*;
import java.awt.*;

public class Main {

    public static void main(String[] args) {

        JFrame frame = new JFrame();

        frame.setLayout(new FlowLayout());

        frame.add(new JButton("One"));
        frame.add(new JButton("Two"));
        frame.add(new JButton("Three"));

        frame.setSize(400,200);
        frame.setVisible(true);
    }
}

JCheckBox Example

JCheckBox java =
    new JCheckBox("Java");

JCheckBox python =
    new JCheckBox("Python");

frame.add(java);
frame.add(python);

JRadioButton Example

JRadioButton male =
    new JRadioButton("Male");

JRadioButton female =
    new JRadioButton("Female");

ButtonGroup group =
    new ButtonGroup();

group.add(male);
group.add(female);

JComboBox Example

String[] countries = {
    "India",
    "Zimbabwe",
    "South Africa"
};

JComboBox box =
    new JComboBox(countries);

frame.add(box);

JTextArea Example

JTextArea area =
    new JTextArea();

frame.add(area);

Message Dialogs

JOptionPane.showMessageDialog(
    null,
    "Operation Successful"
);

Input Dialog

String name =
    JOptionPane.showInputDialog(
        "Enter Name"
    );

Confirm Dialog

int result =
    JOptionPane.showConfirmDialog(
        null,
        "Delete Record?"
    );

Menu Bar Example

JMenuBar menuBar =
    new JMenuBar();

JMenu file =
    new JMenu("File");

JMenuItem exit =
    new JMenuItem("Exit");

file.add(exit);
menuBar.add(file);

frame.setJMenuBar(menuBar);

Building a Login Form

JLabel user =
    new JLabel("Username");

JTextField txtUser =
    new JTextField();

JLabel pass =
    new JLabel("Password");

JPasswordField txtPass =
    new JPasswordField();

JButton login =
    new JButton("Login");
Mini Project Ideas
  • Calculator
  • Student Registration System
  • Library Management System
  • Inventory System
  • Banking Application
  • Login System
  • Quiz Application
Exam Tips
  • Know all major Swing components.
  • Understand event handling.
  • Practice JFrame creation.
  • Learn layout managers.
  • Understand dialogs and forms.
Lecture Summary
  • Swing is Java's GUI toolkit.
  • JFrame is the main window.
  • Components are added to containers.
  • Layouts organize components.
  • Events make applications interactive.
  • Swing is commonly used for desktop applications.
Lecture 13 · Advanced

Interfaces & Abstract Classes

Requires: Lecture 12
Lesson Overview

Interfaces and abstract classes are important concepts in Object-Oriented Programming (OOP). They help create flexible, reusable, and maintainable code by defining common behavior for multiple classes.

What is an Abstract Class?

An abstract class is a class that cannot be instantiated directly. It serves as a blueprint for other classes.

Key Features of Abstract Classes
  • Declared using the abstract keyword.
  • Cannot create objects directly.
  • Can contain abstract and normal methods.
  • Can have constructors and variables.
  • Used when classes share common functionality.

Abstract Method

An abstract method has no body and must be implemented by subclasses.

abstract class Animal {
    abstract void makeSound();
}

Example: Abstract Class

abstract class Animal {

    abstract void makeSound();

    void sleep() {
        System.out.println("Sleeping...");
    }
}

class Dog extends Animal {

    void makeSound() {
        System.out.println("Bark");
    }
}

public class Main {
    public static void main(String[] args) {

        Dog d = new Dog();

        d.makeSound();
        d.sleep();
    }
}

Output

Bark
Sleeping...

What is an Interface?

An interface is a completely abstract blueprint that defines what a class must do without specifying how it does it.

Key Features of Interfaces
  • Declared using the interface keyword.
  • Contains abstract methods by default.
  • Supports multiple inheritance.
  • Cannot create objects directly.
  • Implemented using the implements keyword.

Creating an Interface

interface Vehicle {
    void start();
}

Implementing an Interface

interface Vehicle {
    void start();
}

class Car implements Vehicle {

    public void start() {
        System.out.println("Car Started");
    }
}

public class Main {
    public static void main(String[] args) {

        Car c = new Car();
        c.start();
    }
}

Output

Car Started

Multiple Interface Implementation

A class can implement multiple interfaces, which helps achieve multiple inheritance.

interface Camera {
    void takePhoto();
}

interface MusicPlayer {
    void playMusic();
}

class Smartphone implements Camera, MusicPlayer {

    public void takePhoto() {
        System.out.println("Photo Taken");
    }

    public void playMusic() {
        System.out.println("Playing Music");
    }
}

Abstract Class vs Interface

Feature Abstract Class Interface
Methods Abstract + Concrete Mainly Abstract
Variables Normal Variables Allowed Constants Only
Constructors Allowed Not Allowed
Inheritance Single Inheritance Multiple Inheritance
Keyword extends implements

When to Use an Abstract Class

  • When classes share common code.
  • When you want partial implementation.
  • When subclasses should inherit state and behavior.

When to Use an Interface

  • When unrelated classes need common behavior.
  • When multiple inheritance is required.
  • When defining a contract for classes.
Real-World Examples
  • Abstract Class: Animal, Vehicle, Employee
  • Interface: Printable, Runnable, Comparable
  • Smartphone: Camera + Music Player + Internet Device
Key Takeaways
  • Abstract classes provide partial implementation.
  • Interfaces define contracts for classes.
  • Abstract methods must be implemented by subclasses.
  • Interfaces support multiple inheritance.
  • Both improve flexibility and code reusability.
Lecture 14 · Advanced

Enums & Annotations

Requires: Lecture 13

Content coming soon...

Lecture 15 · Advanced

File I/O & NIO

Requires: Lecture 14
Lesson Overview

File I/O (Input/Output) allows Java programs to read and write data from files. Java provides two major approaches:

  • Classic File I/O (java.io package)
  • NIO (New Input/Output - java.nio package)

Why File Handling?

  • Store data permanently.
  • Read configuration files.
  • Save application settings.
  • Create logs and reports.
  • Process large datasets.

Java File Class

The File class represents files and directories.

import java.io.File;

public class Main {
    public static void main(String[] args) {

        File file = new File("student.txt");

        System.out.println(file.exists());
    }
}

Creating a File

import java.io.File;
import java.io.IOException;

public class Main {

    public static void main(String[] args)
            throws IOException {

        File file =
            new File("data.txt");

        if(file.createNewFile()) {
            System.out.println("File Created");
        } else {
            System.out.println("Already Exists");
        }
    }
}

Writing to a File (FileWriter)

import java.io.FileWriter;

public class Main {

    public static void main(String[] args)
            throws Exception {

        FileWriter writer =
            new FileWriter("notes.txt");

        writer.write("Hello Java!");

        writer.close();

        System.out.println("Written Successfully");
    }
}

Appending Data

FileWriter writer =
    new FileWriter("notes.txt", true);

writer.write("\nNew Line Added");

writer.close();

Reading Files (Scanner)

import java.io.File;
import java.util.Scanner;

public class Main {

    public static void main(String[] args)
            throws Exception {

        File file =
            new File("notes.txt");

        Scanner sc =
            new Scanner(file);

        while(sc.hasNextLine()) {
            System.out.println(sc.nextLine());
        }

        sc.close();
    }
}

BufferedWriter

BufferedWriter improves performance by reducing disk access.

import java.io.*;

BufferedWriter writer =
    new BufferedWriter(
        new FileWriter("data.txt")
    );

writer.write("Fast Writing");

writer.close();

BufferedReader

import java.io.*;

BufferedReader reader =
    new BufferedReader(
        new FileReader("data.txt")
    );

String line;

while((line = reader.readLine()) != null) {
    System.out.println(line);
}

reader.close();

Binary Files

Binary files store raw bytes instead of text.

FileOutputStream

import java.io.*;

FileOutputStream out =
    new FileOutputStream("file.bin");

out.write(65);

out.close();

FileInputStream

import java.io.*;

FileInputStream in =
    new FileInputStream("file.bin");

int data = in.read();

System.out.println(data);

in.close();

Introduction to NIO

What is NIO?

NIO (New Input/Output) was introduced to provide faster, more scalable file operations and better support for large files.

Important NIO Classes

Class Purpose
Path Represents a file path
Paths Create Path objects
Files File operations
DirectoryStream Directory traversal

Creating a Path

import java.nio.file.*;

Path path =
    Paths.get("data.txt");

System.out.println(path);

Writing Files with NIO

import java.nio.file.*;
import java.util.*;

Path path =
    Paths.get("data.txt");

Files.write(
    path,
    Arrays.asList(
        "Java",
        "Python",
        "C++"
    )
);

Reading Files with NIO

import java.nio.file.*;
import java.util.*;

Path path =
    Paths.get("data.txt");

List<String> lines =
    Files.readAllLines(path);

for(String line : lines) {
    System.out.println(line);
}

Copying Files

Path source =
    Paths.get("source.txt");

Path target =
    Paths.get("backup.txt");

Files.copy(
    source,
    target
);

Moving Files

Files.move(
    Paths.get("old.txt"),
    Paths.get("new.txt")
);

Deleting Files

Files.delete(
    Paths.get("temp.txt")
);

Creating Directories

Files.createDirectory(
    Paths.get("Students")
);

Exception Handling Example

try {

    Files.delete(
        Paths.get("data.txt")
    );

} catch(IOException e) {

    System.out.println(
        "Error: " + e.getMessage()
    );
}

File I/O vs NIO

Feature File I/O NIO
Package java.io java.nio
Performance Good Better
Large Files Limited Excellent
Modern API No Yes
Best Practices
  • Always close file resources.
  • Use try-with-resources when possible.
  • Handle exceptions properly.
  • Prefer NIO for modern applications.
  • Validate file paths before access.

Try-With-Resources Example

try(BufferedReader reader =
        new BufferedReader(
            new FileReader("data.txt"))) {

    String line;

    while((line = reader.readLine()) != null) {
        System.out.println(line);
    }

} catch(IOException e) {
    e.printStackTrace();
}
Key Takeaways
  • File I/O enables reading and writing files.
  • FileWriter and Scanner are common text-file tools.
  • BufferedReader and BufferedWriter improve performance.
  • NIO provides modern, efficient file operations.
  • Files and Paths simplify file management.
  • Always handle exceptions and close resources.
Lecture 16 · Advanced

Networking & Sockets

Requires: Lecture 15
Lesson Overview

Networking allows Java applications to communicate over a network. Java provides powerful networking APIs for creating client-server applications, chat systems, file transfer applications, and web services.

What is Networking?

Networking is the process of exchanging data between computers or devices. Java supports networking through the java.net package.

Common Networking Terms

Term Description
IP Address Unique address of a device on a network
Port Communication endpoint on a device
Protocol Rules for communication
Client Requests services
Server Provides services
Socket Endpoint for communication

What is a Socket?

A socket is a communication endpoint that allows two programs to exchange data over a network.

Socket Communication
  1. Server starts and listens on a port.
  2. Client connects to the server.
  3. Data is exchanged between client and server.
  4. Connection is closed.

Important Networking Classes

Class Purpose
InetAddress Represents IP addresses
Socket Client-side communication
ServerSocket Server-side communication
URL Represents web resources
URLConnection Connection to URL resources

Getting Local Host Information

import java.net.*;

public class Main {

    public static void main(String[] args)
            throws Exception {

        InetAddress ip =
            InetAddress.getLocalHost();

        System.out.println(ip);
        System.out.println(ip.getHostName());
        System.out.println(ip.getHostAddress());
    }
}

Getting Website IP Address

import java.net.*;

public class Main {

    public static void main(String[] args)
            throws Exception {

        InetAddress ip =
            InetAddress.getByName("google.com");

        System.out.println(ip);
    }
}

Client-Server Architecture

How It Works

The server waits for connections. The client connects to the server. Once connected, both can exchange information.

Creating a Server

import java.net.*;
import java.io.*;

public class Server {

    public static void main(String[] args)
            throws Exception {

        ServerSocket server =
            new ServerSocket(5000);

        System.out.println("Server Started");

        Socket socket =
            server.accept();

        System.out.println("Client Connected");

        server.close();
    }
}

Creating a Client

import java.net.*;

public class Client {

    public static void main(String[] args)
            throws Exception {

        Socket socket =
            new Socket("localhost", 5000);

        System.out.println(
            "Connected to Server"
        );

        socket.close();
    }
}

Sending Data from Client

PrintWriter out =
    new PrintWriter(
        socket.getOutputStream(),
        true
    );

out.println("Hello Server");

Receiving Data on Server

BufferedReader in =
    new BufferedReader(
        new InputStreamReader(
            socket.getInputStream()
        )
    );

String message =
    in.readLine();

System.out.println(message);

Simple Chat Example

// Client sends
out.println("Hello!");

// Server receives
String msg = in.readLine();
System.out.println(msg);

Reading Data from a URL

import java.net.*;
import java.io.*;

public class Main {

    public static void main(String[] args)
            throws Exception {

        URL url =
            new URL(
                "https://example.com"
            );

        BufferedReader reader =
            new BufferedReader(
                new InputStreamReader(
                    url.openStream()
                )
            );

        String line;

        while((line = reader.readLine())
                != null) {

            System.out.println(line);
        }

        reader.close();
    }
}

UDP vs TCP

Feature TCP UDP
Connection Required Not Required
Reliability High Lower
Speed Slower Faster
Examples Web, Email, Banking Gaming, Streaming

Creating a UDP Socket

import java.net.*;

DatagramSocket socket =
    new DatagramSocket();

Sending UDP Data

byte[] data =
    "Hello".getBytes();

InetAddress ip =
    InetAddress.getByName(
        "localhost"
    );

DatagramPacket packet =
    new DatagramPacket(
        data,
        data.length,
        ip,
        6000
    );

socket.send(packet);

Exception Handling

try {

    Socket socket =
        new Socket(
            "localhost",
            5000
        );

} catch(IOException e) {

    System.out.println(
        "Connection Failed"
    );
}
Networking Best Practices
  • Always close sockets after use.
  • Handle exceptions properly.
  • Validate incoming data.
  • Use threads for multiple clients.
  • Never trust external network input.

Real-World Applications

  • Chat Applications
  • Online Games
  • File Sharing Systems
  • Web Browsers
  • Email Services
  • Video Streaming Platforms
  • Banking Systems
Key Takeaways
  • Java networking is provided by the java.net package.
  • Sockets enable communication between applications.
  • ServerSocket creates servers.
  • Socket creates client connections.
  • TCP is reliable while UDP is faster.
  • Networking powers modern internet applications.
Lecture 17 · Professional

JDBC & Databases

Requires: Lecture 16
What is JDBC?

JDBC (Java Database Connectivity) is a Java API that allows Java applications to communicate with databases such as MySQL, PostgreSQL, Oracle, and SQLite. JDBC acts as a bridge between Java programs and relational databases.

Why Use Databases?

  • Store data permanently.
  • Manage large amounts of information efficiently.
  • Perform searches and filtering using SQL.
  • Support multi-user applications.
  • Provide data security and integrity.
JDBC Architecture
  1. Java Application
  2. JDBC API
  3. JDBC Driver
  4. Database Server

Steps to Connect Java with MySQL

Prerequisites
  • Java JDK installed
  • MySQL Server installed
  • MySQL Connector/J JDBC Driver
  • Database created in MySQL

Step 1: Import JDBC Package

import java.sql.*;

Step 2: Establish Connection

String url = "jdbc:mysql://localhost:3306/school";
String username = "root";
String password = "";

Connection con =
    DriverManager.getConnection(url, username, password);

Step 3: Create Statement

Statement stmt = con.createStatement();

Step 4: Execute SQL Query

ResultSet rs =
    stmt.executeQuery("SELECT * FROM students");

Step 5: Process Results

while(rs.next()) {
    System.out.println(
        rs.getInt("id") + " " +
        rs.getString("name")
    );
}

Step 6: Close Resources

rs.close();
stmt.close();
con.close();

Complete Example

import java.sql.*;

public class JDBCExample {
    public static void main(String[] args) {

        try {
            String url =
                "jdbc:mysql://localhost:3306/school";

            Connection con =
                DriverManager.getConnection(
                    url, "root", ""
                );

            Statement stmt =
                con.createStatement();

            ResultSet rs =
                stmt.executeQuery(
                    "SELECT * FROM students"
                );

            while(rs.next()) {
                System.out.println(
                    rs.getInt("id") + " - " +
                    rs.getString("name")
                );
            }

            rs.close();
            stmt.close();
            con.close();

        } catch(Exception e) {
            System.out.println(e);
        }
    }
}

CRUD Operations

Operation SQL Command
Create INSERT
Read SELECT
Update UPDATE
Delete DELETE

Insert Example

String sql =
    "INSERT INTO students(name) VALUES('John')";

stmt.executeUpdate(sql);

Update Example

String sql =
    "UPDATE students SET name='Mike' WHERE id=1";

stmt.executeUpdate(sql);

Delete Example

String sql =
    "DELETE FROM students WHERE id=1";

stmt.executeUpdate(sql);
Security Warning

Avoid building SQL queries by directly concatenating user input. This can lead to SQL Injection attacks. Use PreparedStatement instead.

PreparedStatement Example

String sql =
    "SELECT * FROM students WHERE id=?";

PreparedStatement ps =
    con.prepareStatement(sql);

ps.setInt(1, 5);

ResultSet rs = ps.executeQuery();
Key Takeaways
  • JDBC connects Java applications to databases.
  • Connections are created using DriverManager.
  • Statements execute SQL commands.
  • ResultSet stores query results.
  • PreparedStatement improves security and performance.
  • Always close database resources after use.
Lecture 18 · Professional

Unit Testing (JUnit)

Requires: Lecture 17

Content coming soon...

Lecture 19 · Professional

Design Patterns

Requires: Lecture 18

Content coming soon...

Lecture 20 · Professional

Build Tools (Maven & Gradle)

Requires: Lecture 19

Content coming soon...

Lecture 21 · Professional

Introduction to Spring Boot

Requires: Lecture 20

Content coming soon...

Lecture 22 · Professional

Final Project — Enterprise Java App

Requires: All Previous

Content coming soon...