Core JAVA
Core JAVA
Unit Structure
4.1 Introduction
• Compile-time errors
• Run-time errors
Compile-Time Errors Exception Handling
All syntax errors are detected and displayed by the Java compiler and
hence these errors are known as compile-time errors. Whenever the
compiler displays an error, it will not create the .class file. Therefore, it is
necessary that we fix all the errors before we can successfully compile and
run the program.
Program 4.1 Illustration of compile-time errors
/*This program contains an error*/
class Error1
{
public static void main (String[] args)
{
System.out.println("Hello, World!")//Missing;
}
}
The Java compiler does a nice job of telling us where the errors have
occurred in the program. For example, if we have missed the semicolon at
the end of print statement in Program 4.1, the following message will
appear on the screen.
We can now go to the appropriate line, correct an error and recompile the
program. Sometimes, a single error may be the source of multiple errors
later in the compilation. For example, use of an undeclared variable in
several places will cause a series of errors of type “undefined variable”.
In such case, we should consider the earliest errors as the major source of
problem. Once we fix an error, we should recompile the program and look
for other errors.
Most of the compile-time errors are due to typing mistakes. Typographical
errors are hard to find, and we may have to check code word by word. The
most common problems are:
• Missing semicolons
• Missing (or mismatch of) brackets in classes and methods
• Misspelling of keywords and identifiers
• Missing double quotes in strings
• Using undeclared variables
• Use of = in place of == operator and so on.
Core JAVA Other errors may occur because of directory paths. An error such as
System.out.println("b=" +y);
}
Program 4.2 is syntactically correct and therefore does not cause any Exception Handling
problem during compilation. However, during execution, it displays the
following message and stops without executing remaining statements.
4.3 EXCEPTIONS
An exception is a condition caused by a run-time error in the program.
When the Java interpreter encounters an error such as dividing an integer
by zero, it creates and throws an exception object (i.e., informs us that an
error has occurred). If the exception object is not caught and handled
properly, the interpreter will display an error message as shown in the
output of Program 4.2 and will terminate the program.
If we want our 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.
The purpose of exception handling is to detect and report an “exceptional
circumstance” so that appropriate action can be taken. Error handling code
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)
Error handling code consists of two segments, one to detect errors and to
throw exceptions and the other to catch exceptions and take appropriate
actions.
While writing programs, we must check for places in the program where
an exception could be generated. Some common exceptionsare listed in
Table 4.1
Core JAVA Table 4.1 Common java Exceptions
}
catch (Exception- type e)
{
statement ; //processes the exception
}
………………………..
………………………..
The try block can have one or more statements that could generate an
exception. If any one statement generates an exception, the remaining
statements in the try block are skipped and execution jumps to the catch
block that is placed immediately next to the try block.
The catch block can have one or more statements that are necessary to
process the exception. Every try statement should be followed by at least
one catch statement; otherwise compilation error will occur.
The catch statement works like a method definition. A single parameter,
which is reference to the exception object is thrown (by the try block). If
the catch parameter matches with the type of exception object, then the
exception is caught and statements in the catch block will be executed.
Otherwise, the exception is not caught, and the default exception handler
will cause the execution to terminate.
Program 4.3 illustrates the use of try and catch blocks to handle an
arithmetic exception. Note that program 4.3 is a modified version of
Program 4.2.
Core JAVA
Program 4.3 Using try and catch for exception handling
class Error3
{
public static void main(String[] args)
{
int x = 10;
int y = 5;
int z = 5;
try
{
inta = x/(y-z); //Exception here
}
catch(ArithmeticException e)
{
System.out.println("Division by zero");
}
int b = x/(y+z);
System.out.println("b=" +y);
Note that the program did not stop when an exception is caused inside try
block. Exception is caught by catch block and it prints the error message,
and then continues the execution, as if nothing has happened. Compare
with the output of Program 4.2 which did not give the value of y.
Program 4.4 shows another example of using exception handling
mechanism.
Program 4.4 Example of ArrayIndexOutOfBoundsException Exception Handling
class TryCatchExample
{
}
Output:
In this program we have array which contains 4 elements i.e arr[0], arr[1],
arr[2], arr[3]. We are printing arr[4] which doesn’t exist in the array list.
Hence ArrayIndexOutOfBoundsException is caused by try block and
caught by catch block.
Note that the array element a [10] does not exist because array a is defined
to have only five elements, a[0], a[1], a[2], a[3], a[4]. Therefore, the index
10 is outside the array boundary thus causing the block
catch (ArrayIndexOutofBoundsException e)
to catch and handle the error. Remaining catch blocks are skipped.
{
System.out.println("ArrayIndexOutOfBounds Exception occurs");
}
catch(ArithmeticException e)
{
System.out.println("Arithmetic Exception occurs");
}
catch(Exception e)
{
System.out.println("Parent Exception occurs");
}
finally
{
System.out.println("rest of the code");
}
}
}
This will produce the same output.
}
else
{
System.out.println("You are eligible for voting");
}
}
public static void main(String args[])
{
validate(10); //calling the function
System.out.println("Rest of the code...");
}
}
A run of Program 4.6 produces:
import java.io.*;
class Main1
{ Exception Handling
The object e which contains the error message “Number is too small” is
caught by the catch block which then display’s the message using the
getMessage() method.
Note that Program 4.8 also illustrates the use of finally block. The last
line of output is produced by the finally block.
4.8 USING EXCEPTION FOR DEBUGGING Exception Handling
4.9 SUMMARY
A good program does not produce unexpected results. We should
incorporate features that could check for potential problem spots in
programs and guard against program failures. Exceptions in Java must be
handled carefully to avoid any program failures.
In this chapter we have discussed the following:
✓ What exceptions are
✓ try,catch and finally block
✓ How to catch and handle different types of exceptions.
✓ How to throw system exceptions
4.10 TEXTBOOK(S):
1) Herbert Schildt, Java The Complete Reference, Ninth Edition,
McGraw-Hill Education, 2014
4.12 QUESTIONS:
❖❖❖❖
MULTITHREADING
Unit Structure
5.1 Introduction
5.8 Summary
5.9 Textbook
5.10 Additional Reference(s)
5.11 Questions
5.1 INTRODUCTION
Those who are familiar with the modern operating systems (Windows 10)
may recognize that they can execute several programs simultaneously.
This ability is known as multitasking. In system's terminology, it is called
multithreading.
Multithreading is a conceptual programming paradigm where a program
(process) is divided into two or more subprograms (processes), which can
be implemented in parallel. This is similar to dividing one task into
subtasks and assigning them to different people for execution
independently and simultaneously. For example, one subprogram can
display an animation on the screen while another may build the next
animation to be displayed.
In most computers, there is only a single processor and therefore, in
reality, the processor does only one thing at a time. However, the
processor switches between the processes so fast that it appears to human
beings that all of them are being executed simultaneously. Java programs
that we have seen and discussed so far contain only a single sequential
flow of control. This is what happens when we execute a normal program.
The program begins, runs through a sequence of executions, and finally
ends. At any given point of time, there is only one statement under
execution.
A thread is similar to a program that has a single flow of control. It has a
Multithreading
beginning, a body, and an end, and executes commands sequentially. All
main programs in our earlier (previous chapters) examples can be called
single-threaded programs. Every program will have at least one thread as
shown in Fig. 5.1
Once initiated by the main thread, the threads A, B run concurrently and
share the resources jointly. It is like people living in joint families and
sharing certain resources among all of them. Since threads in Java are
subprograms of a main application program and share the same memory
space, they are known as lightweight threads or lightweight processes.
It is important to remember that 'threads running in parallel' does not
really mean that they are running at the same time. Since all the threads
are running on a single processor, the flow of execution is shared between
the threads. The Java interpreter handles the switching of control between
the threads in such a way that it appears they are running concurrently.
Multithreading is a powerful programming tool that makes Java distinctly
different from its fellow programming languages. Multithreading enables
programmers to do multiple things at same time. They can divide a long
program (containing operations that are conceptually concurrent) into
threads and execute them in parallel. For example, we can send print
command into the background and continue to perform some other task in
the foreground. This approach would considerably improve the speed of
our programs.
Any application we are working on that requires two or more things to be
done at the same time is probably a best one for use of threads.
{
……………………..
……………………..
(statements for implementing thread)
……………………….
……………………….
}
The run( ) method should be invoked by an object of the concerned
thread. This can be achieved by creating the thread and initiating it with
the help of another thread method called start().
A new thread can be created in two ways.
1. By creating a thread class:
Define a class that extends Thread class and override its run( ) method
with the code required by the thread.
{
……………………..
……………………. //Thread code here
………………………
………………………
}
When we start any new thread, Java calls the thread's run( ) method, so it
is the run ( ) where all the action takes place.
❖ Starting New Thread
To create and run an instance of our thread class, we will write:
TestThread t1 = new TestThread();
Program 5.1 illustrates the use of Thread class for creating and running
threads in an application. In program we have created two threads A and B
for undertaking two different tasks. The main method in the ThreadTest1
class also constitutes another thread which we may call the "main thread".
The main thread dies at the end of its main method. However, before it
dies. it creates and starts other two threads A, B.
We can start a thread as follows:
A t1 = new A();
t1.start();
Immediately after the thread A is started, there will be two threads running
in the program: the main thread and the thread A.
The start() method returns back to the main thread immediately after
invoking the run( ) method, thus the allowing the main thread to start the
thread B.
Program 5.1 Creating threads using the thread class
class A extends Thread
{
public void run()
{
for (int i =1; i<=5; i++)
{
System.out.println("Thread A: i=" +i);
}
System.out.println("Exit from A");
}
}
class B extends Thread
{
public void run()
{
for (int j =1; j<=5; j++)
{
System.out.println("Thread B: j=" +j);
}
Core JAVA System.out.println("Exit from B");
}
}
class Threadtest1
{
public static void main(String args[])
{
A t1 = new A();
B t2 = new B();
t1.start(); //start first thread
t2.start(); //start second thread
}
}
Output:
First run
Second run
Third run
Multithreading
By the time the main thread has reached the end of its main method, there
are a total of three separate threads running in parallel.
We have simply initiated two new threads and started them. We did not
hold on to them further. They are running concurrently on their own. Note
that the outputs from the threads are not sequential. They do not follow
any specific order.
They are running independently of one another and each executes
whenever it has a chance. Remember, once the threads started. We cannot
decide with certainty the order in which they may execute statements.
Note a second run and third run has a different output sequence.
These methods cause the thread to go into the blocked (or not-runnable)
state.
Core JAVA The thread will return to the runnable state when the specified time is
elapsed in the case of sleep( ).
The resume() method is invoked in the case of suspend( ), and the notify
( ) method is called in the case of wait( ).
Newborn State
When we create a thread object, the thread is born and is said to be in
newborn state. The thread is not yet scheduled for running. At this state,
we can do only one of the following things with it:
✓ We can schedule it for running using start() method.
✓ We can kill it using stop() method.
If scheduled, it moves to the runnable state (Fig. 5.4). If we attempt to use
any other method at this stage, an exception will be thrown.
Multithreading
3) It has been told to wait until some event occurs. It is done using the
wait() method.
The thread can be scheduled to run again using the notify() method.
{
public void run()
{
if(k==1)
try
{
sleep(2000);
}
catch(Exception e)
{
}
}
}
}
Output:
Program 5.2 uses the yield() method in thread A at the iteration i=1.
Therefore, the thread A, although started first, has relinquished its control
to the thread B.
The thread B started sleeping after executing for loop only once.
When it woke up (after 2000 milliseconds), the other thread has already
completed its runs and therefore was running alone.
The main thread died much earlier than the other two threads.
{
…………………… //code here is synchronized
……………………
}
Whenever a thread completes its work of using synchronized method (or
block of code), it will hand over the monitor to the next thread that is
ready to use the same resource.
A deadlock situation may occur when two or more threads are waiting to
gain control of a resource. Due to some reason, the condition on which the
waiting threads rely on to gain control does not happen.
For example, assume that the thread X must access Method1 before it can
release Method2, but the thread Y cannot release Method1 until it gets
hold of Method2. Because these are mutually exclusive conditions, a
deadlock occurs. The code below illustrates this:
Thread X
synchronized method2 ()
{
synchronized method1()
{
……………………
…………………… Multithreading
}
}
Thread Y
synchronized method1 ()
{
synchronized method2 ()
{
……………………
……………………
}
}
5.8 SUMMARY
A thread is a single line of execution within a program. Multiple threads
can run concurrently in any single program.
A thread is created either by sub classing the Thread class or
implementing the Runnable interface. Careful application of
multithreading will considerably improve the execution speed of Java
programs.
5.9 TEXTBOOK
Herbert Schildt, Java The Complete Reference, Ninth Edition, McGraw-
Hill Education, 2014
5.11 QUESTIONS
1. What is thread? Explain the life cycle of thread.
2. Explain the synchronization of thread.
3. Write a java program to implement the concept of thread.
❖❖❖❖