Skip to content

Latest commit

 

History

History
1922 lines (1415 loc) · 38.2 KB

File metadata and controls

1922 lines (1415 loc) · 38.2 KB

📘 JAVA COMPLETE REVISION NOTES

OOPs, Exception Handling, Threads, JDBC, Collections & Generics

Exam-Focused | Question-Aligned | Code-Ready


TABLE OF CONTENTS

  1. OOPs & Exception Handling
  2. Threads & Multithreading
  3. JDBC - Java Database Connectivity
  4. Collections, Wrapper Classes & Generics


OOPs & EXCEPTION HANDLING

1️⃣ Characteristics of OOP (Very Important)

OOP is based on four pillars:

  1. Encapsulation - Data hiding
  2. Inheritance - Acquiring properties
  3. Polymorphism - One name, many forms
  4. Abstraction - Hiding implementation

2️⃣ Polymorphism

👉 One name, many forms

Types of Polymorphism:

  1. Compile-time Polymorphism (Method Overloading)
  2. Run-time Polymorphism (Method Overriding)

🔹 Compile-time Polymorphism → Method Overloading

Method Overloading

Same method name but:

  • Different number of parameters OR
  • Different data types
class MathOp {
    int add(int a, int b) {
        return a + b;
    }

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

🧠 Rules:

  • Return type alone cannot overload
  • Happens at compile time
  • Parameter order/type/count must differ

3️⃣ Constructors

👉 Constructor is used to initialize objects

  • Constructor name = Class name
  • No return type
  • Automatically called when object is created
class Student {
    int id;
    String name;

    Student() {
        id = 0;
        name = "NA";
    }
}

🔹 Constructor Overloading

Multiple constructors with different parameters.

class Student {
    int id;
    String name;

    // Default Constructor
    Student() {
        id = 0;
        name = "NA";
    }

    // Parameterized Constructor
    Student(int i, String n) {
        id = i;
        name = n;
    }
}

4️⃣ this Keyword

👉 Refers to current object

Uses of this:

  1. Differentiate instance & local variables
  2. Call another constructor (Constructor chaining)
  3. Pass current object as parameter
class Student {
    int id;
    String name;

    Student(int id, String name) {
        this.id = id;           // Differentiating
        this.name = name;
    }
    
    void display() {
        System.out.println(this.id);
    }
}

5️⃣ static Keyword

Belongs to class, not object.

Can be:

  • static variable
  • static method
  • static block
class Test {
    static int x = 10;         // Class variable
    int y = 20;                // Instance variable

    static void show() {       // Class method
        System.out.println(x);
    }
    
    static {                   // Static block
        System.out.println("Executes once when class loads");
    }
}

🧠 Rules:

  • Static method cannot use non-static data directly
  • Static block executes once when class loads
  • Static variables are shared among all objects

6️⃣ Inheritance

👉 One class acquires properties of another class 👉 Uses extends keyword

class A {                      // Parent/Super class
    int x = 10;
}

class B extends A {            // Child/Sub class
    int y = 20;
}

🔹 Types of Inheritance in Java

Type Supported Example
Single B extends A
Multilevel C extends B extends A
Hierarchical B,C both extend A
Multiple ❌ (via class) NOT allowed with classes
Hybrid ❌ (via class) NOT allowed with classes

✔️ Multiple inheritance is supported using interface


7️⃣ super Keyword

Used to:

  1. Access parent class variable
  2. Call parent class method
  3. Call parent class constructor
class A {
    int x = 10;
    
    void show() {
        System.out.println("Parent");
    }
}

class B extends A {
    int x = 20;

    void show() {
        System.out.println(super.x);        // Access parent variable
        super.show();                        // Call parent method
    }
}

8️⃣ Method Overriding (Run-time Polymorphism)

👉 Same method name + same parameters in inheritance 👉 Decided at runtime based on object type

class A {
    void show() {
        System.out.println("A");
    }
}

class B extends A {
    @Override
    void show() {
        System.out.println("B");
    }
}

class Test {
    public static void main(String[] args) {
        A obj = new B();       // Reference of A, object of B
        obj.show();            // Calls B's show() - Runtime polymorphism
    }
}

🧠 Rules:

  • Method signature must be same
  • Cannot reduce visibility (public → private not allowed)
  • Return type can be covariant (subclass)
  • Achieves runtime/dynamic polymorphism

9️⃣ Abstract Class

👉 A class that cannot be instantiated 👉 Can have abstract + non-abstract methods

abstract class Shape {
    abstract void area();          // Abstract method
    
