OOOpsunit 2
OOOpsunit 2
Exception indicates
An Error indicates a serious
conditions that a reasonable
problem that a reasonable
Definition application might try to catch
Aspect Error Exception
OutOfMemoryError IOException
Examples StackOverFlowError NullPointerException
Checked Exception
Unchecked Exception
2. User-Defined Exceptions
1. Built-in Exception
Build-in Exception are pre-defined exception classes provided by Java to handle
common errors during program execution.
1.1 Checked Exceptions
Checked exceptions are called compile-time exceptions because these exceptions
are checked at compile-time by the compiler. Examples of Checked Exception are
listed below:
1. ClassNotFoundException: Throws when the program tries to load a class at
runtime but the class is not found because it’sbelong not present in the correct
location or it is missing from the project.
2. InterruptedException: Thrown when a thread is paused and another thread
interrupts it.
3. IOException: Throws when input/output operation fails
4. InstantiationException: Thrown when the program tries to create an object of
a class but fails because the class is abstract, an interface, or has no default
constructor.
5. SQLException: Throws when there’s an error with the database.
6. FileNotFoundException: Thrown when the program tries to open a file that
doesn’t exist
1.2 Unchecked Exceptions
The unchecked exceptions are just opposite to the checked exceptions. The
compiler will not check these exceptions at compile time. In simple words, if a
program throws an unchecked exception, and even if we didn’t handle or declare it,
the program would not give a compilation error. Examples of Unchecked Exception
are listed below:
1. ArithmeticException: It is thrown when there’s an illegal math operation.
2. ClassCastException: It is thrown when you try to cast an object to a class it
does not belongThis to.
3. NullPointerException: It is thrown when you try to use a null object (e.g.
accessing its methods or fields)
4. ArrayIndexOutOfBoundsException: ThisThis occurs when we try to access
an array element with an invalid index.
5. ArrayStoreException: Thishandle happens when you store an object of the
wrong type in an array.
6. IllegalThreadStateException: It is thrown when a thread operation is not
allowed in its current state
User-Defined Exception
Sometimes, the built-in exceptions in Java are not able to describe a certain situation.
In such cases, users can also create exceptions, which are called “user-defined
Exceptions“.
Methods to Print the Exception Information
Method Description
Base
Derived from Exception Derived from RuntimeException
class
External factors like file I/O and Programming bugs like logical
database connection cause the errors cause unchecked
Cause checked Exception. Exceptions.
Java catch block is used to handle the Exception by declaring the type of exception
within the parameter. The declared exception must be the parent class exception ( i.e.,
Exception) or the generated exception type. However, the good approach is to declare
the generated type of exception.
The catch block must be used after the try block only. You can use multiple catch block
with a single try block.
finally Block
The finally Block is used to execute important code regardless of whether an
exception occurs or not.
Note: finally block is always executes after the try-catch block. It is also used for
resource cleanup.
try {
// Code that may throw an exception
} catch (ExceptionType e) {
// Code to handle the exception
}finally{
// cleanup code
}
Difference Between throw and throws in Java
The differences between throw and throws in Java are:
S. Key
No. Difference throw throws
ArithmeticException Example
public class ArithmeticExceptionDemo {
public static void main(String[] args) {
int a = 10;
int b = 0; // This will cause division by zero
try {
int result = a / b; // ArithmeticException occurs here
System.out.println("Result: " + result);
} catch (ArithmeticException e) {
System.out.println("Exception caught: " + e.getMessage());
} finally {
System.out.println("Finally block executed.");
}
}
}
Output:
Exception caught: / by zero
Finally block executed.
NullPointerException Example
public class NullPointerExceptionDemo {
public static void main(String[] args) {
String str = null; // str is not pointing to any object
try {
// This will throw NullPointerException
int length = str.length();
System.out.println("Length of the string: " + length);
} catch (NullPointerException e) {
System.out.println("Exception caught: " + e.getMessage());
} finally {
System.out.println("Finally block executed.");
}
}
}
Output:
Exception caught: Cannot invoke "String.length()" because "str" is null
Finally block executed.
try {
// Trying to access an out-of-bounds index
System.out.println("Value at index 5: " + arr[5]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Exception caught: " + e);
System.out.println("Please access a valid index (0 to " + (arr.length - 1) + ").");
}
System.out.println("Program continues after exception handling.");
}
}
Output:
Exception caught: java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for
length 5
Please access a valid index (0 to 4).
Program continues after exception handling.
(StringIndexOutOfBoundsException Example)
try {
char ch = str.charAt(5);
} catch (StringIndexOutOfBoundsException e) {
}
OUTPUT:
Exception caught: java.lang.StringIndexOutOfBoundsException: String index out of
range: 5
Valid indices are from 0 to 4
Program continues after exception handling.
What is ClassNotFoundException in Java?
ClassNotFoundException is a checked exception in Java that occurs when an
application tries to load a class at runtime using:
Class.forName("...")
ClassLoader.loadClass("...")
...and the class cannot be found in the classpath.
Key Points:
try {
Class.forName("com.example.NonExistentClass");
} catch (ClassNotFoundException e) {
Output:
Exception caught: java.lang.ClassNotFoundException: com.example.NonExistentClass
The specified class was not found in the classpath.
Program continues after handling ClassNotFoundException.
try {
} catch (ClassCastException e) {
}
}
Output:
Exception caught: java.lang.ClassCastException: java.lang.String cannot be cast to
java.lang.Integer
Cannot cast String to Integer.
Program continues after exception handling.
try {
} catch (NumberFormatException e) {
OUTPUT:
Exception caught: java.lang.NumberFormatException: For input string: "123abc"
Invalid number format: '123abc'
Program continues after exception handling.
if (age < 0) {
try {
} catch (IllegalArgumentException e) {
OUTPUT:
Exception caught: java.lang.IllegalArgumentException: Age cannot be negative: -5
Program continues after exception handling.
Java Program Demonstrating throw and throws
Scenario:
You are developing a banking login system where a user is allowed to enter their PIN only 3
times. If the user fails to enter the correct PIN after 3 attempts, the system should throw a
custom exception called TooManyAttemptsException and lock the account.
Question:
Write a Java program that simulates a simple PIN verification system. The correct PIN is 1234. The
user is allowed a maximum of 3 attempts to enter the correct PIN.
If the user fails all 3 times, throw a custom exception TooManyAttemptsException with an
appropriate message.
Catch and handle the exception in the main method and display the error message
import java.util.Scanner;
// Custom exception class
super(message);
int attempts = 0;
if (inputPin == CORRECT_PIN) {
return;
} else {
attempts++;
System.out.println("Incorrect PIN. Attempt " + attempts + " of " + MAX_ATTEMPTS);
try {
verifyPin();
} catch (TooManyAttemptsException e) {
System.out.println("Program ends.");
Output:
Enter your 4-digit PIN: 1111
Incorrect PIN. Attempt 1 of 3
Enter your 4-digit PIN: 2222
Incorrect PIN. Attempt 2 of 3
Enter your 4-digit PIN: 3333
Incorrect PIN. Attempt 3 of 3
Exception caught: Too many incorrect attempts. Your account is locked.
Program ends.
Scenario:
You are building a system for a library that allows users to check out books by entering their
library card number. The library card number must be a 6-digit numeric value. Users will
input their card numbers as strings, and the system must validate the format of the card
number.
If a user enters a card number that doesn't match the expected 6-digit numeric format, the
system should throw a NumberFormatException (which is a subclass of
InputMismatchException) and notify the user that the card number is invalid.
import java.util.Scanner;
if (!input.matches("\\d{6}")) {
validateCardNumber(cardNumber);
} catch (NumberFormatException e) {
System.out.println("Program ends.");
OUTPUT:
Enter your 6-digit library card number: 123456
Library card number 123456 is valid. Access granted.
Program ends.
Enter your 6-digit library card number: ab123
Exception caught: Invalid library card number. Must be exactly 6 digits.
Program ends.
Scenario:
You are developing a simple ATM-like application that allows users to withdraw money from their
account. The application asks the user to enter the amount to withdraw, which must be an integer
value (e.g., 100, 500, 1000).
However, if the user accidentally enters a non-integer input such as text ("abc") or a decimal
number ("100.50"), the program should catch an InputMismatchException, inform the user of
the mistake, and allow them to try again.
import java.util.Scanner;
import java.util.InputMismatchException;
int amount = 0;
while (!validInput) {
try {
if (amount <= 0) {
} else {
} catch (InputMismatchException e) {
OutPut:
import java.io.*;
int data;
fos.write(data);
fis.close();
fos.close();
}
OUTPUT:
The output is not printed to the console, and there is no visible output in the terminal or
console.
A new file named output.bin is created, and its content is an exact byte-for-byte copy
of input.bin.
Example:
If input.bin contains:
Binary data from an image, a video, or even text — e.g., [01001000 01001001]
(binary for "HI")
Then output.bin will contain the same binary data, and both files will be identical in size
and content.
Character Stream
Character streams are designed for handling textual data. They read and write characters (2
bytes each) and support Unicode, making them ideal for reading and writing text files. The
base classes are Reader and Writer, which handle character encoding internally.
import java.io.*;
int ch;
fw.write(ch);
}
fr.close();
fw.close();
OUTPUT:
Example:
Hello, Java!
Hello, Java!
A text file stores characters using a specific encoding (e.g., UTF-8, ASCII).
Byte streams read raw bytes from the file.
If you use a byte stream to read a text file, you are just reading the encoded bytes.
However, you must manually decode those bytes to characters if you want to display
or process the text correctly.
MULTITHREADING
THREAD
In Java, a thread is a lightweight subprocess — the smallest unit of execution. Java allows
multiple threads to run concurrently, enabling multitasking within a program.
MULTITHREADING
Multithreading means running two or more threads (parts of a program) simultaneously.
Each thread runs independently, but shares the same memory space.
Ways to Create a Thread
Method Description
start() Starts the thread and calls the run() method asynchronously.
run() Contains the code that defines the thread’s task.
sleep(long millis) Pauses the thread for the specified number of milliseconds.
join()
Causes the current thread to wait until the thread on which join()
was called finishes.
yield()
Suggests that the thread scheduler give other threads a chance to run
(a hint, not guaranteed).
isAlive() Checks if the thread is still running (has not finished execution).
setPriority(int p)
Sets the thread’s priority (ranges from Thread.MIN_PRIORITY = 1 to
Thread.MAX_PRIORITY = 10).
getPriority() Returns the thread’s current priority.
Method Description
getName() Returns the thread’s name.
setName(String
name) Sets the thread’s name.
interrupt()
Interrupts a thread, setting its interrupted status; can be used to stop a
sleeping/waiting thread.
isInterrupted()
Tests if the thread has been interrupted (does not clear the
interrupted status).
currentThread() Returns a reference to the currently executing thread.
setPriority() Method in Java
This method sets the priority level of a thread. Thread priority helps the thread scheduler decide
which thread to run first, though it's not guaranteed and depends on the JVM and OS.
Constant Value Description
Thread.MIN_PRIORITY 1 Lowest priority
Thread.NORM_PRIORITY 5 Default (normal)
Thread.MAX_PRIORITY 10 Highest priority
The life cycle of a thread in Java refers to the various states of a thread goes through. For
example, a thread is born, started, runs, and then dies. Thread class defines the life cycle
and various states of a thread.
New − A new thread begins its life cycle in the new state. It remains in this state
until the program starts the thread. It is also referred to as a born thread.
Runnable − After a newly born thread is started, the thread becomes runnable. A
thread in this state is considered to be executing its task.
Waiting − Sometimes, a thread transitions to the waiting state while the thread
waits for another thread to perform a task. A thread transitions back to the
runnable state only when another thread signals the waiting thread to continue
executing.
Timed Waiting − A runnable thread can enter the timed waiting state for a specified
interval of time. A thread in this state transitions back to the runnable state when
that time interval expires or when the event it is waiting for occurs.
Terminated (Dead) − A runnable thread enters the terminated state when it
completes its task or otherwise terminates.
Example 1
Write a java program using setName() and getName() method to create threads.
class MyThread extends Thread {
public void run() {
System.out.println("Thread is running: " + getName());
}
}
// Start threads
t1.start();
t2.start();
}
}
Output:
Before start:
HighPriorityThread Priority: 10
LowPriorityThread Priority: 1
Thread Name: HighPriorityThread
Thread Priority: 10
Thread Name: LowPriorityThread
Thread Priority: 1
⚠ Note: The order of thread execution is not guaranteed — even though one thread has a
higher priority, the actual scheduling depends on the JVM and OS.
t1.setName("Thread-1");
t2.setName("Thread-2");
t1.start();
t2.start();
}
}
Output:
Thread-1 - Count: 1
Thread-2 - Count: 1
Thread-1 - Count: 2
Thread-2 - Count: 2
Thread-1 - Count: 3
Thread-2 - Count: 3
Thread-1 - Count: 4
Thread-2 - Count: 4
Thread-1 - Count: 5
Thread-2 - Count: 5
⏱ The threads will print their messages every second, running concurrently.
Why Synchronization?
In multithreading, multiple threads may try to access and modify the same resource
simultaneously, leading to problems like:
Inconsistent data
Race conditions
Unexpected behavior
class Counter {
count++;
try {
} catch (InterruptedException e) {
return count;
super(name);
this.counter = counter;
}
counter.increment(getName());
t1.start();
t2.start();
OUTPUT:
try {
} catch (InterruptedException e) {
System.out.println("Interrupted");
System.out.println(" ]");
Printer printer;
String message;
this.printer = printer;
this.message = message;
printer.printMessage(message);
}
}
t1.start();
t2.start();
}
OUTPUT:
[ Hello ]
[ World ]
Question:
You're building a Java application that simulates a ticket booking system for a theater. There
are only 10 tickets available. Multiple users are trying to book tickets at the same time
through different threads.
Write a Java program using multithreading to handle this scenario safely. Ensure that:
No ticket is overbooked
The ticket count is updated correctly
The program prevents race conditions
Requirements:
class TicketBookingSystem {
ticketsAvailable -= numberOfTickets;
} else {
System.out.println(userName + " tried to book " + numberOfTickets + " ticket(s), but only " +
ticketsAvailable + " are available. Booking failed.");
this.bookingSystem = bookingSystem;
this.ticketsToBook = ticketsToBook;
}
bookingSystem.bookTicket(getName(), ticketsToBook);
user1.start();
user2.start();
user3.start();
Output:
Tickets remaining: 6
Charlie tried to book 3 ticket(s), but only 1 are available. Booking failed.
Thread Safety:
The bookTicket() method is marked synchronized to ensure that only one thread
can access it at a time, preventing race conditions.
These must be called from synchronized context (i.e., inside a synchronized block or
method)
EXAMPLE:
class Customer {
int amount = 10000;
this.amount -= amount;
System.out.println("Withdraw completed. Remaining balance: " + this.amount);
}
new Thread() {
public void run() {
c.withdraw(15000); // withdraw more than current balance
}
}.start();
new Thread() {
public void run() {
try {
Thread.sleep(2000); // wait for a moment before depositing
} catch (InterruptedException e) {
System.out.println(e);
}
c.deposit(10000); // deposit enough to allow withdrawal
}
}.start();
}
}
OUTPUT
Going to withdraw...
Less balance; waiting for deposit...
Going to deposit...
Deposit completed. Current balance: 20000
Withdraw completed. Remaining balance: 5000
class Customer {
int amount = 10000;
this.amount -= amount;
System.out.println(Thread.currentThread().getName() + " completed withdrawal.
Remaining: " + this.amount);
}
// Deposit thread
Thread depositThread = new Thread(new Runnable() {
public void run() {
try {
Thread.sleep(3000); // simulate delay before deposit
} catch (InterruptedException e) {
System.out.println(e);
}
c.deposit(50000); // deposit enough to wake all waiting threads
}
}, "Deposit-Thread");
depositThread.start();
}
}
OUTPUT:
Withdraw-Thread-1 wants to withdraw...
Withdraw-Thread-1 waiting due to low balance...
Withdraw-Thread-3 wants to withdraw...
Withdraw-Thread-3 waiting due to low balance...
Withdraw-Thread-2 wants to withdraw...
Withdraw-Thread-2 waiting due to low balance...
Deposit-Thread is depositing...
Deposit-Thread deposit complete. New balance: 60000
Withdraw-Thread-1 completed withdrawal. Remaining: 45000
Withdraw-Thread-2 completed withdrawal. Remaining: 30000
Withdraw-Thread-3 completed withdrawal. Remaining: 15000