Enotes - Unit 3 - Java Programming
Enotes - Unit 3 - Java Programming
VANIYAMBADI
PG Department of Computer Applications
I M.C.A - Semester - II
Unit: 3 – Packages– Package Hierarchy, Import Statement, Hiding the Classes, Access
Control Modifiers, Exception Handling – Default Exception – User Defined Exception
Handling, Exception and Error Classes, Throw and Throws. Threading– Life Cycle,
Creating and Running, Methods in Thread Class, Priority Thread, Synchronization, Dead
Lock, Inter Thread Communication.
Overview
Packages
Exception Handling
Threading
A package in Java is used to group related classes. Think of it as a folder in a file directory. We use
packages to avoid name conflicts, and to write a better maintainable code.
1. Built-in Packages
Built-in Packages comprise a large number of classes that are part of the Java API. Some of the
commonly used built-in packages are:
[Link]: Contains language support classes(e.g, classes that define primitive data types, math
operations). This package is automatically imported.
[Link]: Contains classes for supporting input/output operations.
[Link]: Contains utility classes that implement data structures such as Linked Lists and
Dictionaries, as well as support for date and time operations.
[Link]: Contains classes for creating Applets.
[Link]: Contains classes for implementing the components for graphical user interfaces (like
buttons, menus, etc).
}
} // Output Random number: 59
2. User-defined Packages
User-defined Packages are the packages that are defined by the user.
Example:
package [Link];
import [Link];
[Link]();
In Java, we can import classes from a package using either of the following methods:
import [Link];
This imports only the Vector class from the [Link] package.
import [Link].*;
This imports all classes and interfaces from the [Link] package but does not include sub-
packages.
Advantages of Packages
Package Hierarchy
Packages can contain sub-packages, forming a hierarchical structure similar to directories. Packages can
be nested, forming a hierarchy similar to folders in a file system.
Example Hierarchy
java
└── util
└── ArrayList
Code Example
package [Link];
This means:
3. Import Statement
The import statement allows access to classes defined in other packages without using their fully
qualified names.
Types of Import
import [Link];
import [Link].*;
A class declared without public is accessible only within the same package
Example
class HiddenClass {
// accessible everywhere
Rule: A source file can have only one public class, and its name must match the file name.
Java access modifiers are used to specify the scope of the variables, data members, methods, classes, or
constructors. These help to restrict and secure the access (or, level of access) of the data.
There are four different types of access modifiers in Java, we have listed them as follows:
Default access modifier allows class members to be accessed only within the same package.
Default access modifier means we do not explicitly declare an access modifier for a class, field,
method, etc.
A variable or method declared without any access control modifier is available to any other class in the
same package. The fields in an interface are implicitly public static final and the methods in an
interface are by default public.
Variables and methods can be declared without any modifiers, as in the following examples –
// File: [Link]
package pack1;
// File: [Link]
package pack1;
class B {
public static void main(String[] args) {
A obj = new A(); // allowed (same package)
[Link]();
}
}
This works because both classes are in the same package (pack1).
Access from Another Package (Not Allowed)
// File: [Link]
package pack2;
class C {
public static void main(String[] args) {
A obj = new A(); // ❌ERROR
}
}
Error occurs because class A has default access and is not visible outside its package.
Diagram
Package pack1 Package pack2
------------- -------------
class A --------X----> Not Accessible
class B
Methods, variables, and constructors that are declared private can only be accessed within the declared
class itself.
Private access modifier is the most restrictive access level. Class and interfaces cannot be private.
Variables that are declared private can be accessed outside the class, if public getter methods are present
in the class.
Using the private modifier is the main way that an object encapsulates itself and hides data from the
outside world.
Example 1
[Link](x);
void display()
{ // default method
class B {
// [Link](); // ❌ERROR
[Link](); // ✔ allowed
A class, method, constructor, interface, etc. declared public can be accessed from any other class.
Therefore, fields, methods, blocks declared inside a public class can be accessed from any class
belonging to the Java Universe.
However, if the public class we are trying to access is in a different package, then the public class still
needs to be imported. Because of class inheritance, all public methods and variables of a class are
inherited by its subclasses.
Syntax
// Class One
class One {
public void printOne() {
[Link]("printOne method of One class.");
}
}
Variables, methods, and constructors, which are declared protected in a superclass can be accessed only
by the subclasses in other package or any class within the package of the protected members' class.
The protected access modifier cannot be applied to class and interfaces. Methods, fields can be declared
protected, however methods and fields in a interface cannot be declared protected.
Protected access gives the subclass a chance to use the helper method or variable, while preventing a
nonrelated class from trying to use it.
Example:
package [Link].pack1;
class Animal
{
protected String name;
protected void makeSound() {
[Link]("Animal makes a sound");
}
}
Output:
This scenario highlights a key feature of protected: accessibility across package boundaries via
inheritance
package [Link].pack1;
package [Link].pack2;
Output:
Brand: Ford
Tuut, tuut!
Model: Mustang
Exception handling is a mechanism to handle runtime errors, allowing the normal flow of a
program to continue. Exceptions are events that occur during program execution that disrupt the
normal flow of instructions.
The try statement allows you to define a block of code to be tested for errors while it is
being executed.
The catch statement allows you to define a block of code to be executed, if an error
occurs in the try block.
The try and catch keywords come in pairs:
Syntax
try {
// Block of code to try
}
catch(Exception e) {
// Block of code to handle errors
}
class Geeks{
int n = 10;
int m = 0;
try
int ans = n / m;
catch (ArithmeticException e)
[Link](myNumbers[10]); // error!
at [Link]([Link])
Note: ArrayIndexOutOfBoundsException occurs when you try to access an index number that does not
exist.
If an error occurs, we can use try...catch to catch the error and execute some code to handle it:
Example
try {
[Link](myNumbers[10]);
} catch (Exception e) {
Default exception usually refers to the built-in exceptions that the Java runtime throws automatically
when an error occurs. Java doesn’t have a single exception literally called “DefaultException”, but it has
a default exception handling mechanism and default runtime exceptions.
If an exception occurs and you do not handle it using try-catch, Java uses its default exception handler,
which:
Example
class Test {
int a = 10 / 0; // ArithmeticException
Output
at [Link]([Link])
try {
int x = 10 / 0;
} catch (ArithmeticException e) {
An exception is an unwanted or unexpected event that occurs during the execution of a program, i.e., at
run time, that disrupts the normal flow of the program’s instructions. In Java, there are two types of
exceptions:
•Checked Exception: These exceptions are checked at compile time, forcing the programmer to
handle them explicitly.
• Unchecked Exception: These exceptions are checked at runtime and do not require explicit
handling at compile time.
If a method throws a checked Exception, then the exception must be handled using a try-catch block and
declared the exception in the method signature using the throws keyword.
Example
import [Link].*;
class Geeks {
[Link]([Link]());
[Link]();
} catch (FileNotFoundException e) {
} catch (IOException e) {
Unchecked exception are exceptions that are not checked at the compile time. In Java, exceptions under
Error and RuntimeException classes are unchecked exceptions, everything else under throwable is
checked.
Consider the following Java program. It compiles fine, but it throws an ArithmeticException when run.
The compiler allows it to compile because ArithmeticException is an unchecked exception.
class Geeks {
// Here we are dividing by 0 which will not be caught at compile time as there is no mistake but caught
at runtime because it is mathematically incorrect
int x = 0;
int y = 10;
int z = y / x;
}
}
Note:
• Unchecked exceptions are runtime exceptions that are not required to be caught or declared in a
throws clause.
• These exceptions are caused by programming errors, such as attempting to access an index out
of bounds in an array or attempting to divide by zero.
• Unchecked exceptions include all subclasses of the RuntimeException class, as well as the
Error class and its subclasses.
Java throw
The throw keyword in Java is used to explicitly throw an exception from a method or any block of code.
We can throw either checked or unchecked exception. The throw keyword is mainly used to throw
custom exceptions.
Where instance is an object of type Throwable (or its subclasses, such as Exception).
Example:
class Geeks {
try {
catch (NullPointerException e) {
try {
fun();
catch (NullPointerException e) {
[Link]("Caught in main.");
Output
Caught in main.
Java throws
throws is a keyword in Java that is used in the signature of a method to indicate that this method might
throw one of the listed type exceptions. The caller to these methods has to handle the exception using a
try-catch block.
Example
class Geeks {
try {
fun();
catch (IllegalAccessException e) {
[Link]("Caught in main.");
Output
Inside fun().
Caught in main.
Difference Between throw and throws
The main differences between throw and throws in Java are as follows:
throw throws
finally clause
A finally keyword is used to create a block of code that follows a try block. A finally block of
code is always executed whether an exception has occurred or not. Using a finally block, it lets you run
any cleanup type statements that you want to execute, no matter what happens in the protected code. A
finally block appears at the end of catch block.
In this example, we are using finally block along with try block. This program throws an exception and
due to exception, program terminates its execution but see code written inside the finally block
executed. It is because of nature of finally block that guarantees to execute the code.
class Demo
try
catch(ArrayIndexOutOfBoundsException e) {
[Link]("Exception caught");
finally
Output
Out of try
[Link]
Errors and exceptions are both types of throwable objects, but they represent different types of
problems that can occur during the execution of a program.
Errors are usually caused by serious problems that are outside the control of the program, such as
running out of memory or a system crash. Errors are represented by the Error class and its
subclasses. Some common examples of errors in Java include:
OutOfMemoryError: Thrown when the Java Virtual Machine (JVM) runs out of memory.
StackOverflowError: Thrown when the call stack overflows due to too many method
invocations.
NoClassDefFoundError: Thrown when a required class cannot be found.
Since errors are generally caused by problems that cannot be recovered from, it's usually not
appropriate for a program to catch errors. Instead, the best course of action is usually to log the
error and exit the program.
Exceptions, on the other hand, are used to handle errors that can be recovered from within the
program. Exceptions are represented by the Exception class and its subclasses. Some common
examples of exceptions in Java include:
Since exceptions can be caught and handled within a program, it's common to include code to
catch and handle exceptions in Java programs. By handling exceptions, you can provide more
informative error messages to users and prevent the program from crashing.
In summary, errors and exceptions represent different types of problems that can occur during
program execution. Errors are usually caused by serious problems that cannot be recovered from,
while exceptions are used to handle recoverable errors within a program.
In java, both Errors and Exceptions are the subclasses of [Link] class. Error refers
to an illegal operation performed by the user which results in the abnormal working of the
program. Programming errors often remain undetected until the program is compiled or
executed. Some of the errors inhibit the program from getting compiled or executed. Thus errors
should be removed before compiling and executing. It is of three types:
Compile-time
Run-time
Logical
Whereas exceptions in java refer to an unwanted or unexpected event, which occurs during the
execution of a program i.e at run time, that disrupts the normal flow of the program’s
instructions.
Example : Run Time Error
class StackOverflow {
// non-stop recursion.
if (i == 0)
return;
else {
test(i++);
[Link](5);
}
Threads
Threads allows a program to operate more efficiently by doing multiple things at the same time.
Threads can be used to perform complicated tasks in the background without interrupting the
main program.
Creating a Thread
It can be created by extending the Thread class and overriding its run() method:
Extend Syntax
Implement Syntax
Running Threads
If the class extends the Thread class, the thread can be run by creating an instance of the class
and call its start() method:
Extend Example
[Link]();
[Link]("This code is outside of the thread");
If the class implements the Runnable interface, the thread can be run by passing an instance of
the class to a Thread object's constructor and then calling the thread's start() method:
Implement Example
[Link]();
The major difference is that when a class extends the Thread class, you cannot extend any other
class, but by implementing the Runnable interface, it is possible to extend from another class as
well, like: class MyClass extends OtherClass implements Runnable.
Concurrency Problems
Because threads run at the same time as other parts of the program, there is no way to know in
which order the code will run. When the threads and main program are reading and writing the
same variables, the values are unpredictable. The problems that result from this are called
concurrency problems.
Example
[Link]();
[Link](amount);
amount++;
[Link](amount);
amount++;
To avoid concurrency problems, it is best to share as few attributes between threads as possible.
If attributes need to be shared, one possible solution is to use the isAlive() method of the thread
to check whether the thread has finished running before using any attributes that the thread can
change.
Example
[Link]();
while([Link]()) {
[Link]("Waiting...");
}
amount++;
amount++;
Life Cycle:
In Java, a thread goes through several states from creation to termination. These states are
defined in the [Link] enum.
1. New State
2. Runnable State
3. Blocked State
4. Waiting State
5. Timed Waiting State
6. Terminated State
The diagram below represents various states of a thread at any instant:
Life Cycle of a Thread
New Thread: When a new thread is created, it is in the new state. The thread has not yet
started to run when the thread is in this state. When a thread lies in the new state, its code
is yet to be run and has not started to execute.
Runnable State: A thread that is ready to run is moved to a runnable state. In this state, a
thread might actually be running or it might be ready to run at any instant of time. It is the
responsibility of the thread scheduler to give the thread, time to run. A multi-threaded
program allocates a fixed amount of time to each individual thread. Each and every
thread get a small amount of time to run. After running for a while, a thread pauses and
gives up the CPU so that other threads can run.
Blocked: The thread will be in blocked state when it is trying to acquire a lock but
currently the lock is acquired by the other thread. The thread will move from the blocked
state to runnable state when it acquires the lock.
Waiting state: The thread will be in waiting state when it calls wait() method or join()
method. It will move to the runnable state when other thread will notify or that thread
will be terminated.
Timed Waiting: A thread lies in a timed waiting state when it calls a method with a
time-out parameter. A thread lies in this state until the timeout is completed or until a
notification is received. For example, when a thread calls sleep or a conditional wait, it is
moved to a timed waiting state.
Terminated State: A thread terminates because of either of the following reasons:
o Because it exits normally. This happens when the code of the thread has been
entirely executed by the program.
o Because there occurred some unusual erroneous event, like a segmentation fault
or an unhandled exception.
In Java, to get the current state of the thread, use [Link]() method to get the current state
of the thread. Java provides [Link] enum that defines the ENUM constants for
the state of a thread, as a summary of which is given below:
1. New
2. Runnable
Thread state for a runnable thread. A thread in the runnable state is executing in the Java virtual
machine but it may be waiting for other resources from the operating system such as a processor.
Thread state for a thread blocked waiting for a monitor lock. A thread in the blocked state is
waiting for a monitor lock to enter a synchronized block/method or reenter a synchronized
block/method after calling [Link]().
4. Waiting
Thread state for a waiting thread. A thread is in the waiting state due to calling one of the
following methods:
5. Timed Waiting
Thread state for a waiting thread with a specified waiting time. A thread is in the timed waiting
state due to calling one of the following methods with a specified positive waiting time:
[Link]
[Link] with timeout
[Link] with timeout
[Link]
[Link]
6. Terminated
Thread state for a terminated thread. The thread has completed execution.
Thread t;
MyThread(String name)
[Link]();
@Override
try
[Link](2000);
catch(InterruptedException e)
{
MyThread thread1 = new MyThread("First Thread");
try
[Link](1000);
[Link]();
catch(InterruptedException e)
State: NEW
State: RUNNABLE
First Thread: 1
State: TIMED_WAITING
First Thread: 2
First Thread: 3
State: TERMINATED
[Link]();
2. run()
// task
3. sleep(long millis)
[Link](1000);
4. join()
[Link]();
5. yield()
Temporarily pauses the current thread and allows other threads of the same priority to
execute.
Static method.
[Link]();
6. interrupt()
7. isAlive()
[Link]("MyThread");
[Link]([Link]());
[Link](Thread.MAX_PRIORITY);
10. currentThread()
Thread t = [Link]();
11. getState()
Method Purpose
We can use the following methods of the Thread class to manage thread priority:
getPriority(): This method is used to returns the current priority of the thread.
super(name);
[Link](
[Link]().getName()
[Link](Thread.MIN_PRIORITY); // 1
[Link](Thread.NORM_PRIORITY); // 5
[Link](Thread.MAX_PRIORITY); // 10
// Start threads
[Link]();
[Link]();
[Link]();
Output
Explanation:
MyThread extends Thread and overrides run(), which prints the thread’s name and
priority.
Threads have default priority 5, which can be changed between 1–10 using setPriority().
The code sets t1=1, t2=5, t3=10 and prints their priorities.
On calling start(), each thread runs concurrently; higher priority may get preference, but
actual order depends on the OS thread scheduler.
What is a thread's priority used for in Java? To control the order of thread execution
[Link]
Synchronization
What Is Synchronization?
Synchronization is the technique used to control the access of multiple threads to shared
resources. It ensures that only one thread can access a critical section of code at a time,
thus preventing conflicts, data inconsistency, or race conditions.
Consider a scenario where two threads try to update the same bank account balance at the
same time. If both read the same initial balance and then write their changes back without
coordination, the final result will be incorrect.
This kind of problem is known as a race condition, and synchronization prevents it by making
sure only one thread can perform a sensitive operation at a time.
There are two types of thread synchronization mutual exclusive and inter-thread communication.
1. Mutual Exclusive
1. Synchronized method.
2. Synchronized block.
3. static synchronization.
Mutual Exclusive
Mutual Exclusive helps keep threads from interfering with one another while sharing data. This
can be done by three ways in java
1. by synchronized method
2. by synchronized block
3. by static synchronization
1. Synchronized Method
Dead Lock
Deadlock is a situation in multithreading where two or more threads are permanently blocked
because each one is waiting for the other to release a required lock. In simple terms, threads get
stuck forever, and the program never continues.
Each thread holds a lock and waits for another lock held by a different thread.
[Link]();
[Link]();
synchronized (Lock1) {
try { [Link](10); }
catch (InterruptedException e) {}
synchronized (Lock2) {
[Link]("Thread 1: Holding lock 1 & 2...");
synchronized (Lock2) {
try { [Link](10); }
catch (InterruptedException e) {}
synchronized (Lock1) {
Output
Let's change the order of the lock and run of the same program to see if both the threads still wait
for each other −
[Link]();
[Link]();
synchronized (Lock1) {
try {
[Link](10);
} catch (InterruptedException e) {}
synchronized (Lock2) {
synchronized (Lock1) {
try {
[Link](10);
} catch (InterruptedException e) {}
synchronized (Lock2) {
Output