    void display() {               // Non-abstract method
        System.out.println("Shape");
    }
}

class Circle extends Shape {
    @Override
    void area() {
        System.out.println("Area of circle");
    }
}

🧠 Key Points:

  • Cannot create object: Shape s = new Shape();
  • Can have constructors
  • Can have instance variables
  • Child class MUST implement all abstract methods

🔟 Interface

👉 Used to achieve 100% abstraction 👉 Supports multiple inheritance

interface Shape {
    void area();
    void perimeter();
}

interface Drawable {
    void draw();
}

class Circle implements Shape, Drawable {
    public void area() {
        System.out.println("Area");
    }
    
    public void perimeter() {
        System.out.println("Perimeter");
    }
    
    public void draw() {
        System.out.println("Drawing");
    }
}

🧠 Abstract Class vs Interface:

Feature Abstract Class Interface
Constructors ✅ Can have ❌ Cannot have
Instance variables ✅ Can have ❌ Only static/final
Methods Mixed abstract + concrete All abstract (Java 8+: default/static)
Inheritance Single (extends) Multiple (implements)
Abstraction Partial (0-100%) Full (100%)
Access public, protected, private Only public

⚠️ EXCEPTION HANDLING (VERY IMPORTANT)


1️⃣ What is an Exception?

👉 An unwanted event that interrupts program execution.

Exceptions prevent abrupt program termination.


2️⃣ Exception Hierarchy

Throwable (Base class for all throwables)
 ├── Exception (Recoverable)
 │    ├── Checked Exceptions
 │    │    ├── IOException
 │    │    └── SQLException
 │    └── Unchecked Exceptions (RuntimeException)
 │         ├── ArithmeticException
 │         ├── NullPointerException
 │         └── ArrayIndexOutOfBoundsException
 └── Error (Unrecoverable - JVM related)
      ├── StackOverflowError
      └── OutOfMemoryError

3️⃣ Types of Exceptions

🔹 Checked Exceptions

  • Checked at compile time
  • Must be handled or declared
  • Examples:
    • IOException
    • SQLException
    • FileNotFoundException
void readFile() throws IOException {
    // Code that may throw IOException
}

🔹 Unchecked Exceptions

  • Occur at runtime
  • Not mandatory to handle
  • Examples:
    • ArithmeticException (10/0)
    • NullPointerException (null reference)
    • ArrayIndexOutOfBoundsException (invalid index)
    • StringIndexOutOfBoundsException

4️⃣ Exception Handling Keywords

Keyword Use
try Contains code that may throw exception
catch Handles the exception
finally Executes always (cleanup code)
throw Explicitly throw exception
throws Declare exception in method signature

5️⃣ try–catch Example

try {
    int a = 10 / 0;              // May throw exception
} 
catch(ArithmeticException e) {
    System.out.println("Error: " + e.getMessage());
}
catch(Exception e) {
    System.out.println("General exception");
}
finally {
    System.out.println("This always executes");
}

🧠 Key Points:

  • Multiple catch blocks can exist
  • General exception catch must be last
  • Finally block executes even if exception occurs or not

6️⃣ User Defined Exception

Steps:

  1. Create class extending Exception
  2. Throw it using throw keyword
class LowAmountException extends Exception {
    LowAmountException(String msg) {
        super(msg);
    }
}

class BankAccount {
    int balance = 10000;
    
    void withdraw(int amount) throws LowAmountException {
        if(amount > balance) {
            throw new LowAmountException("Insufficient balance");
        }
        balance -= amount;
        System.out.println("Withdrawal successful");
    }
}

class Test {
    public static void main(String[] args) {
        BankAccount acc = new BankAccount();
        try {
            acc.withdraw(15000);
        } 
        catch(LowAmountException e) {
            System.out.println(e.getMessage());
        }
    }
}

🎯 Exception Handling - Final Tips

✔️ throw vs throws:

  • throw - explicitly throw exception in code
  • throws - declare exception in method signature

✔️ finally always executes except when:

  • System.exit(0)
  • JVM crashes

✔️ try-with-resources (Java 7+):

try(FileReader fr = new FileReader("file.txt")) {
    // Code - auto closes resource
}


🧵 THREADS & MULTITHREADING


1. What is a Thread?

A thread is a lightweight sub-process. It represents a separate path of execution within a program.

