Unit 2
Unit 2
2.1 Exception Handling: The Idea behind Exception, Exceptions & Errors, Types of
Exception, Control Flow in Exceptions, JVM Reaction to Exceptions, Use of try, catch,
finally, throw, throws in Exception Handling, In-built and User Defined Exceptions, Checked
and Un-Checked Exceptions.
2.2 Input /Output Basics: Byte Streams and Character Streams, Reading and Writing File in
Java.
2.3 Multithreading: Thread, Thread Life Cycle, Creating Threads, Thread Priorities,
Synchronizing Threads, Inter-thread Communication.
2.1 Exception Handling: One of the most effective mechanisms in Java for managing
runtime faults and preserving the regular operation of the application is exception handling.
An exception in Java is an occurrence that prevents the program from operating normally. It
is a runtime object that is thrown.
An approach to deal with runtime problems like ClassNotFoundException, IOException,
SQLException, RemoteException, etc. is called exception handling.
Benefits of Exceptional Management:
Preserving the application's regular flow is the fundamental benefit of exception handling.
Because an exception typically causes the application's usual flow to be disrupted, exception
handling is necessary. Let us examine an example:
In a Java program with ten statements, let's say an exception happens at statement five. In this
case, statements six through ten will not be performed. However, the remaining sentences
will be carried out when we handle exceptions. In Java, exception handling is used for this
reason.
2.1.1 The Idea behind Exception: An unwanted or unexpected occurrence that arises during
program execution, or during run time, which interferes with the program's instructions' usual
flow is referred to as an exception in Java. The application has the capability to detect and
manage exceptions. A method creates an object when an exception happens within it. We
refer to this object as the exception object. It includes details about the exception, including
its name, description, and the program's status at the time it happened.
Major reasons why an exception Occurs:
2.1.4 Control Flow in Exceptions: The exception is sent to the catch block, just like an
argument is passed into a method parameter, and the code in the (corresponding) catch block
is performed, if the type of exception that occurred is specified or handled in a catch block.
An issue (run time fault) that arose while a program was running is called an exception.
Compile-time exceptions, also referred to as checked exceptions, are those that elicit an
exception during the compilation process.
When an exception arises, the program stops suddenly at the line that raised it, stopping
execution of the remaining code. You must deal with exceptions if you want to avoid this.
Try, grab, and then block: Java includes a try-catch block method to manage exceptions.
The try block: Try blocks are positioned around code that could throw an exception.
Protected code is code that is enclosed in a try/catch block.
An exception simply propagates "up" to the caller if it arises outside of a try, catch and block.
There are several possible configurations for the control flow when an exception arises inside
a try, catch and block. The following scenarios are listed with indicators of the code blocks
that are part of the control flow in the given table:
Case try catch finally bottom
try throws no exception. y - y y
try throws a handled exception y y y y
try throws an unhandled exception y - y -
As demonstrated here, "bottom" in this context simply refers to any code that comes after the
finally block:
Example:
Test1.java
Example:
Test.java
Output:
Output:
2.1.6 Use of try: It is possible to provide a block of code that will be checked for mistakes
during execution by using the try statement. If an error happens in the try block, you may
specify a block of code that will be performed using the catch statement.
Try blocks in Java are used to contain code that has the potential to throw exceptions. The
method must be followed when using it.
The remainder of the block code won't run if an exception arises at that specific try block
statement. Therefore, it is advised against keeping code that won't throw an exception in the
try block.
Either the catch or finally blocks must come after the Java try block.
Syntax:
try
{
// statement(s) that might cause exception
}
2.1.7 Catch: The type of exception is declared within the argument and handled by the Java
catch block. Either the created exception type or the parent class exception (Exception) must
First, the JVM determines if the exception is handled or not. The JVM comes with a default
exception handler that takes care of the following functions in case the exception is not
handled:
Prints out exception description.
Prints the stack trace (Hierarchy of methods where the exception occurred).
Causes the program to terminate.
2.1.10 Throws in Exception Handling: For exception handling without a try and catch
block, utilize the throws keyword. It doesn't handle itself; instead, it describes the exceptions
that a method can throw to the caller.
A brief explanation of try, catch, finally. Throw and throws in below table:
Keyword Description
try This keyword is used to specify a block and this block must be followed by
either catch or finally. That is, we can‟t use try block alone.
catch This keyword must be preceded by a try block to handle the exception and
can be followed by a final block later.
finally This keyword is used to execute the program, whether an exception is
handled or not.
throw This keyword is used to throw an exception.
throws This keyword is used to declare exceptions.
2.2.1.2 Byte Stream: Data is processed byte by byte (8 bits) by byte streams. For instance,
FileOutputStream is used to write to the destination and FileInputStream is used to read from
the source.
2.2.2 Reading and Writing File in Java: Java provides the java.nio.file API to read and
write files. The InputStream class is the superclass of all classes representing an input stream
of bytes.
2.2.2.1 Reading files in Java: The Files.readAllBytes method can be used to read a text file.
The following listing illustrates how to use this approach.
To read a text file line by line into a List of type String structure you can use the
Files.readAllLines method.
Files.readAllLines uses UTF-8 character encoding. It also ensures that file is closed after all
bytes are read or in case an exception occurred.
2.2.2.1.1 Reading file line by line in Java: By providing a stream, the Files.lines method
enables reading a file line by line. It is possible to map and filter this stream. Try-with-
resource statements should enclose Files.lines since they don't close the file after its contents
are read.
The following example filters out empty lines and removes extra whitespace at the end of
each line.
2.2.2.2 Write file in Java: We'll look at many approaches of writing in a file using the Java
programming language. Because it is used in file handling in Java, the Java FileWriter class
is character-oriented and is used to write character-oriented data to files. In Java, there are
numerous classes and methods that can accomplish the following goals, hence there are
numerous ways to write into a file:
2.2.2.2.1 Using writeString() method: Java version 11 supports this approach. Four
parameters can be passed to this method. The file location, charset, character sequence, and
options are these. In order for this method to write into a file, the first two parameters must be
provided. The characters are written as the file's content. In addition to returning the file path,
it has four error types. It works well when the file's content is brief.
Example: It demonstrates how to put data into a file using the writeString() function under
the Files class. The filename is associated with a path where the content is to be written using
a different class called Path. The readString() function of the Files class allows you to read
the contents of any file that is currently in existence and verify that the content is written
correctly in the file.
2.2.2.2.2 Using FileWriter Class: Writing to the file with the FileWriter class is an even
better choice if the content of the file is brief. The writeString() method is also used to write
the character stream as the file's content. Both the default character encoding and buffer size
in bytes are defined by the constructor of this class.
The usage of the FileWriter class to write material to a file is demonstrated in the example
below. To write into a file, an instance of the FileWriter class object must be created using
the filename. The value of the text variable is then written to the file using the write()
method. An IOException will be raised and the error message will be written from the catch
block if there is a problem when writing the file.
2.2.2.2.4 Using FileOutputStream Class: The raw stream data is written to a file using it.
Only text can be written to a file using the FileWriter and BufferedWriter classes; binary data
can be written using the FileOutputStream class.
The following example illustrates how to use the FileOutputStream class to write data into a
file. To put data into a file, the class object must also be created with the filename. Here, the
write() method is used to transform the string content into a byte array that is written to the
file.
Process and Programs: All we have on our computers are programs (or a group of programs
called software) that we use as apps. These are the programs that run when we start an
application, and we use the Operating System, another program, to interface with these
programs.
So, if we give it some serious thought, there are only two possible states for these programs:
under execution and not under execution. All that means is that every program on your
computer is either in use or not. Thus, processes are programs that are in use or being carried
out.
Therefore, the following definition of a program and a process can be understood as follows:
"A process is a program under execution."
2.3.1 Thread: The smallest unit of a process is called a thread. Indeed, it is crucial to realize
that a thread is the smallest unit of a process, not a program, as a process is what executes
while a program does not. Here's an example to assist us comprehend this. Please take note
that this is not a precise explanation of how threads operate; rather, it is merely an example to
show what they are.
Each thread is autonomous. Other threads are unaffected if an exception occurs in one of
them. It makes use of shared memory.
2.3.1.1 Java Thread class: To accomplish thread programming, Java offers the Thread class.
Constructors and methods to generate and operate on a thread are provided by the Thread
class. The Thread class implements the Runnable interface and extends the Object class.
Java Thread Methods: The table below includes representations of various significant Java
methods.
2.3.2 Thread Life Cycle: A thread in Java is always present in any of the following states.
These states consist of:
1. New: a recently formed thread that is not yet in the execution phase.
2. Active: It is awaiting the distribution of resources and is either in operation or prepared for
execution.
3. Blocked / Waiting: Anticipating the acquisition of a monitor lock in order to enter or re-
enter a synchronized block or method and waiting for an untimed operation to be completed
by another thread.
The figure below depicts the various states that a thread goes through over its lifetime.
2.3.2.1 New: A new thread is always created in the newly created state. The code has not yet
been executed for a thread in the new state since it has not been run.
2.3.2.2 Active: A thread transitions from the new state to the active state when it calls the
start() function. There are two states that make up the active state: running and runnable.
2.3.2.2.1 Runnable: A thread that is ready to run is subsequently advanced to the runnable
state. In the runnable state, the thread can be running or ready to run at any time. It is the
thread scheduler's responsibility to provide thread time to run, i.e. move the thread into the
running state. When a thread calls start(), it transitions from the new state to the active state.
The active state has two states: runnable and running.
A program that a support multithreading allocates a fixed amount of time to each individual
thread. Each thread runs for a short period of time, and when that time slice is up, the thread
voluntarily hands over the CPU to the other thread, allowing the other threads to run for their
own slice of time. Whenever such a circumstance arises, all threads that are ready to run and
waiting for their turn to run are in the runnable state. In the runnable state, threads are stored
in a queue.
2.3.2.2.2 Running: When a thread receives the CPU, it transitions from the runnable to the
running state. The most common transition in a thread's state is from runnable to running,
then back to runnable.
2.3.2.3 Blocked/Waiting: When a thread is inactive for an extended period of time (but not
permanently), it is classified as either blocked or waiting.
2.3.2.4 Time Waiting: Sometimes waiting causes famine. For example, a thread (named A)
has entered a critical portion of code and refuses to leave it. In such a case, another thread
(named B) must wait indefinitely, resulting in starvation. To avoid this issue, thread B is set
to a timed waiting state. Thus, the thread is in a waiting state for a set amount of time, not
eternally. The sleep() method on a specified thread is a real-world example of timed waiting.
The sleep() function puts the thread into a timed wait state. When the timer runs out, the
thread wakes up and resumes its execution from where it left off before.
2.3.2.5 Terminated: A thread enters the termination state for the following reasons:
A terminated thread signifies that it is no longer in the system. In other words, the thread is
no longer active, and it cannot be respawned.
2.3.3 Creating Threads: There are two methods for creating a thread:
2.3.3.1 Thread class: Thread classes provide constructors and methods for creating and
operating with threads. Thread extends the Object class and implements the Runnable
interface.
Thread()
Thread(String name)
Thread(Runnable r)
Thread(Runnable r,String name)
2.3.3.2 Runnable interface: Any class that expects its instances to be executed by a thread
should implement the Runnable interface. The Runnable interface has only one function,
named run().
The start() function of the Thread class is used to initiate a freshly formed thread. It carries
out the following tasks:
2.3.4 Thread Priorities: Every thread has a priority. Priorities are represented by a number
from 1 to 10. In most circumstances, the thread scheduler assigns threads based on their
priority (known as pre-emptive scheduling). However, it is not assured because it is
dependent on the JVM specification as to which scheduling is chosen. It is worth noting that,
in addition to the JVM, a Java programmer can directly assign thread priority in a Java
program.
Priorities in threads is a concept in which each thread has a priority, which can be translated
into layman's terms as "every object" and is represented by numbers ranging from 1 to 10.
Let us look at how to get and set the priority of a thread in Java.
public final int getPriority(): The java.lang.Thread.getPriority() method returns the priority
of the given thread.
Java Synchronization is a superior solution when only one thread needs to access a shared
resource.
Java Synchronization is used to ensure that only one thread has access to a resource at any
given moment.
2. Thread Synchronization
Mutual Exclusive
Cooperation (Inter-thread communication in Java)
Synchronized method.
Synchronized block.
Static synchronization.
Polling refers to the frequent testing of a condition until it becomes true. Polling is often
implemented using loops to determine whether a specific condition is true or false. If the
statement is true, a certain action is executed. This costs numerous CPU cycles and renders
the implementation inefficient.
For example, in a classic queuing problem, one thread produces data while the other
consumes it.
To avoid polling, Java implements three methods: wait(), notify(), and notifyAll(). All of
these methods are final to the object class, ensuring that they are available to all classes. They
can only be utilized within synchronized blocks.
wait(): Tells the calling thread to release the lock and sleep until another thread
accesses the same monitor and uses notify().
notify(): It wakes up a single thread called wait() on the same object. Calling notify()
does not release a lock on a resource.
notifyAll(): This function wakes up all threads that called wait() on the same object.
2.3.6.1 wait() method: The wait() method forces the current thread to relinquish the lock and
wait until another thread calls the notify() or notifyAll() methods on this object, or until a
certain period of time has passed.
The current thread must own this object's monitor, therefore it can only be called from the
synchronized method; otherwise, it will throw an exception.
Method Description
public final void wait()throws It waits until object is notified.
InterruptedException
public final void wait(long timeout)throws It waits for the specified amount of time.
InterruptedException
2.3.6.2 notify() method: The notify() method activates a single thread that is waiting on the
object's monitor. If any threads are waiting for this object, one of them is selected to be
awakened. The decision is arbitrary and made at the discretion of the implementation.
2.3.6.3 notifyAll() method: All threads waiting on the monitor of this object are woken up.
Syntax: