(OOP)
SE AIML
UNIT-IV
EXCEPTION HANDLING AND GENERIC
PROGRAMMING
By:
Dr. Puja Gholap
WHAT IS AN ERROR?
An error is a problem that arises during program
execution and disturbs the normal flow of instructions
and even may cause the system to crash.
Some errors are minor and can be handled
(exceptions), while others are severe and cannot be
controlled (serious system errors).
Even experienced Java developers make mistakes. The
key is learning how to spot and fix them!
TYPES OF ERRORS
Errors can be broadly classified into three categories:
1. Compile-Time Errors
2. Runtime Errors (Exceptions)
1. COMPILE-TIME ERRORS
All syntax errors will be detected and displayed by the
Java compiler and therefore these errors are known as
compile-time errors.
Errors detected by the Java compiler at the time of
compilation.
Whenever the compiler displays an error, it will not create
the class file. It is therefore necessary that we fix all the
errors before we can successfully compile and run the
program.
Examples:
Missing semicolon ;
Using undeclared variables
Type mismatch
missing semicolons,
missing brackets,
misspelled keywords,
EXAMPLE PROGRAM
(COMPILE-TIME ERROR):
class CompileError
{
public static void main(String[] args)
{
int a = 10 //Compile time Error
System.out.println(a);
}
}
Output:
Error: ';' expected
RUNTIME ERRORS (EXCEPTIONS)
Errors that occur while the program is running.
Runtime errors occur when the program has
successfully compiled without giving any errors and
creating a ".class" file. However, the program does not
execute properly. These errors are detected at runtime
or at the time of execution of the program.
Caused by illegal operations such as division by zero,
accessing out-of-bounds array elements, invalid input,
etc.
These are exceptions and can be handled using Java’s
exception handling mechanism.
RUNTIME ERRORS (EXCEPTIONS)
The Java compiler does not detect runtime errors
because the Java compiler does not have any technique
to catch these errors as it does not have all the
runtime information available to it.
Runtime errors are caught by Java Virtual
Machine(JVM) when the program is running.
These runtime errors are called exceptions and they
terminate the program abnormally, giving an error
statement.
Examples of runtime errors:
ArithmeticException – divide by zero
ArrayIndexOutOfBoundsException – invalid array
index
EXAMPLE PROGRAM (RUNTIME ERROR)
class RuntimeError
{
public static void main(String[] args)
{
int a = 10, b = 0;
int c = a / b; // Runtime error: Division by zero
System.out.println("Result = " + c);
}
}
Output:
Error: java.lang.ArithmeticException: / by zero
EXCEPTION
An exception is an abnormal condition that occurs
during the execution of a program and disrupts the
normal flow of instructions.
In simple words, it is an error that occurs at runtime.
Example: Division by zero, invalid array index, file not
found, etc.
If the exception object is not caught and handled
properly, the interpreter will display an error message
and will terminate the program.
If we want the program to continue with the execution
of the remaining code, then we should try to catch the
exception object thrown by the error condition and then
display an appropriate message for taking corrective
actions. This task is known as exception handling.
NEED FOR EXCEPTION HANDLING
The purpose of exception handling mechanism is to
provide a means to detect and report an "exceptional
circumstance" so that appropriate action can be taken. The
mechanism suggests incorporation of a separate error
handling code that performs the following tasks:
1. Find the problem (Hit the exception).
2. Inform that an error has occurred (Throw the
exception)
3. Receive the error information (Catch the
exception)
4. Take corrective actions (Handle the exception)
The error handling code basically consists of two segments,
one to detect errors and to throw exceptions and the other
to catch exceptions and to take appropriate actions.
EXCEPTION TYPES
ArithmeticException- Caused by math errors such
as division by zero
ArrayIndexOutOfBoundsException- Caused by
bad array indexes
ArrayStoreException – caused when a program
tries to store the wrong type of data in the array
FileNotFoundException - Caused by an attempt to
access a nonexistent file
IOException- Caused by general I/O failures, such as
inability to read from a file
NullPointerException - Occurs when trying to
access an object referece that is null
EXCEPTION TYPES
NumberFormatException- Caused when a
conversion between strings and number fails
OutOfMemoryException- Caused when there's not
enough memory to allocate a new object
SecurityException- Caused when an applet tries to
perform an action not allowed by the browser's
security setting
StackOverFlowException- Caused when the system
runs out of stack space
StringIndexOutOfBoundsException- Caused when
a program attempts to access a nonexistent character
position in a string
EXCEPTION-HANDLING FUNDAMENTALS
Exception handling lets you catch and handle errors during runtime -
so your program doesn't crash.
It uses different keywords:
try – Block of code where exceptions may occur. The try statement
allows you to define a block of code to be tested for errors while it is
being executed.
catch – Handles the exception thrown from try block. The catch
statement allows you to define a block of code to be executed, if an
error occurs in the try block.
Syntax:
try {
// Block of code to try
}
catch(Exception e) {
// Block of code to handle errors
}
EXCEPTION-HANDLING FUNDAMENTALS
Exception handling lets you catch and handle errors during runtime -
so your program doesn't crash.
It uses different keywords:
try – Block of code where exceptions may occur. The try statement
allows you to define a block of code to be tested for errors while it is
being executed.
catch – Handles the exception thrown from try block. The catch
statement allows you to define a block of code to be executed, if an
error occurs in the try block.
Syntax:
try {
// Block of code to try
}
catch(Exception e) {
// Block of code to handle errors
}
EXAMPLE- EXCEPTION-HANDLING
class ExceptionDemo {
public static void main(String[] args) {
try {
int a = 10, b = 0;
int c = a / b; // Runtime error: Division by zero
System.out.println("Result: " + c);
} catch (ArithmeticException e) {
System.out.println("Error: Division by zero is not allowed.");
} finally {
System.out.println("End of program.");
}
}
}
Output:
Error: Division by zero is not allowed.
End of program.
EXAMPLE- EXCEPTION-HANDLING
If an error occurs, we can use try...catch to catch the error and
execute some code to handle it:
Example
public class Main {
public static void main(String[ ] args) {
try {
int[] myNumbers = {1, 2, 3};
System.out.println(myNumbers[10]);
} catch (Exception e) {
System.out.println("Something went wrong.");
}
}
}
The output will be:
Something went wrong.
FINALLY STATEMENT
finally – A block of code that always executes (for
cleanup, closing files, releasing resources).
The finally statement lets you execute code, after
try...catch, regardless of the result:
Syntax:
try
{
// Code that may cause exception
} catch (ExceptionType e) {
// Handling code
} finally {
// Optional cleanup code
}
EXAMPLE- FINALLY STATEMENT
public class Main {
public static void main(String[] args) {
try {
int[] myNumbers = {1, 2, 3};
System.out.println(myNumbers[10]);
} catch (Exception e) {
System.out.println("Something went wrong.");
} finally {
System.out.println("The 'try catch' is finished.");
}
}
}
The output will be
Something went wrong.
The 'try catch' is finished
THE THROW KEYWORD
throw – Used to explicitly throw an exception.
The throw statement allows you to create a custom
error.
The throw statement is used together with an
exception type.
There are many exception types available in Java:
ArithmeticException, FileNotFoundException,
ArrayIndexOutOfBoundsException,
SecurityException, etc:
EXAMPLE-THE THROW KEYWORD
Throw an exception if age is below 18 (print "Access
denied"). If age is 18 or older, print "Access granted"
public class Main {
static void checkAge(int age) {
if (age < 18) {
throw new ArithmeticException("Access denied - You
must be at least 18 years old.");
}
else {
System.out.println("Access granted - You are old
enough!");
}
}
public static void main(String[] args) {
checkAge(15); // Set age to 15 (which is below 18...)
}
}
OUTPUT
The output will be:
Exception in thread "main" java.lang.ArithmeticException:
Access denied - You must be at least 18 years old.
at Main.checkAge(Main.java:4)
at Main.main(Main.java:12)
If age was 20, you would not get an exception:
Example
checkAge(20);
The output will be:
Access granted - You are old enough!
UNCAUGHT EXCEPTIONS
In Java, when an exception occurs, it must either be
caught (handled) by the program or declared in the
method using throws.
But if an exception is not handled properly, it is
called an uncaught exception.
In java, assume that, if we do not handle the
exceptions in a program. In this case, when an
exception occurs in a particular function, then Java
prints a exception message with the help of uncaught
exception handler.
The uncaught exceptions are the exceptions that are
not caught by the compiler but automatically caught
and handled by the Java built-in(default)
exception handler.
JAVA BUILT-IN(DEFAULT) EXCEPTION
HANDLER.
What the Default Handler Does?
When an exception is uncaught:
The program is terminated abruptly.
JRE prints an error message that includes:
Type of exception
Description of the exception
Location (method name, class name, line
number) where it occurred
A stack trace (a list of method calls leading to
the error)
EXAMPLE OF AN UNCAUGHT EXCEPTION
class UncaughtDemo
{
public static void main(String[] args)
{
int a = 10, b = 0;
int c = a / b;
// No try-catch block
System.out.println("Result: " + c);
}
}
Output:
Exception in thread "main"
java.lang.ArithmeticException: / by zero at
UncaughtDemo.main(UncaughtDemo.java:4)
USING TRY AND CATCH
The try block contains statements that may cause an
exception.
The catch block contains statements that handle the
exception.This prevents the program from terminating
abnormally.
A try-catch block in Java is a mechanism to handle
exceptions. This make sure that the application
continues to run even if an error occurs. The code
inside the try block is executed, and if any exception
occurs, it is then caught by the catch block.
EXAMPLE- USING TRY AND CATCH
class TryCatchExample {
public static void main(String[] args) {
int a = 10, b = 0;
int c;
try {
c = a / b; // Risky code: may throw ArithmeticException
System.out.println("Result: " + c);
}
catch (ArithmeticException e) {
System.out.println("Error: Division by zero is not allowed.");
}
System.out.println("Program continues after exception
handling.");
}
}
Output:
Error: Division by zero is not allowed.
Program continues after exception handling.
MULTIPLE CATCH CLAUSES(STATEMENTS)
A try block may generate more than one type of
exception.
To handle such cases, multiple catch clauses can be
attached to a single try block.
Each catch block is designed to handle a specific type
of exception.
The JVM searches the catch blocks in order and
executes the first one that matches the exception type.
MULTIPLE CATCH CLAUSES(STATEMENTS)
Syntax:
try {
// Risky code
}
catch (ExceptionType1 e1) {
// handler for ExceptionType1
}
catch (ExceptionType2 e2) {
// handler for ExceptionType2
}
catch (Exception e) {
// generic handler (catches all exceptions)
}
class SimpleMultipleCatch {
public static void main(String[] args) {
try {
EXAMPLE- MULTIPLE CATCH STATEMENT
int num = Integer.parseInt("ABC"); // May cause
NumberFormatException
int result = 10 / 0; // May cause ArithmeticException
}
catch (NumberFormatException e) {
System.out.println("Error: Invalid number format.");
}
catch (ArithmeticException e) {
System.out.println("Error: Division by zero.");
}
catch (Exception e) {
System.out.println("General Exception: " + e);
}
System.out.println("Program continues normally...");
}
}
OUTPUT
Possible Outputs
1. If "ABC" cannot be converted to integer
→
Error: Invalid number format.
Program continues normally...
2. If you change "ABC" to "20", then
division by zero occurs →Error: Division by
zero.
Program continues normally...
NESTED TRY STATEMENTS
A try block inside another try block is called a nested
try statement.
This is useful when a block of code inside a try can
itself cause another exception.
The inner try block handles its own exceptions.
If the inner block cannot handle an exception, it is
passed to the outer catch block.
SYNTAX: NESTED TRY STATEMENTS
try {
// outer try block
try {
// inner try block
}
catch (ExceptionType1 e) {
// handle exception of inner try
}
}
catch (ExceptionType2 e) {
// handle exception of outer try
}
class Geeks {
EXAMPLE- NESTED TRY STATEMENTS public static void main(String args[]) {
try { Output:
// Initializing array 5
Division by zero is not possible
int a[] = { 1, 2, 3, 4, 5 };
// Trying to print element at index 5
System.out.println(a[4]);
// Inner try block (try-block2)
try {
// Performing division by zero
int x = a[2] / 0; // This will throw ArithmeticException
} catch (ArithmeticException e2) {
System.out.println("Division by zero is not possible");
}
} catch (ArrayIndexOutOfBoundsException e1) {
System.out.println("ArrayIndexOutOfBoundsException");
System.out.println("Element at such index does not exist");
}
} }
USER-DEFINED EXCEPTIONS
Java provides many predefined exceptions (e.g.,
ArithmeticException,ArrayIndexOutOfBoundsExcepti
on).
Sometimes we need to create our own exceptions to
handle application-specific errors.
This is done by defining a new exception class that
extends Exception (checked) or RuntimeException
(unchecked).We use the throw keyword to explicitly
raise an exception.
Java provides us the facility to create our own
exceptions by extending the Java Exception class.
Steps to Create User-Defined Exception
1. Create a class that extends Exception.
2. Provide a constructor that calls the
superclass constructor (super).
3. Use throw to create and throw an object of
that class.
4. Handle it with a try–catch block.
EXAMPLE- USER-DEFINED EXCEPTIONS
// User-defined exception
class InvalidAgeException extends Exception {
public InvalidAgeException(String message) {
super(message);
} Output: Exception caught: Age must
} be 18 or above to vote.
class VotingApp {
public static void main(String[] args) {
int age = 15; // test age
try {
if (age < 18) {
throw new InvalidAgeException("Age must be 18 or above to vote.");
}
System.out.println("Eligible to vote!");
}
catch (InvalidAgeException e) {
System.out.println("Exception caught: " + e.getMessage());
}
}
}
GENERIC PROGRAMMING
Generic programming refers to writing code that will
work for many types of data.
“Write once, use for any type.”
Achieved by using type parameters that act as
placeholders for actual data types.
Instead of writing the same code multiple times for
different data types (e.g., int, float, String), we write
one generic version that can handle all.
Generics allow you to write classes, interfaces, and
methods that work with different data types, without
having to specify the exact type in advance.
This makes your code more flexible, reusable, and
type-safe.
ADVANTAGES- GENERIC PROGRAMMING
Code Reusability – Same code works with different
data types.
Type Safety – Errors are caught at compile-time, not
at runtime.
Readability and Maintainability – Reduces code
duplication and complexity.
Performance – No need for type casting or
boxing/unboxing.
GENERIC CLASSES
A class that can refer to any type is known as generic
class. Here, we are using T type parameter to create the
generic class of specific type.
A generic class declaration looks like a non-generic class
declaration, except that the
class name is followed by a type parameter section.
The most commonly used type parameter names are:
E - Element (used extensively by the Java Collections
Framework)
K - Key
N - Number
T - Type
V - Value
S,U,V etc. - 2nd, 3rd, 4th types
SYNTAX-GENERIC CLASS
• Where, the type parameter section, delimited by angle brackets (<>), follows the
class name. It specifies the type parameters (also called type variables)
// A generic class
EXAMPLE- GENERIC CLASS class Box<T> {
private T value;
public void set(T value) { Output:
this.value = value; Integer Value: 100
} String Value: Hello Generics
public T get() {
return value;
}
}
public class GenericExample {
public static void main(String[] args) {
// Box for Integer
Box<Integer> intBox = new Box<>();
int Box.set(100);
System.out.println("Integer Value: " + intBox.get());
// Box for String
Box<String> strBox = new Box<>();
strBox.set("Hello Generics");
System.out.println("String Value: " + strBox.get());
}
}
GENERIC METHOD
A Generic Method is a method with type parameter. We can
write a single generic method declaration that can be called
with arguments of different types. Based on the types of the
arguments passed to the generic method, the compiler
handles each method call appropriately.
Rules to define Generic Methods
All generic method declarations have a type parameter
section delimited by angle brackets (< and >) that precedes
the method's return type.
Each type parameter section contains one or more type
parameters separated by commas. A type parameter, also
known as a type variable, is an identifier that specifies a
generic type name.
The type parameters can be used to declare the return type
and act as placeholders for the types of the arguments
passed to the generic method, which are known as actual
type arguments.
A generic method's body is declared like that of any other
method. Note that type parameters can represent only
reference types, not primitive types (like int, double and
char)
SYNTAX- GENERIC METHOD
EXAMPLE- GENERIC METHOD
class GenericMethodExample {
// A generic method
public static <T> void printArray(T[] array) {
for (T element : array) {
System.out.print(element + " ");
}
System.out.println();
}
public static void main(String[] args) {
Integer[] intArray = {1, 2, 3, 4};
String[] strArray = {"Java", "C++", "Python"};
System.out.print("Integer Array: ");
printArray(intArray);
System.out.print("String Array: ");
printArray(strArray);
}
}
SPECIFIC COLLECTION INTERFACES
The Collection interface in Java is a core member of
the Java Collections Framework located in the
java.util package.
Java provides a Collections Framework (in java.util
package) with a set of interfaces and classes to handle
groups of objects.
It is one of the root interfaces of the Java Collection
Hierarchy. The Collection interface is not directly
implemented by any class. Instead, it is implemented
indirectly through its sub-interfaces like List, Queue,
and Set.
Two of the most widely used collection interfaces are
1) List Interface
2) Set Interface
SPECIFIC COLLECTION INTERFACES
Here are some common interfaces, along with their classes:
Interface Common Classes Description
List ArrayList, LinkedList Ordered collection that
allows duplicates
Set HashSet, TreeSet, LinkedHashSet Collection of unique
elements
1) LIST INTERFACE
The List interface is part of the Java Collections
Framework and represents an ordered collection of
elements.
A List in Java is an ordered collection that allows duplicate
elements.
Elements are stored in sequence, and we can access them
using an index.
List interface Maintains insertion order, Allows duplicate
elements, Supports index-based access.
Instead, you use a class that implements the List interface,
such as:
ArrayList - like a resizable array with fast random access
LinkedList - like a train of cars you can easily attach or
remove
EXAMPLE- LIST INTERFACE
import java.util.*;
public class ListDemo {
public static void main(String[] args) {
List<String> fruits = new ArrayList<>();
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Mango");
fruits.add("Apple"); // duplicate allowed
System.out.println("List Elements: " + fruits);
// Access using index
System.out.println("First Element: " + fruits.get(0));
}
}
Output:
List Elements: [Apple, Banana, Mango, Apple]
First Element: Apple
2. SET INTERFACE
A Set in Java is an unordered collection that does not
allow duplicate elements. Useful when we need to
store unique items only.
In set interface no duplicate elements allowed, No
index-based access (unordered), Different
implementations maintain order differently:
HashSet – no order.
LinkedHashSet – maintains insertion order.
TreeSet – maintains sorted order.
EXAMPLE- SET INTERFACE
import java.util.*;
public class SetDemo {
public static void main(String[] args) {
Set<String> cities = new HashSet<>();
cities.add("Pune");
cities.add("Mumbai");
cities.add("Delhi");
cities.add("Pune"); // duplicate ignored
System.out.println("Set Elements: " + cities);
}
}
Output: Set Elements: [Delhi, Pune, Mumbai]
METHODS OF COLLECTION INTERFACE
The Collection interface includes various methods that
can be used to perform different operations on objects.
These methods are available in all its subinterfaces.
add() - inserts the specified element to the collection
size() - returns the size of the collection
remove() - removes the specified element from the
collection
iterator() - returns an iterator to access elements of
the collection
addAll() - adds all the elements of a specified
collection to the collection
removeAll() - removes all the elements of the specified
collection from the collection
clear() - removes all the elements of the collection
COLLECTION CLASSES IN JAVA
Java provides Collection Classes inside the
Collections Framework (java.util package).
Two widely used classes that implement the List
interface are:
1) ArrayList
2) LinkedList
1) ARRAYLIST CLASS
ArrayList is a resizable (dynamic) array
implementation of the List interface.
Unlike arrays, it can grow or shrink dynamically as
elements are added or removed.
Key Features of ArrayList:
Maintains insertion order.
Allows duplicate elements.
Provides index-based access (like arrays).
Faster for searching and accessing (because it uses
index).
Internally uses a dynamic array.
1) ARRAYLIST CLASS
The difference between a built-in array and an
ArrayList in Java, is that the size of an array cannot
be modified (if you want to add or remove elements
to/from an array, you have to create a new one).
While elements can be added and removed from an
ArrayList whenever you want.
CREATE AN ARRAYLIST
To use an ArrayList, you must first import it from
java.util:
Create an ArrayList object called cars that will store
strings:
import java.util.ArrayList; // Import the ArrayList class
ArrayList<String> cars = new ArrayList<String>(); // Create an
ArrayList object
ADD ELEMENTS- ARRAYLIST
To add elements to an ArrayList, use the add() method:
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<String> cars = new ArrayList<String>();
cars.add("Volvo");
cars.add("BMW");
cars.add("Ford");
cars.add("Mazda");
System.out.println(cars);
}
}
Output: [Volvo, BMW, Ford, Mazda]
EXAMPLE: ARRAYLIST
import java.util.*;
public class ArrayListDemo {
public static void main(String[] args) {
ArrayList<String> students = new ArrayList<>();
// Adding elements
students.add("Amit");
students.add("Pooja");
students.add("Rahul");
students.add("Amit"); // duplicate allowed
System.out.println("ArrayList Elements: " + students);
// Accessing element by index
System.out.println("First Student: " + students.get(0));
// Removing element
students.remove("Rahul");
System.out.println("After Removing: " + students);
}
} Output:
ArrayList Elements: [Amit, Pooja, Rahul, Amit]
First Student: Amit
After Removing: [Amit, Pooja, Amit]
2. LINKEDLIST CLASS
LinkedList is a doubly linked list implementation of the List and
Deque interfaces.
It allows storage of duplicate elements and maintains insertion
order.
Key Features of LinkedList are Maintains insertion order.
Allows duplicates.
Better performance in insertion/deletion (compared to ArrayList).
Slower for searching and accessing (because traversal is
required).Can be used as List, Queue, or Deque.
EXAMPLE: LINKEDLIST
import java.util.*;
public class LinkedListDemo {
public static void main(String[] args) {
LinkedList<String> cities = new LinkedList<>();
// Adding elements
cities.add("Pune");
cities.add("Mumbai");
cities.add("Delhi");
cities.add("Pune"); // duplicate allowed
System.out.println("LinkedList Elements: " + cities);
// Adding at first and last
cities.addFirst("Nagpur");
cities.addLast("Chennai");
System.out.println("After Adding First & Last: " + cities);
// Removing element
cities.remove("Mumbai");
System.out.println("After Removing: " + cities);
}
} LinkedList Elements: [Pune, Mumbai, Delhi, Pune]
After Adding First & Last: [Nagpur, Pune, Mumbai, Delhi, Pune,
Chennai]
After Removing: [Nagpur, Pune, Delhi, Pune, Chennai]
DIFFERENCE BETWEEN ARRAYLIST AND LINKEDLIST
Parameters ArrayList LinkedList
Implementatio
Uses a dynamic array internally. Uses a doubly linked list internally.
n
Slower compared to LikedListTime Faster than ArrayListTime
Insertion
Complexity : O(N) Complexity : O(1)
Slower compared to LikedListTime Faster than ArrayListTime
Deletion
Complexity : O(N) Complexity : O(1)
Traverse Bidirectional Bidirectional
Fast searching Time Complexity : Fast searching Time Complexity :
Searching
O(N) O(N)
Random Access Fast Slow
Memory inefficient. It stores the
Memory efficient. It only stores the
Memory Usage object and the pointers to next and
object in the list.
previous nodes.
Memory Contiguous memory is allocated to
Contiguous memory is not allocated.
Allocation all the objects.
THANK YOU