  • A Java program always has at least one thread (main thread)
  • Multiple threads allow parallel execution

Real-life Example:

  • One thread downloads a file
  • Another thread shows progress bar simultaneously

2. Why Multithreading?

Multithreading is used to:

  • Improve program performance
  • Use CPU efficiently
  • Perform multiple tasks simultaneously (apparent parallelism)
  • Reduce overall program execution time
  • Better resource utilization

3. Thread Life Cycle (Thread States)

A thread goes through the following states:

1️⃣ New State

Thread object is created but start() is not called yet.

Thread t = new Thread();

2️⃣ Runnable State

Thread is ready to run and waiting for CPU allocation from thread scheduler.

t.start();                 // Thread moves to Runnable state

3️⃣ Running State

Thread scheduler assigns CPU and thread executes run() method.


4️⃣ Waiting/Blocked State

Thread temporarily stops due to:

  • sleep(milliseconds) - thread sleeps
  • wait() - thread waits for notification
  • I/O operation - waiting for I/O completion
  • join() - waiting for another thread to complete
Thread.sleep(1000);        // Sleep for 1 second
t.join();                  // Wait for thread t to complete

5️⃣ Terminated/Dead State

Thread completes execution or is explicitly stopped.


4. Thread Priority

Thread priority decides importance, not guaranteed execution order.

Priority Constants:

Constant Value Use
MIN_PRIORITY 1 Lowest priority
NORM_PRIORITY 5 Default
MAX_PRIORITY 10 Highest priority
Thread t = new Thread();
t.setPriority(Thread.MAX_PRIORITY);
System.out.println(t.getPriority());

🧠 Note: Priority behavior depends on OS and JVM. It's not guaranteed.


5. Thread Operations (Important Methods)

Method Description
start() Starts new thread (calls run internally)
run() Code to be executed by thread
sleep(ms) Pauses thread for milliseconds
join() Main thread waits for this thread
yield() Gives CPU to another thread of same priority
isAlive() Checks if thread is running
interrupt() Interrupts the thread
stop() Stops the thread (deprecated)

🧠 Critical: start() creates new thread, run() directly does NOT create thread.


6. Creating Threads in Java

Method 1: Extending Thread Class

class MyThread extends Thread {
    public void run() {
        for(int i = 1; i <= 5; i++) {
            System.out.println("Thread: " + i);
            try {
                Thread.sleep(500);
            } catch(Exception e) {}
        }
    }
}

class Test {
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
        
        t1.start();              // Start thread 1
        t2.start();              // Start thread 2
    }
}

🧠 Key Point:

  • start() creates a new thread
  • Calling run() directly does NOT create a thread

Method 2: Implementing Runnable Interface (Recommended ✅)

class MyRunnable implements Runnable {
    public void run() {
        System.out.println("Runnable thread");
    }
}

class Test {
    public static void main(String[] args) {
        Thread t = new Thread(new MyRunnable());
        t.start();
    }
}

Why Runnable is better?

  • Java supports only single inheritance
  • Runnable allows extending another class
  • Better design approach (composition over inheritance)
  • More flexible

7. Multithreading Example (Exam-Level) - Q33

class Generator extends Thread {
    public void run() {
        while(true) {
            int n = (int)(Math.random() * 10);
            System.out.println("Generated: " + n);

            if(n % 2 == 0) {
                new Square(n).start();
            } else {
                new Cube(n).start();
            }

            try {
                Thread.sleep(1000);
            } catch(Exception e) {}
        }
    }
}

class Square extends Thread {
    int n;
    
    Square(int n) { 
        this.n = n; 
    }
    
    public void run() {
        System.out.println("Square of " + n + " = " + (n*n));
    }
}

class Cube extends Thread {
    int n;
    
    Cube(int n) { 
        this.n = n; 
    }
    
    public void run() {
        System.out.println("Cube of " + n + " = " + (n*n*n));
    }
}

class MainTest {
    public static void main(String[] args) {
        new Generator().start();
    }
}

✅ This matches Question 33 exactly


8. Thread Synchronization

Problem:

Multiple threads accessing shared resource may cause data inconsistency/race condition.

class Account {
    int balance = 10000;

    void withdraw(int amount) {
        if(balance >= amount) {
            balance -= amount;              // Problem: Race condition
            System.out.println("Withdrawn: " + amount);
        }
    }
}

Solution: Synchronization

Only one thread at a time can access synchronized method.

class Account {
    int balance = 10000;

    synchronized void withdraw(int amount) {
        if(balance >= amount) {
            balance -= amount;              // Safe now
            System.out.println("Withdrawn: " + amount);
        }
    }
}

🧠 How it works:

  • Thread acquires lock on object
  • Executes method
  • Releases lock
  • Other threads wait

9. Synchronized Block

More granular control over synchronization.

class Account {
    int balance = 10000;

    void withdraw(int amount) {
        synchronized(this) {
            if(balance >= amount) {
                balance -= amount;
                System.out.println("Withdrawn");
            }
        }
    }
}


🧩 JDBC - JAVA DATABASE CONNECTIVITY


1. What is JDBC?

JDBC is an API (Application Programming Interface) that allows Java programs to connect and interact with databases.

JDBC enables:

  • Database connection
  • Execute SQL queries
  • Retrieve results
  • Update/Delete data

2. JDBC Architecture

Java Application
      ↓
   JDBC API
      ↓
  JDBC Driver
      ↓
Database (MySQL, Oracle, PostgreSQL)

3. Types of JDBC Drivers

Type Name Example Use
Type 1 JDBC-ODBC Bridge Sun's JDBC-ODBC Bridge Deprecated ❌
Type 2 Native API Driver Oracle Native Driver Direct connection
Type 3 Network Protocol Driver Middleware Remote databases
Type 4 Thin Driver MySQL Connector/J Pure Java ✅

MySQL uses Type 4 driver (Most common)


4. Steps to Connect Java with Database

Step 1: Load JDBC Driver

Class.forName("com.mysql.cj.jdbc.Driver");

Step 2: Establish Connection

Connection con = DriverManager.getConnection(
    "jdbc:mysql://localhost:3306/dbname",
    "username",
    "password"
);

Connection URL format:

jdbc:mysql://hostname:port/database_name

Step 3: Create Statement Object

Three types:

  • Statement - For simple queries
  • PreparedStatement - For parameterized queries (Recommended)
  • CallableStatement - For stored procedures
Statement stmt = con.createStatement();
// OR
PreparedStatement ps = con.prepareStatement(query);

Step 4: Execute Query

// SELECT
ResultSet rs = ps.executeQuery();

// INSERT, UPDATE, DELETE
int rows = ps.executeUpdate();

Step 5: Process Results

while(rs.next()) {
    int id = rs.getInt(1);           // Column 1
    String name = rs.getString(2);   // Column 2
}

Step 6: Close Resources

rs.close();
ps.close();
con.close();

5. PreparedStatement (Recommended ✅)

Advantages:

  • Precompiled - Faster execution
  • Secure - Prevents SQL Injection
  • Reusable - Can execute multiple times
String query = "INSERT INTO student VALUES(?, ?, ?)";
PreparedStatement ps = con.prepareStatement(query);

ps.setInt(1, 1);              // Parameter 1
ps.setString(2, "Aditya");    // Parameter 2
ps.setInt(3, 95);             // Parameter 3

ps.executeUpdate();            // Execute

🧠 SQL Injection Prevention:

// ❌ Vulnerable to SQL Injection
String query = "SELECT * FROM student WHERE id=" + userId;

// ✅ Safe with PreparedStatement
String query = "SELECT * FROM student WHERE id=?";
PreparedStatement ps = con.prepareStatement(query);
ps.setInt(1, userId);

6. CallableStatement

Used to execute stored procedures in database.

CallableStatement cs = con.prepareCall("{call procedureName()}");
cs.execute();

Example with parameters:

String sql = "{call getStudentGrade(?, ?)}";
CallableStatement cs = con.prepareCall(sql);

cs.setInt(1, 101);                    // IN parameter
cs.registerOutParameter(2, Types.VARCHAR);  // OUT parameter

cs.execute();
String grade = cs.getString(2);       // Get result

7. ResultSet

Used to retrieve data from database.

ResultSet rs = ps.executeQuery();

while(rs.next()) {
    int id = rs.getInt("id");         // By column name
    String name = rs.getString("name");
    int marks = rs.getInt(3);         // By column index
}

🧠 Cursor operations:

rs.first();                           // Move to first row
rs.last();                            // Move to last row
rs.next();                            // Move to next row
rs.previous();                        // Move to previous row
rs.isFirst();                         // Check if first row

8. INSERT Operation

String query = "INSERT INTO student(id, name, marks) VALUES(?, ?, ?)";
PreparedStatement ps = con.prepareStatement(query);

ps.setInt(1, 1);
ps.setString(2, "Aditya");
ps.setInt(3, 95);

int result = ps.executeUpdate();
if(result > 0) {
    System.out.println("Record inserted");
}

9. UPDATE Operation

String query = "UPDATE student SET marks=? WHERE id=?";
PreparedStatement ps = con.prepareStatement(query);

ps.setInt(1, 98);              // New marks
ps.setInt(2, 1);               // Student id

int result = ps.executeUpdate();
if(result > 0) {
    System.out.println("Record updated");
}

10. DELETE Operation

String query = "DELETE FROM student WHERE id=?";
PreparedStatement ps = con.prepareStatement(query);

ps.setInt(1, 1);               // Student id to delete

int result = ps.executeUpdate();
if(result > 0) {
    System.out.println("Record deleted");
}

11. Transaction Management

Auto-commit (Default)

Each SQL statement is automatically committed.

Connection con = DriverManager.getConnection(url);
// Auto-commit is ON by default

Manual Transaction Control

con.setAutoCommit(false);      // Disable auto-commit

try {
    ps1.executeUpdate();
    ps2.executeUpdate();
    con.commit();              // Save both
    System.out.println("Transaction successful");
} 
catch(Exception e) {
    con.rollback();            // Undo both
    System.out.println("Transaction failed");
}

🧠 Definitions:

  • Commit - Permanently saves all changes
  • Rollback - Cancels all changes since last commit

12. Complete JDBC Program Example (Q34 Type)

import java.sql.*;
import java.util.Scanner;

class StudentDB {
    static final String URL = "jdbc:mysql://localhost:3306/college";
    static final String USER = "root";
    static final String PASS = "password";
    
    static Connection con;
    
    static {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            con = DriverManager.getConnection(URL, USER, PASS);
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void insertStudent(int id, String name, int marks) {
        try {
            String query = "INSERT INTO student VALUES(?, ?, ?)";
            PreparedStatement ps = con.prepareStatement(query);
            
            ps.setInt(1, id);
            ps.setString(2, name);
            ps.setInt(3, marks);
            
            ps.executeUpdate();
            System.out.println("Student added");
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void displayStudents() {
        try {
            String query = "SELECT * FROM student";
            Statement stmt = con.createStatement();
            ResultSet rs = stmt.executeQuery(query);
            
            System.out.println("ID\tName\tMarks");
            while(rs.next()) {
                System.out.println(rs.getInt(1) + "\t" + 
                                 rs.getString(2) + "\t" + 
                                 rs.getInt(3));
            }
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        insertStudent(1, "Aditya", 95);
        insertStudent(2, "Priya", 92);
        displayStudents();
    }
}


📊 COLLECTIONS, WRAPPER CLASSES & GENERICS


🔹 QUESTION MAPPING

From your syllabus, this chapter covers:

  • Q30 – LinkedList iteration
  • Q31 – LinkedList insertion (without collections)
  • Q32 – Delete duplicate objects from ArrayList
  • Q46 – Addition of elements in List
  • Q47 – Size of Collection & empty check
  • Q49 – Set usage
  • Generics / Wrapper – Type safety questions

1️⃣ COLLECTIONS FRAMEWORK

What is Collection?

A Collection is a framework that provides ready-made classes and interfaces to store and manipulate a group of objects.

👉 Used when:

  • Size is dynamic
  • Duplicate handling needed
  • Searching/sorting required
  • Need flexibility

Core Interfaces Hierarchy

Collection (Interface)
   ├── List (Ordered, allows duplicates)
   │    ├── ArrayList
   │    ├── LinkedList
   │    └── Vector (Legacy)
   │
   ├── Set (Unique elements)
   │    ├── HashSet
   │    ├── LinkedHashSet
   │    └── TreeSet
   │
   └── Queue (FIFO)
        ├── LinkedList
        └── PriorityQueue

Map (Separate - NOT part of Collection)
   ├── HashMap
   ├── LinkedHashMap
   └── TreeMap

⚠️ Note: Map is NOT part of Collection interface


2️⃣ COLLECTION INTERFACE (Q47)

Important Methods:

add(Object obj)              // Add element
remove(Object obj)           // Remove element
size()                       // Number of elements
isEmpty()                    // Check if empty
contains(Object obj)         // Check if exists
iterator()                   // Iterate through collection
clear()                      // Remove all elements

Example (Q47 Type):

import java.util.*;

class CollectionDemo {
    public static void main(String[] args) {
        Collection<Integer> col = new ArrayList<>();
        
        col.add(10);
        col.add(20);
        col.add(30);
        
        System.out.println("Size: " + col.size());        // 3
        System.out.println("Is Empty: " + col.isEmpty()); // false
        System.out.println("Contains 20: " + col.contains(20)); // true
        
        col.remove(20);
        System.out.println("Size after remove: " + col.size()); // 2
    }
}

3️⃣ LIST INTERFACE (Q30, Q32, Q46)

Characteristics:

  • Ordered - Elements stored in insertion order
  • Allows duplicates - Same element can appear multiple times
  • Index-based - Access by position (0, 1, 2...)

3.1 ArrayList (Q32, Q46)

When to use:

  • Frequent access by index
  • Removing duplicates
  • Dynamic size needed
  • Faster for retrieval
ArrayList<Integer> list = new ArrayList<>();
list.add(10);      // Index 0
list.add(20);      // Index 1
list.add(30);      // Index 2

System.out.println(list.get(0));  // 10
list.set(0, 15);                  // Change element
list.remove(0);                   // Remove first

🔹 Q32 – Delete duplicate objects from ArrayList

Problem: Remove duplicates from ArrayList

import java.util.*;

class RemoveDuplicates {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(10);
        list.add(10);
        list.add(20);
        list.add(20);
        list.add(30);
        
        System.out.println("Before: " + list);  // [10, 10, 20, 20, 30]
        
        // Solution 1: Using HashSet
        HashSet<Integer> set = new HashSet<>(list);
        list.clear();
        list.addAll(set);
        
        System.out.println("After: " + list);   // [20, 10, 30]
        
        // Solution 2: Using LinkedHashSet (maintains order)
        LinkedHashSet<Integer> lset = new LinkedHashSet<>(list);
        list.clear();
        list.addAll(lset);
        
        System.out.println("After (with order): " + list);
    }
}

🔥 Most common lab solution for Q32


3.2 LinkedList (Q30, Q31)

Features:

  • Doubly linked list - Each node has previous and next pointers
  • No index-based fast access
  • Best for insertion/deletion
LinkedList<Integer> list = new LinkedList<>();
list.add(10);      // Add at end
list.addFirst(5);  // Add at beginning
list.addLast(20);  // Add at end
list.remove();     // Remove first

🔹 Q30 – Iterate LinkedList from specific position

Problem: Iterate from a specific position using ListIterator

import java.util.*;

class LinkedListIteration {
    public static void main(String[] args) {
        LinkedList<Integer> list = new LinkedList<>();
        list.add(10);
        list.add(20);
        list.add(30);
        list.add(40);
        list.add(50);
        
        System.out.println("List: " + list);
        
        // Iterate from index 2
        ListIterator<Integer> it = list.listIterator(2);
        
        System.out.println("Elements from index 2:");
        while(it.hasNext()) {
            System.out.println(it.next());
        }
        
        // Output:
        // 30
        // 40
        // 50
    }
}

🧠 ListIterator methods:

hasNext()        // Check if next element exists
next()           // Get next element
hasPrevious()    // Check if previous exists
previous()       // Get previous element
set(Object)      // Replace current element
add(Object)      // Insert element

🔹 Q31 – Insert element in LinkedList (WITHOUT Collections)

Problem: Implement LinkedList manually and insert element

class Node {
    int data;
    Node next;

    Node(int data) {
        this.data = data;
        this.next = null;
    }
}

class MyLinkedList {
    Node head;

    MyLinkedList() {
        head = null;
    }

    // Insert at end
    void insert(int data) {
        Node newNode = new Node(data);
        
        if(head == null) {
            head = newNode;
        } else {
            Node temp = head;
            while(temp.next != null) {
                temp = temp.next;
            }
            temp.next = newNode;
        }
    }

    // Insert at beginning
    void insertAtBeg(int data) {
        Node newNode = new Node(data);
        newNode.next = head;
        head = newNode;
    }

    // Insert at position
    void insertAtPos(int data, int pos) {
        Node newNode = new Node(data);
        
        if(pos == 1) {
            newNode.next = head;
            head = newNode;
            return;
        }
        
        Node temp = head;
        for(int i = 1; i < pos - 1 && temp != null; i++) {
            temp = temp.next;
        }
        
        if(temp != null) {
            newNode.next = temp.next;
            temp.next = newNode;
        }
    }

    // Display
    void display() {
        Node temp = head;
        while(temp != null) {
            System.out.print(temp.data + " -> ");
            temp = temp.next;
        }
        System.out.println("null");
    }
}

class Test {
    public static void main(String[] args) {
        MyLinkedList list = new MyLinkedList();
        
        list.insert(10);
        list.insert(20);
        list.insert(30);
        list.display();              // 10 -> 20 -> 30 -> null
        
        list.insertAtBeg(5);
        list.display();              // 5 -> 10 -> 20 -> 30 -> null
        
        list.insertAtPos(15, 2);
        list.display();              // 5 -> 15 -> 10 -> 20 -> 30 -> null
    }
}

⚠️ Examiner checks logic, not speed - This is best for Q31


3.3 Vector (Legacy)

Vector<Integer> v = new Vector<>();
v.add(10);
v.addElement(20);

🧠 Thread-safe but slower than ArrayList


3.4 Stack

LIFO (Last In First Out)

Stack<Integer> stack = new Stack<>();
stack.push(10);       // Add
stack.pop();          // Remove and return
stack.peek();         // View top
stack.isEmpty();      // Check if empty

4️⃣ QUEUE & DEQUE

Queue (FIFO - First In First Out)

Queue<Integer> q = new LinkedList<>();
q.add(10);            // Enqueue
q.remove();           // Dequeue
q.peek();             // View front
q.isEmpty();

Deque (Double Ended Queue)

Insert/remove from both ends

Deque<Integer> dq = new ArrayDeque<>();
dq.addFirst(10);      // Add at front
dq.addLast(20);       // Add at end
dq.removeFirst();     // Remove from front
dq.removeLast();      // Remove from end

5️⃣ SET INTERFACE (Q49)

Characteristics:

  • No duplicates - Unique elements only
  • No index - Cannot access by position
  • No ordering (except TreeSet/LinkedHashSet)

🔹 Q49 – Program using Set

HashSet (Unordered)

import java.util.*;

class SetDemo {
    public static void main(String[] args) {
        Set<Integer> set = new HashSet<>();
        
        set.add(10);
        set.add(10);      // Duplicate - ignored
        set.add(20);
        set.add(30);
        
        System.out.println("HashSet: " + set);
        // Output: [20, 10, 30] (Order may vary)
        
        System.out.println("Size: " + set.size());  // 3
        System.out.println("Contains 10: " + set.contains(10));  // true
        
        set.remove(20);
        System.out.println("After remove: " + set);
        
        // Iterate
        for(Integer num : set) {
            System.out.println(num);
        }
    }
}

LinkedHashSet (Insertion Order)

Set<Integer> set = new LinkedHashSet<>();
set.add(30);
set.add(10);
set.add(20);

System.out.println(set);  // [30, 10, 20] - Maintains order

TreeSet (Sorted Order)

Set<Integer> set = new TreeSet<>();
set.add(30);
set.add(10);
set.add(20);

System.out.println(set);  // [10, 20, 30] - Sorted

6️⃣ MAP INTERFACE

Characteristics:

  • Key-value pairs
  • Keys are unique
  • Not part of Collection interface

HashMap (Unordered)

Map<Integer, String> map = new HashMap<>();
map.put(1, "Java");
map.put(2, "Python");

System.out.println(map.get(1));    // "Java"
System.out.println(map.size());    // 2
System.out.println(map.containsKey(1));  // true

// Iterate
for(Integer key : map.keySet()) {
    System.out.println(key + " = " + map.get(key));
}

LinkedHashMap (Insertion Order)

Map<Integer, String> map = new LinkedHashMap<>();
map.put(1, "A");
map.put(2, "B");
map.put(3, "C");

System.out.println(map);  // {1=A, 2=B, 3=C}

TreeMap (Sorted by Key)

Map<Integer, String> map = new TreeMap<>();
map.put(3, "C");
map.put(1, "A");
map.put(2, "B");

System.out.println(map);  // {1=A, 2=B, 3=C}

7️⃣ WRAPPER CLASSES

Purpose:

Convert primitive data types to objects and vice versa.

Primitive Wrapper
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

Boxing (Primitive → Object)

// Explicit Boxing
int a = 10;
Integer obj = Integer.valueOf(a);

// Auto Boxing (Java 5+)
Integer obj = 10;

Unboxing (Object → Primitive)

// Explicit Unboxing
Integer obj = 10;
int b = obj.intValue();

// Auto Unboxing (Java 5+)
int b = obj;

Common Methods

Integer.parseInt("10");          // String to int
Integer.toString(10);            // int to String
Integer.max(10, 20);             // Maximum
Integer.min(10, 20);             // Minimum
Double.parseDouble("3.14");      // String to double

Wrapper Classes in Collections

ArrayList<Integer> list = new ArrayList<>();
list.add(10);                    // Auto boxing
int num = list.get(0);           // Auto unboxing

8️⃣ GENERICS (VERY IMPORTANT)

Why Generics?

  • Type safety - Compile-time checking
  • No casting - Avoid ClassCastException
  • Code reusability - Write once, use for multiple types

Generic Class

class Box<T> {
    T value;
    
    void set(T value) {
        this.value = value;
    }
    
    T get() {
        return value;
    }
}

class Test {
    public static void main(String[] args) {
        Box<Integer> intBox = new Box<>();
        intBox.set(10);
        System.out.println(intBox.get());  // 10
        
        Box<String> strBox = new Box<>();
        strBox.set("Java");
        System.out.println(strBox.get());  // Java
    }
}

🧠 Key Points:

  • <T> is type parameter (placeholder)
  • Can use: <T>, <E>, <K>, <V>, <N> etc.
  • Type determined at runtime

Generic Method

class Test {
    // Generic method
    static <T> void show(T data) {
        System.out.println("Type: " + data.getClass().getName());
        System.out.println("Value: " + data);
    }
    
    public static void main(String[] args) {
        show(10);           // Integer
        show("Java");       // String
        show(3.14);         // Double
    }
}

Generic Collection (Q46 Type)

// Without Generics (Type-unsafe)
ArrayList list = new ArrayList();
list.add(10);
list.add("Java");           // Mixed types
Integer num = (Integer)list.get(0);  // Casting needed

// With Generics (Type-safe)
ArrayList<String> list = new ArrayList<>();
list.add("Java");
// list.add(10);            ❌ Compile error
String str = list.get(0);  // No casting needed

Bounded Type Parameters

// T must be Number or its subclass
class Box<T extends Number> {
    void show(T value) {
        System.out.println(value);
    }
}

class Test {
    public static void main(String[] args) {
        Box<Integer> box1 = new Box<>();
        Box<Double> box2 = new Box<>();
        // Box<String> box3 = new Box<>();  ❌ Error
    }
}

Wildcard (?)

// ? means any type
void printList(ArrayList<?> list) {
    for(Object obj : list) {
        System.out.println(obj);
    }
}

// ? extends Number - any subclass of Number
void addNumbers(ArrayList<? extends Number> list) {
    // Can only read, not add
}


🎯 FINAL EXAM STRATEGY

Topics by Priority:

HIGH PRIORITY (Must Score):

  1. ✅ Thread creation & lifecycle
  2. ✅ ArrayList & LinkedList operations
  3. ✅ Exception handling (try-catch-finally)
  4. ✅ JDBC operations (Insert, Select, Update)
  5. ✅ Collections methods
  6. ✅ Generics basics
  7. ✅ OOP concepts (Inheritance, Polymorphism)

MEDIUM PRIORITY:

  1. ✓ Synchronization
  2. ✓ PreparedStatement vs Statement
  3. ✓ Set operations
  4. ✓ Wrapper classes
  5. ✓ Abstract class vs Interface

LOWER PRIORITY:

  1. Map interface
  2. Queue/Deque
  3. Bounded generics
  4. Custom exceptions (viva level)

Quick Revision Checklist:

  • Understand thread life cycle completely
  • Differentiate ArrayList vs LinkedList
  • Know all exception keywords (try/catch/finally/throw/throws)
  • JDBC 6-step connection process
  • Duplicate removal from ArrayList (Q32 solution)
  • LinkedList iteration from specific position (Q30 solution)
  • Generic class and method creation
  • Set types: HashSet, LinkedHashSet, TreeSet
  • Polymorphism: overloading vs overriding
  • Synchronization concept

Expected Question Types in Exam:

Type Questions
Theory (Short answer) 2-3 questions
Code snippet (Find output) 2-3 questions
Program writing 2-3 questions
Database operations 1-2 questions
Thread programs 1-2 questions

Good luck with your exams! 🚀

Last updated: January 2026 Aligned with Galgotias University CSE Curriculum