Java Programming
History
Green Team Project
Java was developed by a team of computer professionals under the guidance of James Gosling at Sun Microsystems. Java development project had been started to develop software to embed into television or any other digital devices for interaction purpose. The team members of java development project are known as Green Team. The project began in June 1991.
Why the name ‘java’?
The team initially selected ‘oak’ as the name of their programming language since oak is a symbol of strength and also honored as national tree of many countries like USA, Germany etc.
Later in 1995 the name changed to ‘java’ since ‘oak’ is already taken as trade mark by Oak Technologies.
Java is the name of an island of Indonesia where the first coffee was produced. The name ‘java’ is selected by James Gosling while having coffee.
In 1995, Sun Micro System the developer of java is taken over by Oracle.
Java is simple, scalable, object oriented, general purpose, case sensitive and strongly typed programming language.
Features of JAVA Language:
- Platform Independent: Java is both software and hardware platform independent.
- Object Oriented: pure object oriented language which doesn’t allow methods without classes and data without objects.
- Easy to Learn: the syntax of java looks similar to C/C++
- Robust(reliable): java eliminated all complex concepts found in C/C++ like pointers, multiple inheritance and operator overloading. It also provides automatic de-allocation of memory and powerful exception handling features.
- Secure
- Multi-Threaded
- Dynamic
- High-performance
JVM ARCHITECTURE
JVM stands for Java Virtual Machine which is also known as run-time engine that is the reason behind platform independence ability of java (both hardware and software). A java program can be considered like compiled as well as interpreted (Write Once and Run Anywhere).
The source code file of java program will be saved with .java extension. The compiled java program creates a java byte code file with .class extension. The byte code is handled by JVM of the platform on which program is executing. The JVM translates the byte code into such a language that can be understandable by the machine based on its platform (operating system or configuration).
VM Vs JDK Vs JRE
JDK stands for Java Development Kit that contains everything needed to develop java program along JRE.
JRE is also known as Java Runtime Environment consists of JVM, class libraries, compiler, debugger and other files required to run java program.
Using JRE you can run java program but not develop it.
JVM or Java Virtual Machine is component of JRE and handles the bytecode and enable us to run java program on a particular platform.
INSTALLATION OF JDK & ECLIPSE IDE SETUP
You need to have JDK installed before you setup any IDE for java program development. You can download the latest version of java by clicking on the following link:
https://www.oracle.com/java/technologies/javase-downloads.html
The following screen would appear:
Clicking on JDK download link you can download java standard edition version 13
But if you want to download any previous version, you can scroll down the above page for that.
Clicking any of JDK download link you can the following page:
Click on the desired download link based on the o/s type of your system.
It will ask you to accept the license agreement with the screen:
After that click on the download button to start downloading.
IDE stands for Integrated Development Environment which provides all facilities for developing programs in a single environment.
Popular IDEs for java program development are Eclipse, IntelliJ, JDeveloper, BlueJ, JCreator and many others.
BASIC STRUCTURE OF JAVA PROGRAM
Here is a sample java program that displays a welcome message as output.
/*First Java Application*/
public class application
{
public static void main(String args[])
{
System.out.println(“This is my first java program”);
}
}
What is System.out.println?
System is a class of java.lang package
out is a static variable of System class of PrintStream type
println() is a method of PrintStream class
If any change in the syntax of main method, the program can be able to compile but at runtime you will get NoSuchMethodError: main Error
Acceptable changes to the main method in java program
The arguments of main method can be written in any of the following form:
String[] args
String []args
String args[]
String… args
String[] <anyOtherIdentifier>
The following additional modifiers are allowed in the header of main mehod
final
synchronized
strictfp
DATA TYPES & VARIABLES
Data Type specifies the format, range of values and memory requirement of data that a data element can hold.
Hierarchy of Data Types in Java:
- Primitive
- Integral
- Numeric
- Integer
- Byte
- Short
- Int
- long
- Decimal
- Float
- double
- Character
- Integer
- Boolean
- Non-Primitive
- Class
- Array
Range of Signed Values for any Data Type based on its Memory Requirement:
Minimum Value: -2(n-1)
Maximum Value: +2(n-1) – 1
Range of Unsigned Values for any Data Type based on its Memory Requirement:
Minimum Value: 0
Maximum Value: +2(n-1)
Java Primitive Data types
Data type | Description | Example | Groups |
Byte | Byte-lenth integer | 10, 24 | Integer |
Short | Short Integer | 500, 786 | |
Int | Integer | 89, 945, 37865 | |
Long | Long Integer | 89L, -945L | |
Float | Single-precision floating point | 89.5f, -32.5f | Floating point Numbers |
Double | Double-precision floating point | 89.5, -35.5, 87.6E5 | |
Char | Single Character | ‘c’, ‘9’, ‘t’ | Characters |
Boolean | Boolean value (0 or 1) | True or False | Boolean |
In most of the languages, the format and size of primitive data types depend on the platform on which a code is running. But in Java programming language, size and format of its primitive data types is specified.
Integer & Floating-point numbers fall under Numeric datatypes. Java has six numeric datatypes that differ in size and precision of the numbers they can hold. The Size means how many bits are needed to represent the data type. The Range of a data type expresses the precision of numbers.
Four categories of Integer data types
Type | Values | Default | Size | Range |
Byte | Signed int | 0 | 8 bits (1 byte) | -128 to 127 |
Short | Signed int | 0 | 16 bits(2 bytes) | -32768 to 32767 |
Int | Signed int | 0 | 32 bits (4 bytes) | -2147483648 to 2147483647 |
Long | Signed int | 0 | 64 bits(8 bytes) | -9223372036854775808 to 9223372036854775807 |
Float Data types
Float | IEEE 754 floating point | 0.0 | 32 bits | +/- 1.4e-45 to +/- 3.4028235e+38, +/- infinity, +/-0, NAN |
double | IEEE 754 floating point | 0.0 | 64 bits | +/- 4.9e-324 to +/- 1.7976931348623157e+308, +/- infinity, +/-0, NAN |
Character Data type
Type | Values | Default | Size | Range |
Char | Unicode Character | \u0000 | 16 bits | \u0000 to \uFFFF |
Boolean data type
Type | Values | Default | Size | Range |
Boolean | True, False | False | 1 bit used in 32 bit integer | NA |
Keywords:
A keyword or reserved word in Java has a special meaning and cannot be used as a user defined identifier, because they are used by the compiler and if you use them as variable names, compiler will generate errors.
Keywords (53)
Keywords (50)
Used keywords(48)
Primitive data type (8): byte, short, int, long, float, double, char, boolean
Control flow (11): if, else, for, do, while, switch, case, break, continue, default, return
Modifiers (11): public, protected, private, static, final, abstract, synchronized, native, transient, volatile, strictfp
Exception Handling (6): try, catch, throw, throws, finally, assert
Class Related(7): class, interface, enum, extends, implements, import, package
Object related(4): this, super, instanceof, new
Return type(1): void
Unused keywords (2): goto, const
Reserved Words (3): true, false, null
Keywords in Java and their meaning/purpose:
abstract | It declares that a class or method is abstract |
assert | Used to specify assertions |
boolean | Declares that variable is Boolean type |
break | Used to exit a loop before end of the loop is reached |
byte | Declares that variable is byte type |
case | To represent different conditions in switch statement |
catch | Used for handling exceptions, i.e., capture the exceptions thrown by |
some actions |
|
char | Declares that variable is character type |
class | Signals the beginning of a class definition |
const | This keyword is reserved by Java but now it is not in use |
continue | Prematurely return to the beginning of a loop |
default | Default action in switch statement |
do | Begins a do while loop |
double | Declares that variable is double type |
else | Signals the code to be executed when if condition executes to false |
extends | Specifies the class base from which the correct class is inherited |
final | Declares that a class may not be extended or that a field or method may |
not be overridden |
|
finally | Declares a block of code guaranteed to be executed |
float | Declares a floating point variable |
for Start a for loop |
|
goto | This keyword is reserved by Java but now it is not in use |
if | Keyword to represent conditional statement |
implements | Declares that this class implements the given interface |
import | permits access to a class or group of classes in a package |
Instance of | tests whether an object is an instance of a class |
int | Declares an integer variable |
interface | signals the beginning of an interface definition |
long | Declares a long integer variable |
native | Declares that a method that is implemented in native code |
new | Allocates memory to an object dynamically |
package | Defines the package to which this source code file belongs |
private | Declares a method or member variable to be private |
protected | Declares a class, method or member variable to be protected |
public | Declares a class, method or member variable to be public |
return | Returns a value from a method |
short | Declares a short integer variable |
static | Declares that a field or a method belongs to a class rather than an object |
strictfp | To declare that a method or class must be run with exact IEEE 754 semantics |
super | A reference to the parent of the current object |
switch | Tests for the truth of various possible cases |
synchronized | Indicates that a section of code is not thread-safe |
this | A reference to the current object |
throws | Declares the exceptions thrown by a method |
transient | Data should not be serialized |
try | Attempt an operation that may throw an exception |
void | Declare that a method does not return a value |
volatile | Warns the compiler that a variable changes asynchronously |
while | Begins a while loop |
The words true, false, and null are reserved words. Keywords ‘const’ and ‘goto’ are currently not in use. In this list of Keywords the new Keywords have also been added, for exapmle Java 1.2 adds the strictfp keyword to declare that a method or class must run with exact IEEE 754 semantics. Java 1.4 adds the assert keyword to specify assertions.
DECLARATION AND INITIAISATION OF VARIABLES
Variables:
Variable represent memory location in which value can be stored.
3 kinds of variables in java:
- Instance variables: used to define the attributes of a particular object
- Class variables: their values apply to all the instances of a class rather than having different values for each object
- Local variables: declared and used inside methods
The declaration of variable is free to put anywhere in the program, but before its first use.
Rules for naming a variable:
Variable name cannot start with any symbol other than _ or $
Java is case sensitive
variable name can’t contain a white space
there is no limit for the length of variable name
Variable can be initialized at the time of declaration or dynamically.
Example program that initialize the variable dynamically:
/*program that calculates the hypotenuse of a triangle based on its height ‘h’ and base ‘b’, using formula : square root of [h2+b2]*/
class DynamicInitialization
{
public static void main(String args[])
{
double h=3.0, b=4.0;
double c= Math.sqrt(h*h+b*b); //Dynamic Initialization
System.out.println(“Required Hypotenuse is”+c);
}
}
TYPES OF OPERATORS
Operator is basically a symbol that represents an operation. Operators in java are divided into the following categories based on the type of operation they perform.
- Arithmetic Operators
- Binary: works with two operands Eg: Addition, Subtraction etc
- Unary: works with single operand Eg: Increment operator
- Assignment Operators
- Relational Operators
- Boolean Operators
- Bitwise Operators
- Class and Object Operators
- Other Operators
Arithmetic Operators
Binary Operators | ||
Operator | Use | Description |
+ | A+B | Adds A and B |
– | A-B | Subtracts B from A |
* | A*B | Multiplies A by B |
/ | A/B | Divides A by B |
% | A%B | Computes the remainder of dividing A by B |
Unary Operators | ||
Operator | Use | Description |
++ Post increment | A++ | The value is assigned before the increment is done Eg: A=1; B=A++; B will hold 1 and A will hold 2 |
++ Pre increment | ++A | The value is assigned after the increment is done Eg: A=1; B=++A; B will hold 2 and A will hold 2 |
— Post Decrement | A– | Value is assigned before the decrement is made eg: A=1; B=A–; B will hold 1 and A will hold 0 |
— Pre Decrement | –A | Value is assigned after the decrement is made eg: A=1; B=–A; B will hold 0 and A will hold 0 |
Assignment Operators
The basic assignment operator ‘=’ is used to assign value to the variables. For example A = B; in which we assign value of B to A. Similarly, let us see how to assign values to different data types.
int Integer = 100; float Float = 10.5; char Character = ‘S’; boolean aboolean = true;
With basic assignment operator, the Java programming language defines short cut assignment operators that allow you to perform arithmetic, shift, or bitwise operation with one operator.
Now let us see, if you want to add a number to a variable and assign the result back into the same variable, so you will write something like i = i + 2; but using shortcut operator ‘+=’ You can shorten this statement, like i += 2. But remember, i = i + 2; and i += 2; both statements are the same for the compiler.
Use of Shortcut Assignment Operators
Assignment Operators | Use | Equivalent to |
+= | A += B | A=A+B |
-= | A -= B | A=A-B |
*= | A *= B | A=A*B |
/= | A /= B | A=A/B |
%= | A %= B | A=A%B |
&= | A &= B | A=A&B |
|= | A |= B | A=A|B |
^= | A ^= B | A=A^B |
<<= | A <<= B | A=A<<B |
>>= | A >>= B | A=A>>B |
>>>= | A >>>= B | A=A>>>B |
Relational Operators
Relational operators also called, comparison operators, are used to determine the relationship between two values in an expression.
Relational Operators
Operator | Use | Returns true if |
> | A>B | A is greater than B |
>= | A>B | A is greater than equal to B |
< | A>B | A is less than B |
<= | A>B | A is less than or eqal to B |
== | A>B | A and B are equal |
!= | A>B | A and B are not equal |
Boolean Operators
Boolean operators allow you to combine the results of multiple expressions to return a single value that evaluates to either true or false.
Bitwise operators
As you know in computers data is represented in binary (1’s and 0’s) form. The binary representation of the number 43 is 0101011. The first bit from the right to left in the binary representation is the least significant bit, i.e. here value is 1. Each Bitwise operator allows you to manipulate integer variables at bit level.
Bitwise operators
As you know in computers data is represented in binary (1’s and 0’s) form. The binary representation of the number 43 is 0101011. The first bit from the right to left in the binary representation is the least significant bit, i.e. here value is 1. Each Bitwise operator allows you to manipulate integer variables at bit level.
Class and Object Operators
Operator Precedence
The operators in this table are listed in order of the following precedence rule: the higher in the table an operator appears, the higher its precedence. In an expression, operators that have higher precedence are
evaluated before operators that have relatively lower precedence. Operators on the same line have equal precedence.
When operators of same precedence appear in the same expression, some rule must govern which is evaluated first. All binary operators except for the assignment operators are evaluated in left-to-right order and assignment operators are evaluated right to left.
CONTROL STATEMENTS
Statement is a line of executable code that ends with a semicolon (;)
Code Block is a group of two or more statements between curly braces.
Control Statements:
Statement Type | Keyword |
Selection | If-else, Switch-case |
Iteration | While, do-while, for |
Jump | Break, continue, label, return |
Exception handling | Try-catch-finally, throw |
ARRAYS
An Array is a fixed length data structure that stores multiple data elements of same data type. All the elements of an array share the same name, and they are distinguished from one another with the help of an index.
Arrays are supported directly by the Java programming language but there is no array class. The length of an array is established when the array is created (at runtime). After creation, an array is a fixed-length structure.
Syntax of array declaration is as follows:
data-type arrayName [];
The following are some of declarations for arrays:
float[] marks;
boolean [] gender;
Object[] listOfObjects;
String[] NameOfStudents;
The declaration of array doesn’t allocate memory for it. Array must be initialized before using.
Array size must be defined or its size must be specified to allocate required memory space for its elements. For that new operator can be used. The new is an operator that is used to allocate memory for the data element.
The memory size of an array is equivalent to the total size of all its elements.
Definition of array:
int arr[] = new int[5];
(or)
int arr[];
arr=new int[5];
(or)
int arr[]={1,3,5,7,9};
The last definition is also known as declaration with initialisation.
The initialisation of any data element is nothing but storing some values by the developer. Any data element must be initialised before its first use.
//example program to show how array can be declared and defined
public class sample{
public static void main(String[] args){
int arr[]={1,3,5,7,9};
for(int i=0;i<5;i++)
System.out.println(arr[i]);
}
}
//sample program to show how values can be stored in displayed for an array
import java.util.Scanner;
public class Example1 {
public static void main(String[] args) {
int a[];
a=new int[5];
Scanner s=new Scanner(System.in);
for(int i=0;i<a.length;i++) {
System.out.println(“Enter value for Array Element “+(i+1));
a[i]=s.nextInt();
}
System.out.println();
System.out.println(“******************* \n”);
System.out.println(“Value of Array are: \n”);
System.out.println(“******************* \n”);
for(int i=0;i<5;i++)
System.out.println(“Element No”+(i+1)+”: “+a[i]);
}
}
length in the above program is not a method, it is a property provided by the Java platform for all arrays.
For-each loop for Array:
This is the special syntax of for loop provided by java language to work with array elements. For loop is more shortened to work with array elements.
Syntax:
for(datatype Var : ArrName)
System.out.println(Var);
//Example program how for-each loop can be used for array elements
public class ForEachExample {
public static void main(String[] args) {
int a[]= {1,3,5,7,9};
for(int i:a)
System.out.println(i);
}
}
ArrayIndexOutOfBoundsException
Java does not permit to access array beyond its limit which is possible in C or C++. The Java Virtual Machine (JVM) throws an ArrayIndexOutOfBoundsException if length of the array in negative, equal to the array size or greater than the array size while traversing the array.
Multi-Dimensional Array
Array with single dimension can store a row of many data elements. Each data element of single dimensional array can be considered as a field or column. But an array may have many rows of data. Such arrays can be useful to store tabular format of data. This type of arrays known as two dimensional arrays.
It is also possible an array is three dimensional, four dimensional or even n-dimensional. But it becomes complex for developer to manage the data.
Example syntaxes of multi-dimensional arrays:
Two dimensional array:
int[][] Ar2D = new int[10][20];
Three dimensional array:
int[][][] Ar3D = new int[10][20][30];
The number of elements of a multi-dimensional array can be calculated by multiplying all dimensions.
The tabular format of element representation of a Two Dimensional Array:
Arr [3][5]
[0,0] | [0,1] | [0,2] | [0,3] | [0,4] |
[1,0] | [1,1] | [1,2] | [1,3] | [1,4] |
[2,0] | [2,1] | [2,2] | [2,3] | [2,4] |
//Example program to show how 2D array can be initialised and printed in tabular form
public class TwoDArray {
public static void main(String[] args) {
int a[][]= {{1,3,5},{2,4,6}}; //array of 2×3
for(int i=0;i<2;i++)
{
for(int j=0;j<3;j++)
System.out.print(a[i][j]+” “);
System.out.println();
}
}
}
CLASSES AND OBJECTS
A class is a user-defined data type in java. A class can consist of group of values and operations to manipulates these values. The variables of class are known as Objects.
General form of class:
class className
{
datatype varName_1;
datatype varName_2;
….
datatype varName_n;
rtype method_1(arguments)
{
….
…
}
rtype method_2(arguments)
{
….
…
}
…
…
rtype method_n(arguments)
{
….
…
}
}
The data and methods of a class are known as its members.
All objects of a class will have their individual copy of data members but share the global copy of methods.
Creating an object involves the following two steps:
- Declaration of object
- bind the object to its class
The new operator of java dynamically allocates memory for an object, returns a reference(address) to the object and binds the reference with the object.
//example program to define a class student
class student
{
String name;
String course;
int age;
void display_info()
{
System.out.println(“Student Information”);
System.out.println(“Name:”+name);
System.out.println(“Course:”+course);
System.out.println(“Age:”+age)
}
}
class Display_test
{
public static void main(String args[])
student s1; //declaration
s1=new student(); // memory allocation
s1.name= “Mr. Rajendra Prasad”;
s1.course= “Java Programming”;
s1.age= “23”;
s1.display_info();
}
Initialisation of variables is must in programming languages. If the data elements are not initialized before they are used in executable statements it leads unexpected results.
Since class is a user defined data type out of which objects can be declared, the object has the responsibility of initializing its members.
Initialisation of variables can be done in two ways:
- through .(dot) operator
- through constructors
Initializing data members of class is possible only when the class definition is known. To over come this problem, OOP languages are equipped with a mechanism called constructor.
A constructor is a special member method of the class. It is special because of the following characteristics:
- The name of constructor is same as its class name
- It is not mandatory to define constructor for the class since it is available by default.
- There will be no return type in the definition of constructor
- Constructor is not required to be invoked separately.
- Constructor cannot be abstract, static, final and synchronized
- Access Modifiers can be used for constructor declaration. It controls the object creation. In other words, we can have public, protected, private or default constructors.
//java program to show how constructor can be used to intialise class objects
class sample
{
int a;
float b;
sample()
{
a=1;
b=2;
}
void showData()
{
System.out.println(“a=”+a+”\n”+”b=”+b);
}
}
public class ConstructorExample1 {
public static void main(String[] args) {
sample s;
s=new sample();
s.showData();
}
}
The default constructor is also called as non-parameterised constructor. But it is possible to pass arguments for the constructor. Then it is known as parameterized constructor. The parameterized constructor can be used to provide different values to each object.
Overloading Constructors
Overloading is a concept of Object-Oriented Programming using which a method may have more than one definition.
It is not mandatory to define default constructor. But when a constructor is overloaded, then it is mandatory to define default constructor.
//java program to show how constructor can be overloaded and used to intialise class objects
class sample
{
int a;
float b;
sample(int x, float y) //overloaded constructor with parameters
{
a=x;
b=y;
}
sample() //redefining default constructor
{
a=1;
b=2;
}
void showData()
{
System.out.println(“a=”+a+”\n”+”b=”+b);
}
}
public class ConstructorExample {
public static void main(String[] args) {
sample s;
s=new sample(10,15.5f);
s.showData();
sample t=new sample();
t.showData();
}
}
Copying Object
An object can be copied so that the values of its data members are duplicated into the corresponding data members of another object of same class.
Copy object can be done in 3 ways:
- Reference object or Shallow copy
- Deep Copy
- Cloning
Reference Object or Shallow Copy
Reference object is an object that is used as an alias for the existing object of same class.
//Example java program that assign an object directly to another object
class person
{
String name;
int age;
String address;
void display()
{
System.out.println(“Person Information:”+name+ “( ” +age “)” +“\n” +address);
}
}
class AssignObjectDirect
{
public static void main(String[] args)
{
person p= new person();
person q= new person();
p.name= “Mr. Naveen Kumar”;
p.age=24;
p.address= “248,Sector 22, Noida”;
p.display();
q=p;
q.name= “Mr. Suresh”;
q.address= “22, Mahanandi, New Delhi”;
p.display();
q.display();
}
}
In the above program both object p and q are referring to same memory location.
Deep Copy
In this method, we will create two separate objects with their respective constructors and then initialize each data member of second object with separate assignment statements.
//Example code showing Deep Copy
class best
{
int a;
float b;
void showData()
{
System.out.println(“Data from object”+this);
System.out.println(“a= “+this.a+”\n”+”b= “+this.b);
}
}
public class CopyObjectExample {
public static void main(String[] args) {
best s1=new best();
s1.a=2;
s1.b=3.4f;
s1.showData();
best s2=new best();
s2.a=s1.a; //Deep Copy method
s2.b=s1.b;
s2.showData();
s3.a=4; //s3 is a separate object but not alias
System.out.println(“Now, value of member a in s3 = “+s3.a);
}
}
clone() of Object class:
This method requires knowledge of inheritance and exception handling. Hence we will discuss it after the said chapters.
Copy Constructor
There is no pre-defined copy constructor in java like C++. But we can define our own copy constructor using deep copy method.
//Example code showing how copy constructor can be defined
class copy
{
int a;
float b;
copy()
{
}
copy(copy c)
{
a=c.a;
b=c.b;
}
void getData()
{
System.out.println(“value of a is: “+a);
System.out.println(“value of b is: “+b);
}
}
public class CopyConstructor {
public static void main(String[] args) {
copy s1=new copy();
copy s2=new copy(s1);
s2.getData();
}
}
this Keyword
If a method wants to refer the object through which it is invoked, it can refer to by using this keyword. This resolves the name conflicts between local and instance variables inside the definition of a method.
//example program to demonstrate use of this keyword.
class testThis
{
int rate, amount, interest;
testThis()
{
rate=5;
amount=5000;
}
testThis(int r, int a)
{
rate=r;
amount=a;
}
void totalInterest()
{
int rate=5;
rate=this.rate+rate;
interest=rate*amount/100;
System.out.println(“Interest rate for this object is:” +rate);
System.out.println(“Total interest on ” +amount+ ” is:” +interest);
}
}
class thisTest
{
public static void main(String args[])
{
testThis obj1=new testThis();
testThis obj2=new testThis(10,5000);
obj1.totalInterest();
obj2.totalInterest();
}
}
Passing Objects as parameters:
Since objects are the variables of class, they can be passed as arguments to methods and can be returned by the methods.
In general, passing arguments(regular variables) to a method can be done in two ways:
- call by value
- call by reference
In the case of passing of entire object to method can be considered as call by reference since formal argument in the method definition can become alias (reference) to the actual argument.
If you want to implement call by value method through object passing then you have to use deep copy method.
//Example1
class Data {
int x;
int y;
Data(int a, int b)
{
x=a;
y=b;
}
}
public class ObjPassArg {
public static void main(String[] args) {
Data obj=new Data(2,4);
show(obj);
System.out.println(“values of class members after show() method: “+obj.x+”and “+obj.y);
}
static void show(Data obj2)
{
obj2.x++;
obj2.y++;
System.out.println(“values of class members inside show() method: “+obj2.x+”and “+obj2.y);
}
}
//Example2
class Demo
{
int a, b;
Demo(int i, int j)
{
a = i;
b = j;
}
// return true if o is equal to the invoking
// object notice an object is passed as an
// argument to method
boolean equalTo(Demo o)
{
return (o.a == a && o.b == b);
}
}
//Driver class
public class ObjPassDemo
{
public static void main(String args[])
{
Demo ob1 = new Demo(100, 22);
Demo ob2 = new Demo(100, 22);
Demo ob3 = new Demo(-1, -1);
System.out.println(“ob1 == ob2: ” + ob1.equalTo(ob2));
System.out.println(“ob1 == ob3: ” + ob1.equalTo(ob3));
}
}
//Example3 for both call by value and reference
class Data {
int x;
int y;
Data(int a, int b)
{
x=a;
y=b;
}
}
public class SwapValRef {
public static void main(String[] args) {
Data s=new Data(4,5);
System.out.println(“Data in the object before calling SwapVal method”);
System.out.println(“x= “+s.x+”y= “+s.y);
swapVal(s.x,s.y);
System.out.println(“Data in the object after called SwapVal method”);
System.out.println(“x= “+s.x+”y= “+s.y);
System.out.println(“Data in the object before calling SwapRef method”);
System.out.println(“x= “+s.x+”y= “+s.y);
swapRef(s);
System.out.println(“Data in the object after called SwapRef method”);
System.out.println(“x= “+s.x+”y= “+s.y);
}
static void swapVal(int x, int y)
{
int temp;
temp=x;
x=y;
y=temp;
System.out.println(“Data of the object inside SwapVal method”);
System.out.println(“x= “+x+”y= “+y);
}
static void swapRef(Data o)
{
int temp;
temp=o.x;
o.x=o.y;
o.y=temp;
System.out.println(“Data of the object inside SwapRef method”);
System.out.println(“x= “+o.x+”y= “+o.y);
}
}
Object can be also returned from a method to its caller. For this, we have to use its class name as return type in the header of method definition.
//example program that demonstrate method returning objects
class salary
{
int basic;
String empId;
salary(String a, int b)
{
empId=a;
basic=b;
}
salary incSal(salary s)
{
s.basic=basic*110/100;
return s;
}
}
public class ObjRet {
public static void main(String[] args) {
salary s1=new salary(“I100”,5000);
salary s2;
System.out.println(“Previous Basic Salary is:” +s1.basic);
s2=s1.incSal(s1);
System.out.println(“Previous Basic Salary is:” +s1.basic);
System.out.println(“Incremented Basic Salary is:” +s2.basic);
}
}
Method Overloading
A method can be said overloaded when it contains more than one definition but similar name. Each definition may take different number and types of arguments.
class test
{
int area(int i)
{
return i*i;
}
int area(int a,int b)
{
return a*b;
}
}
class overloadTest
{
public static void main(String args[])
{
test t=new test();
int area;
area=t.area(5);
System.out.println(“Area of Square is:” +area);
area=t.area(5,4);
System.out.println(“Area of Rectangle is:” +area);
}
}
Garbage Collection
Garbage collection is the process of automatically freeing objects that are no longer referenced by the program. It is automatically performed by JVM.
Finalised() method can be used to free allocated memory resources manually.
Properties of finalized() method:
- every class inherits the finalized() method from Java.lang.Object class
- garbage collector automatically calls it.
- finalized method does nothing but it can be overloaded to clean-up non-java resources such as closing files, taking file handle etc.
Inheritance
Inheritance describes the ability of one class or object to possess characteristics and functionality of another class or object in the hierarchy.
Inheritance is a language property specific to the object-oriented paradigm. Inheritance is used for a unique form of code-sharing by allowing you to take the implementation of any given class and build a new class based on that implementation.
For example class B, starts by inheriting all of the data and operations defined in the class A. This new subclass can extend the behaviour by adding additional data and new methods to operate on it. Basically during programming inheritance is used for extending the existing property of a class. In other words it can be said that inheritance is “from generalization- to-specialization”. In this by using general class, class with specific properties can be defined.
To inherit a class into another class extends keyword is used. For example, SavingAccount class will inherit BankAccount class as given below.
class BankAccount
{
data members
member functions
}
class SavingAccount extends BankAccount
{
data members
member functions
}
Types of Inheritance
- Single or Single Level Inheritance
- Multi-Level Inheritance
- Hierarchical Inheritance
A class derived from the superclass is called the subclass. Sometime superclass is also called parent class or base class and subclass is called as child class or derived class. The subclass can reuse the data member and methods of the superclass that were already implemented and it can also extend or replace the behaviour in the superclass by overriding methods. Subclass can have its own data members and member functions.
In any type of inheritance, it is usually we create object from the down level class since it is most specialised in the hierarchy. But it does not mean that we cannot create object from parent classes in the inheritance.
//java program demonstrates inheritance
class first
{
void firstMethod()
{
System.out.println(“Message from First class”);
}
}
class second extends first
{
void secondMethod()
{
System.out.println(“Message from Second class”);
}
}
class third extends second
{
void thirdMethod()
{
System.out.println(“message from Third class”);
}
}
class four extends third
{
void fourthMethod()
{
System.out.println(“Message from Fourth class”);
}
}
class testInheritance
{
public static void main(String args[])
{
four fc=new four();
fc.firstMethod();
fc.secondMethod();
fc.thirdMethod();
fc.fourthMethod();
}
}
//Example program for Multi level Inheritance
class superClass
{
void superMethod()
{
System.out.println(“Super class called”);
}
}
class firstSub extends superClass
{
void firstMethod()
{
System.out.println(“Message from First Subclass”);
}
}
class secondSub extends superClass
{
void secondMethod()
{
System.out.println(“Message from second sub class”);
}
}
class multilevelTest
{
public static void main(String args[])
{
firstSub fs=new firstSub();
secondSub ss=new secondSub();
fs.superMethod();
fs.firstMethod();
ss.superMethod();
ss.secondMethod();
}
}
ACCESS AND NON-ACCESS MODIFIERS
What is an Access Modifier?
Access Modifiers are used to control the accessibility of data members or member methods of a class to its objects and rest of the program.
Access Specifier Vs Access Modifier
There are no Access Specifiers in java but only Access Modifiers. If we have not mentioned any Access modifier then the member’s access level is considered as default access.
How many types of Access Modifiers?
- Access Modifiers: they are used to modify the default accessibility of any program element (i.e. class, method, data member, interface etc)
- Non-Access Modifiers: these are used for not to change the accessibility but some specific functionality of program element or behaviour of program element with JVM.
Both Access and Non-access Modifiers can be applied to program elements like class(outer or inner), methods, constructors, data members, interfaces. But some of access and Non-access modifiers cannot be used with certain program elements.
Since we have studied only class (that too top-level class), object and constructor, we are only discussing about meaning of access and non-access modifiers for class, members and constructors only in this chapter. We will discuss meaning of access and non-access modifiers regarding other program elements later in this course.
The three access modifiers of java are:
Private – Basic meaning of this modifier is accessible within the class among the members.
Public – Accessible anywhere (i.e. outside the package or even other project also)
Protected – Accessible to subclasses and package only
Is there any default modifier?
No, there is no default modifier but default access level. If no access modifier is specified, then the program element may have default access level (also known as package-private). There is no keyword called ‘default’ declare default accessibility. Here you should not confuse with a keyword ‘default’ which we use in switch case block.
Table showing visibility of program elements defined with Modifiers:
Modifier | Class | Subclass | Package | World |
Private | Yes |
|
|
|
Protected | Yes | Yes | Yes |
|
Public | Yes | Yes | Yes | Yes |
<Not mentioned> | Yes |
| Yes |
|
Access Modifiers in the order of most restricted to more accessible:
Private – Most Restricted
Protected – Less restricted than Private
<not mentioned>default Access Level – Less restricted than protected
Public – Most Accessible
Access Modifiers and their meaning with respect to a Top-level or Outer class:
Public: can instantiate the class outside the package too.
<default>: can instantiate the class within the package only.
The modifiers private and protected cannot be used for top-level or outer classes.
Access Modifiers and their meaning with respect to members(data/methods):
Public: can access it outside the package also with its class object.
<default>: can access it within the package only with its class object.
Private: can access it only within the class among its class members.
Protected: can be accessible to immediate sub class
Access Modifiers and their meaning with respect to a Constructor:
Since constructor is a special method of class which has the same name of its class and used to initialize its class members, Constructor cannot be directly called or inherited to subclasses. Since there is no question of inheritance, there is no question of overriding too.
We can use any one of the modifiers in the header of a constructor since it is nothing but a class member.
Public: we can access it outside the package also with its class object.
<default>: we can access it within the package only with its class object.
Private: cannot be visible to its sub class constructors.
Protected: can be visible to sub class constructors.
Constructors Inheritance
We know constructor is a special method of any class that is used to initialise the objects at the time of declaration. What about constructors when the members of parent class are available to child class through inheritance? Will constructors go to child class? The answer is, of course No.
Constructors or parent class won’t participate directly in the inheritance. But it is the responsibility of the constructor of child class to make call to its parent class constructor. The default constructor of parent class is automatically being called by child class constructor. But the parameterized constructor of parent class should be called with super() method from child class constructor.
The invocation of parent class constructor must be the first statement in the child class constructor.
//Example code showing how child constructor calls parent constructor
class parent
{
parent()
{
System.out.println(“I am constructor of Parent”);
}
}
class child extends parent
{
child()
{
System.out.println(“I am constructor of Child”);
}
}
public class ConstInherEg1 {
public static void main(String[] args) {
child obj=new child();
}
}
//Example code2 showing how child constructor calls parent constructor
class parent
{
int x;
parent()
{
System.out.println(“I am default constructor of Parent”);
}
parent(int x)
{
this.x=x;
System.out.println(“I am parameterized constructor of Parent”);
}
}
class child extends parent
{
child()
{
System.out.println(“I am constructor of Child”);
}
}
public class ConstInherEg1 {
public static void main(String[] args) {
child obj=new child();
}
}
//Example code3 showing how child constructor calls parent constructor
class parent
{
int x;
parent()
{
System.out.println(“I am default constructor of Parent”);
}
parent(int x)
{
this.x=x; //this keyword refers to the current object
System.out.println(“I am parameterized constructor of Parent”);
}
}
class child extends parent
{
child()
{
super(2);
System.out.println(“I am constructor of Child”);
}
}
public class ConstInherEg1 {
public static void main(String[] args) {
child obj=new child();
}
}
Super keyword and Super() method
Super keyword of java is used to refer the parent class objects to access members of parent class. Super() method of java is used to call parent class constructor.
//Example code showing working of super keyword
class fourWheeler
{
int NoGears=4;
void show()
{
System.out.println(“Number of Gears in parent= “+NoGears);
}
}
class Car extends fourWheeler
{
int NoGears=5;
void show()
{
super.show();
System.out.println(“Number of Gears in child = “+ NoGears);
System.out.println(“Number of Gears in child = “+ super.NoGears);
}
}
public class TestSuperKW {
public static void main(String[] args) {
Car obj=new Car();
obj.show();
}
}
Interfaces
Why java not providing Multiple Inheritance directly?
Java is not supporting multiple inheritance directly like other Object Oriented Programming Languages like C++. If there is any need of multiple inheritance, it can be achieved by using interfaces. There is an ambiguity problem with multiple inheritance where two methods with same name but different definitions exist in two parent classes. The object of child class will get confusion that which definition of its parents to be followed.
The above diagram is depicting how ambiguity can lead to ambiguity in the child class due to Multiple Inheritance in OOP Languages.
There are some other solutions for the above said ambiguity problem in C++, but java completely eliminated direct multiple inheritance to avoid the ambiguity problem. The solution of java for multiple inheritance is Interface.
What is an Interface?
An interface a special class that can only have final data members and methods without definition. All the data members of an interface are static and final and methods of interface are public and abstract implicitly. We need not to use the respective keywords before the members. A method without body or definition is known as abstract method.
The interface and implement keywords
The interface keyword is used to declare interfaces. The implements keyword to be used to derive a new class from an interface.
//testInterface.java
interface calculate
{
public double calInt();
}
class savingAc implements calculate
{
int acNo,amt,time;
double rateOfInt;
savingAc(int a,double b,int c, int d)
{
acNo=a;
rateOfInt=b;
time=c;
amt=d;
}
void displayInt()
{
System.out.println(“Interest for Account No:”+acNo+”is Rs.”+calInt());
}
public double calInt()
{
return(amt*rateOfInt*time/100);
}
}
public class testInterface
{
public static void main(String args[])
{
savingAc s=new savingAc(1010,4.5,5,5000);
s.displayInt();
}
}
A class implements an interface must define the abstract methods. Since abstract methods do not have implementation, a class can be inherited from two or more interfaces too.
interface Father
{
void doEducation();
}
interface Mother
{
void doEducation();
}
class Son implements Father,Mother
{
void doEducation()
{
System.out.println(“I will become Software Engineer”);
}
}
The class which is implementing one or more interfaces, must define all the abstract methods existing in its parent interfaces.
Two or more interfaces can be extend into another interface.
interface Guardian extends Father,Mother
{
void doTakecare();
}
classes vs interfaces:
- objects cannot be declared based on interfaces (no instantiation)
- interface doesn’t contain constructors
- all of the methods of interface are implicitly public and abstract
- Interface cannot contain instance fields. If any fields, they should be declared as static and final.
- An interface cannot be implemented to another interface but is implemented by a class
- An interface can extend multiple interfaces.
properties of an interface:
- abstract keyword is not necessary to be used since all the members of interface are by default abstract
- methods in the interface are implicitly public and abstract.
How an Interface is solving ambiguity problem of Multiple Inheritance?
//example of interface
interface animal
{
public void eat();
public void travel();
}
A class uses implement keyword to implement an interface.
/* File name : MammalInt.java */
public class MammalInt implements Animal{
public void eat(){
System.out.println(“Mammal eats”);
}
public void travel(){
System.out.println(“Mammal travels”);
}
public int noOfLegs(){
return 0;
}
public static void main(String args[]){
MammalInt m = new MammalInt();
m.eat();
m.travel();
}
}
//IntAndInh.java – program that contains inheritance of interface
interface one
{
void methodOne();
}
interface two extends one
{
public void methodTwo();
}
class interfaceInherit implements two
{
public void methodOne()
{
System.out.println(“Method of first interface is implemented”);
}
public void methodTwo()
{
System.out.println(“Method of Second interface is implemented”);
}
}
class InhOfInt
{
public static void main(String args[])
{
System.out.println(“Interface Inheritance Demonstration”);
interfaceInherit ob=new interfaceInherit();
ob.methodOne();
ob.methodTwo();
}
}
//program implements two interfaces into single class
interface First
{
void MethodOne( );
int MyValue1 = 100;
}
interface Second
{
public void MethodTwo();
int MyValue2 = 200;
}
class interfaceIn implements First,Second
{
public void MethodOne()
{
System.out.println(“Method of interface First is implemented with value:”+MyValue1);
}
public void MethodTwo()
{
System.out.println(“Method of interface Second is implemented with value:”+MyValue2);
}
}
class TwoInterfTest
{
public static void main( String args[])
{
interfaceIn object = new interfaceIn() ;
object.MethodOne();
object.MethodTwo();
}
}
Abstract Classes
A class which is declared with the abstract keyword is known as an abstract class in Java. It can have abstract and non-abstract methods (method with the body) too.
Even though a class is declared as abstract it can have all implemented methods. But if any one of the member method is declared as abstract then it is compulsory to declare that class as abstract.
Abstraction is a process of hiding the implementation details and showing only functionality to the user. Another way, it shows only essential things to the user and hides the internal details, for example, sending SMS where you type the text and send the message. You don’t know the internal processing about the message delivery. Abstraction lets you focus on what the object does instead of how it does it.
Ways to achieve Abstraction
There are two ways to achieve abstraction in java
- Abstract class (0 to 100%)
- Interface (100%)
Abstract class in Java
A class which is declared as abstract is known as an abstract class. It can have abstract and non-abstract methods. It needs to be extended and its method implemented. It cannot be instantiated.
Points to Remember
- An abstract class must be declared with an abstract keyword.
- It can have abstract and non-abstract methods.
- It cannot be instantiated.
- It can have constructors and static methods also.
- It can have final methods which will force the subclass not to change the body of the method
//Example code
abstract class Bike{
abstract void run();
}
class Honda4 extends Bike{
void run(){System.out.println(“running safely”);}
public static void main(String args[]){
Bike obj = new Honda4();
obj.run();
}
}
//Example Code – 2
abstract class Shape{
abstract void draw();
}
//In real scenario, implementation is provided by others i.e. unknown by end user
class Rectangle extends Shape{
void draw(){System.out.println(“drawing rectangle”);}
}
class Circle1 extends Shape{
void draw(){System.out.println(“drawing circle”);}
}
//In real scenario, method is called by programmer or user
class TestAbstraction1{
public static void main(String args[]){
Shape s=new Circle1();//In a real scenario, object is provided through method, e.g., getShape() method
s.draw();
}
}
//Example code – 3
abstract class Bank{
abstract int getRateOfInterest();
}
class SBI extends Bank{
int getRateOfInterest(){return 7;}
}
class PNB extends Bank{
int getRateOfInterest(){return 8;}
}
class TestBank{
public static void main(String args[]){
Bank b;
b=new SBI();
System.out.println(“Rate of Interest is: “+b.getRateOfInterest()+” %”);
b=new PNB();
System.out.println(“Rate of Interest is: “+b.getRateOfInterest()+” %”);
}}
//Example of an abstract class that has abstract and non-abstract methods
abstract class Bike{
Bike(){System.out.println(“bike is created”);}
abstract void run();
void changeGear(){System.out.println(“gear changed”);}
}
//Creating a Child class which inherits Abstract class
class Honda extends Bike{
void run(){System.out.println(“running safely..”);}
}
//Creating a Test class which calls abstract and non-abstract methods
class TestAbstraction2{
public static void main(String args[]){
Bike obj = new Honda();
obj.run();
obj.changeGear();
}
}
Multi Threading
Multi Tasking
The activity of doing more than one task at a time is known as multi-tasking. In computer science, two types of multi-tasking
- Process based (or) o/s level
- Thread based (or) program level
Multi-threading is a concept of running different parts of a program simultaneously which are independent of each other.
Multi-threading can be witnessed in our games where some characters has to move independently while we are playing one character.
Thread is basically a lightweight sub-process, a smallest unit of processing. Multiprocessing and multithreading, both are used to achieve multitasking.
Multithreading is most preferable than multiprocessing for the following advantages:
- threads share a common memory area. They don’t allocate separate memory area so saves memory.
- context-switching between the threads takes less time than process.
Advantage of Multithreading
It doesn’t block the user because threads are independent and you can perform multiple operations at same time.
You can perform many operations together so it saves time.
Improves CPU utilisation.
Threads are independent so it doesn’t affect other threads if exception occur in a single thread.
Java language is providing in-built support for multi-threading feature by providing API in the form of Thread class, Runnable interface. Every java program is internally is treated as a thread, and it should be considered that the main() method is executing by main thread of the JVM.
What is Thread in java
A thread is a lightweight sub process, a smallest unit of processing. It is a separate path of execution.
Threads are independent, if there occurs exception in one thread, it doesn’t affect other threads. It shares a common memory area.
There are two ways to create a thread:
- By extending Thread class
- By implementing Runnable interface.
Creating thread by extending Thread Class
Thread class provide constructors and methods to create and perform operations on a thread. Thread class extends Object class and implements Runnable interface.
The important methods of Thread Class:
public void run(): This method is overridden (re-define) to specify the job of the thread. The thread which is in runnable state will get a chance of executing when the Thread Scheduler allocated CPU time to it. |
start(): Thread class is used to start a newly created thread. It causes the thread state change from new/born state to runnable state. Here the thread object is handing over to the JVM by creating a flow and joining the thread object in the flow.
The steps inside the start() method are:
- Register the thread object for the thread scheduler
- Perform all other necessary activities
- Invoke run() method.
//Example code showing how to create a thread by extending Thread class
class MyThread extends Thread
{
public void run()
{
for(int i=0;i<5;i++)
System.out.println(“Child Thread”);
}
}
public class Training {
public static void main(String[] args)
{
MyThread t=new MyThread();
t.start();
for(int i=0;i<5;i++)
System.out.println(“Main Thread”);
}
}
The output of the above program varies each time you run the program because there are two threads are running and getting chance to run based on the decision of Thread Scheduler. Firstly, the main thread of the program is started executing the main() method and later with t.start() a separate flow will be created to start a child thread. After that based on the algorithm of thread scheduler main thread and child thread get the chances of running.
Try the same program by replacing t.start() with t.run() method. Then you see there is no separate flow is created but child thread runs first and main thread continues later. You will get the same output regardless how many times you run the program. The total output is produced by main thread.
Overloaded run() method
We understood that run() method of Thread class to be re-defined in our thread class to assign job for the thread. Then what happens when run() method is overloaded in our thread. In that case, the start() method can only call only non arguments run() method while remaining run methods have to called explicitly.
//Example code showing how to create a thread by extending Thread class
class MyThread extends Thread
{
public void run()
{
System.out.println(“Non-arguments run”);
}
public void run(int i)
{
System.out.println(“overloaded run”+i);
}
}
public class Training {
public static void main(String[] args)
{
MyThread t=new MyThread();
t.start();
for(int i=0;i<5;i++)
System.out.println(“Main Thread”);
}
}
Overridden run() method is recommended but overridden start() method is not.
It is highly recommended to override run() method otherwise don’t go for multi threading.
//example code to show overridden run() method
class MyThread extends Thread
{
public void run()
{
for(int i=0;i<5;i++)
System.out.println(“overridden run1”);
}
public void run(int i)
{
System.out.println(“overridden run1”);
}
}
public class Training {
public static void main(String[] args)
{
MyThread t=new MyThread();
t.start();
for(int i=0;i<5;i++)
System.out.println(“Main Thread”);
}
}
It is not recommended to override start() method since when you call start() method, the over ridden definition will be executed but not the definition exists in the Thread class. As a result no new thread flow will be created but only main thread.
//example code to show overridden start() method
class MyThread extends Thread
{
public void start()
{
//super.start(); //check the output again by uncommenting this line
System.out.println(“overridden start”);
}
public void run()
{
for(int i=0;i<5;i++)
System.out.println(“overridden run”);
}
}
public class Training {
public static void main(String[] args)
{
MyThread t=new MyThread();
t.start();
for(int i=0;i<5;i++)
System.out.println(“Main Thread”);
}
}
Creating thread by implementing Runnable interface:
Runnable interface is exists under java.lang package and have only one method named run(). As stated earlier, the runnable() is a super interface by implementing which the Thread class is created. The Runnable interface can also be implemented by any other class whose instances are intended to be executed by a thread. |
//creating thread by implementing Runnable interface
class MyRunnable implements Runnable
{
public void run()
{
for(int i=0;i<5;i++)
System.out.println(“overridden run”);
}
}
public class Training {
public static void main(String[] args)
{
MyRunnable r=new MyRunnable();
Thread t=new Thread(r);
t.start();
for(int i=0;i<5;i++)
System.out.println(“Main Thread”);
}
}
If you are not extending the Thread class, your class object would not be treated as a thread object. So you need to explicitly create Thread class object. We are passing the object of your class that implements Runnable so that your class run() method may execute.
Need of creating a thread class by implementing Runnable
When you create a thread by extending Thread class then there is no chance of further extending from any other class since multiple inheritance is not supported by java. But in the second case, we are creating our thread class by implementing Runnable interface, hence further extending from any other class is possible.
Life cycle of a Thread (Thread States)
A thread can be in one of the five states. According to Sun, there are only 4 states in thread life cycle in java new, runnable, non-runnable and terminated. There is no running state.
The life cycle of the thread in java is controlled by JVM. The java thread states are as follows:
- New
- Runnable
- Running
- Non-Runnable (Blocked)
- Terminated
1) NewThe thread is in new state if you create an instance of Thread class but before the invocation of start() method. |
2) Runnable/Ready
The thread is in runnable state after invocation of start() method, but the thread scheduler has not selected it to be the running thread.
3) Running
The thread is in running state if the thread scheduler has selected it.
4) Non-Runnable (Blocked)
This is the state when the thread is still alive, but is currently not eligible to run.
5) Terminated/Dead
A thread is in terminated or dead state when its run() method exits.
Every thread must be dead after completion of its assigned job. A thread which is already started cannot be restarted. The runtime exception called IllegalThreadStateException will be raised if you try to restart.
Thread class constructors
There are 8 definitions available for thread class constructor
Thread()
Thread(Runnable r)
Thread(String name)
Thread(Runnable r, String name)
Thread(ThreadGroup g, String name)
Thread(ThreadGroup g, Runnable r)
Thread(ThreadGroup g, Runnable r, String name)
Thread(ThreadGroup g, Runnable r, String name, long callStacklength)
Thread Name
Every thread must have a name assigned by JVM for its identification.
The currentThread() method returns a reference to the currently executing thread object. |
Syntax of currentThread() method:
public static Thread currentThread(): returns the reference of currently running thread.
class TestMultiNaming2 extends Thread{
public void run(){
System.out.println(“Name of Current Thread is :”+Thread.currentThread().getName());
}
public static void main(String args[]){
TestMultiNaming2 t1=new TestMultiNaming2();
TestMultiNaming2 t2=new TestMultiNaming2();
t1.start();
t2.start();
}
}
The Thread class provides methods to change and get the name of a thread.
- public String getName(): is used to return the name of a thread.
- public void setName(String name): is used to change the name of a thread.
//Example of naming a thread
class TestMultiNaming1 extends Thread{
public void run(){
System.out.println(“running…”);
}
public static void main(String args[]){
TestMultiNaming1 t1=new TestMultiNaming1();
TestMultiNaming1 t2=new TestMultiNaming1();
System.out.println(“Name of t1:”+t1.getName());
System.out.println(“Name of t2:”+t2.getName());
t1.start();
t2.start();
t1.setName(“Your Name”);
System.out.println(“After changing name of t1:”+t1.getName());
}
}
Thread Priorities
Thread scheduler in java is the part of the JVM that decides which thread should run. There is no guarantee that which runnable thread will be chosen to run by the thread scheduler. Only one thread at a time can run in a single process.
Each thread has a priority. Priorities are represented by a number between 1 and 10. In most cases, thread schedular schedules the threads according to their priority (known as preemptive scheduling). But it is not guaranteed because it depends on JVM specification that which scheduling it chooses. |
3 constants defined in Thread class:
|
Default priority of a thread is 5 (NORM_PRIORITY). The value of MIN_PRIORITY is 1 and the value of MAX_PRIORITY is 10. Except main thread, the priority will be inherited from its parent. |
class TestMultiPriority1 extends Thread{
public void run(){
System.out.println(“running thread name is:”+Thread.currentThread().getName());
System.out.println(“running thread priority is:”+Thread.currentThread().getPriority());
}
public static void main(String args[]){
TestMultiPriority1 m1=new TestMultiPriority1();
TestMultiPriority1 m2=new TestMultiPriority1();
m1.setPriority(Thread.MIN_PRIORITY);
m2.setPriority(Thread.MAX_PRIORITY);
m1.start();
m2.start();
}
}
Prevent thread from execution
We can prevent a thread from execution by using the following methods:
yield(), sleep() and join()
By using yield() method your current thread can give a chance of execution for other threads having same or high priority by pausing execution of current thread. The current thread goes back to Ready/Runnable state when yield() method is executed. Even the current thread executed yield() method, JVM can continue the same thread if there are no threads or only low priority threads. Also, if a thread that is paused using yield() method, there is no guarantee of continuing same thread after execution of other thread. Since yield() method working on pre-emptive mechanism, it may not work properly on some systems due to lack of hardware support.
Prototype of yield() method
public static native void yield();
native method means the method which is not implemented java.
//example code showing how yield() method works
class MyThread extends Thread
{
public void run()
{
for(int i=0;i<5;i++)
{
System.out.println(“Child Thread”);
Thread.yield();
}
}
}
public class Training {
public static void main(String[] args)
{
MyThread t=new MyThread();
t.start();
for(int i=0;i<5;i++)
System.out.println(“Main Thread”);
}
}
The sleep() method of Thread class is used to sleep a thread for the specified amount of time.
The Thread class provides two methods for sleeping a thread:
- public static void sleep(long miliseconds)throws InterruptedException
- public static void sleep(long miliseconds, int nanos)throws InterruptedException
//example for sleep method
class TestSleepMethod1 extends Thread{
public void run(){
for(int i=1;i<5;i++){
try{Thread.sleep(500);}
catch(InterruptedException e)
{
System.out.println(e);
}
System.out.println(i);
}
}
public static void main(String args[]){
TestSleepMethod1 t1=new TestSleepMethod1();
TestSleepMethod1 t2=new TestSleepMethod1();
t1.start();
t2.start();
System.out.println(“Code in the main thread”);
}
}
As you know well that at a time only one thread is executed. If you sleep a thread for the specified time, the thread schedular picks up another thread and so on.
//program describing sleepmethod
class sleepDemo
{
public static void main(String args[])
{
Thread t=Thread.currentThread();
try
{
for(int i=1;i<=10;i++)
{
System.out.println(i);
t.sleep(1000);
}
}
catch(InterruptedException e)
{
System.out.println(“Thread interrupted”);
}
}
}
The join() method
This method is used to send wish of wait of a thread to another thread to continue after completion of execution of that thread. The thread which wants to join must execute join method and after execution of join method the thread goes into wait state.
Prototype of join() method
public final void join() throws InterruptedException
public final void join(long ms) throws InterruptedException
public final void join(long milliseconds, int nanoseconds) throws InterruptedException
//example code
class MyThread extends Thread
{
public void run()
{
for(int i=0;i<5;i++)
{
System.out.println(“Child Thread”);
try
{
Thread.sleep(2000);
}
catch(InterruptedException e)
{
}
}
}
}
public class Training {
public static void main(String[] args) throws InterruptedException
{
MyThread t=new MyThread();
t.start();
t.join();
for(int i=0;i<5;i++)
System.out.println(“Main Thread”);
}
}
Synchronization
Synchronization is the concept of avoidance of data inconsistency problem due to multiple threads trying to access a common resource. But synchronization causes performance degradation hence it should be only used when there is a need.
The threads of a program may want to access a system resource at a time. In this case, data inconsistency problem may arise. To avoid this problem, we have to provide exclusive access (Lock) to any one of the thread interested in the system resource.
Read operation need not synchronization but update, delete operations need synchronization.
For example, x is an object
t1,t2 and t3 are the three threads want to access the object.
can these three read data at a time from x? yes
but t1 wants to update(add, modify) the data in x
while t2 wants to read the data in x
The synchronization can provide exclusive lock at object level. synchronization can be achieved by using ‘synchronized’ keyword. This ‘synchronized’ modifier is applicable only for methods and blocks but not for classes and variables.
class x extends Thread
{
synchronized m1()
{
}
synchronized m2()
{
}
m3()
{
}
}
//example code where there is no synchronization is required
class Table1
{
void printTable(int n)
{
for(int i=1;i<=10;i++)
{
System.out.print(i+”x”+n+”=”);
try
{
Thread.sleep(2000);
}
catch(InterruptedException e)
{
}
System.out.println(i*n);
}
}
}
class TableThread extends Thread
{
Table1 tobj=new Table1();
TableThread(Table1 tobj)
{
this.tobj=tobj;
}
public void run()
{
tobj.printTable(5);
}
}
public class Synchronization {
public static void main(String[] args) {
Table1 tobj=new Table1();
TableThread t=new TableThread(tobj);
t.start();
}
}
Output of the above program:
1×5=5
2×5=10
……
10×5=50
Now, try the same program by creating more one thread for accessing the same object of class Table1 and check the output. You will get irregular output. The solution for this problem is making the printTable() method as synchronized.
The above example is demonstrating, if multiple threads are accessing same object then only synchronization is required. But there will be no use of synchronized keyword when the threads are accessing different independent objects that is again we will get irregular output. The solution for this is static synchronized.
static synchronized is used to obtain class level lock.
Only synchronized enables to obtain object level lock.
If a thread wants to execute any static synchronized method, then that thread requires class level lock to access the method.
Once thread got class level lock, then it is allowed execute any static synchronized method of that class.
Once method execution completes, automatically thread releases lock.
Synchronized keyword will be used for enclosing critical section of the program.
Two levels of locks:
- class level
- object level
while a thread executing static synchronized method, remaining threads are not allowed to execute any static synchronized methods of that class. But remaining threads are allowed execute, normal static method, synchronized instant method, normal instant method.
Class X
{
Static sync m1();
Static sync m2();
Sync m3();
Static m4();
M5();
}
//Example code where two threads are executing two different methods of same object
class Display
{
public void showN()
{
for(int i=1;i<=10;i++)
{
System.out.print(i);
try
{
Thread.sleep(2000);
}
catch(InterruptedException e)
{
}
}
}
public void showC()
{
for(int i=65;i<=75;i++)
{
System.out.print((char)i);
try
{
Thread.sleep(2000);
}
catch(InterruptedException e)
{
}
}
}
}
class ThreadN extends Thread
{
Display d;
ThreadN(Display d)
{
this.d=d;
}
public void run()
{
d.showN();
}
}
class ThreadC extends Thread
{
Display d;
ThreadC(Display d)
{
this.d=d;
}
public void run()
{
d.showC();
}
}
public class Synchornization {
public static void main(String[] args) {
Display d=new Display();
ThreadN t1=new ThreadN(d);
ThreadC t2=new ThreadC(d);
t1.start();
t2.start();
}
}
Output: A1B2C3D4E5F67G8H9I10JK
By making both showN() and showC() methods as synchronized we can get the output as:
12345678910ABCDEFGHIJK
//another example code showing how threads compete for one object without synchronization
class PrintDemo {
public void printCount() {
try {
for(int i = 5; i > 0; i–) {
System.out.println(“Counter — ” + i );
}
} catch (Exception e) {
System.out.println(“Thread interrupted.”);
}
}
}
class ThreadDemo2 extends Thread {
private Thread t;
private String threadName;
PrintDemo PD;
ThreadDemo2( String name, PrintDemo pd) {
threadName = name;
PD = pd;
}
public void run() {
PD.printCount();
System.out.println(“Thread ” + threadName + ” exiting.”);
}
public void start () {
System.out.println(“Starting ” + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}
public class SyncTest2 {
public static void main(String[] args) {
PrintDemo PD = new PrintDemo();
ThreadDemo2 T1 = new ThreadDemo2( “Thread – 1 “, PD );
ThreadDemo2 T2 = new ThreadDemo2( “Thread – 2 “, PD );
T1.start();
T2.start();
// wait for threads to end
try {
T1.join();
T2.join();
} catch ( Exception e) {
System.out.println(“Interrupted”);
}
}
}
The above code will give irregular output which can be solved by using synchronized keyword.
DeadLock
Deadlock in java is a part of multithreading. Deadlock can occur in a situation when a thread is waiting for an object lock, that is acquired by another thread and second thread is waiting for an object lock that is acquired by first thread. Since, both threads are waiting for each other to release the lock, the condition is called deadlock.
//example code showing the problem of DeadLock
public class DeadLockEg {
public static void main(String[] args) {
final String resource1 = “Best Computer”;
final String resource2 = “Institute”;
// t1 tries to lock resource1 then resource2
Thread t1 = new Thread() {
public void run() {
synchronized (resource1) {
System.out.println(“Thread 1: locked resource 1”);
try { Thread.sleep(100);} catch (Exception e) {}
synchronized (resource2) {
System.out.println(“Thread 1: locked resource 2”);
}
}
}
};
// t2 tries to lock resource2 then resource1
Thread t2 = new Thread() {
public void run() {
synchronized (resource2) {
System.out.println(“Thread 2: locked resource 2”);
try { Thread.sleep(100);} catch (Exception e) {}
synchronized (resource1) {
System.out.println(“Thread 2: locked resource 1”);
}
}
}
};
t1.start();
t2.start();
}
}
//Java program to illustrate Deadlock in multithreading.
class Util
{
// Util class to sleep a thread
static void sleep(long millis)
{
try
{
Thread.sleep(millis);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
//This class is shared by both threads
class Shared
{
// first synchronized method
synchronized void test1(Shared s2)
{
System.out.println(“test1-begin”);
Util.sleep(1000);
// taking object lock of s2 enters
// into test2 method
s2.test2(this);
System.out.println(“test1-end”);
}
// second synchronized method
synchronized void test2(Shared s1)
{
System.out.println(“test2-begin”);
Util.sleep(1000);
// taking object lock of s1 enters
// into test1 method
s1.test1(this);
System.out.println(“test2-end”);
}
}
class Sh1Thread extends Thread
{
private Shared s1;
private Shared s2;
// constructor to initialize fields
public Sh1Thread(Shared s1, Shared s2)
{
this.s1 = s1;
this.s2 = s2;
}
// run method to start a thread
@Override
public void run()
{
// taking object lock of s1 enters
// into test1 method
s1.test1(s2);
}
}
class Sh2Thread extends Thread
{
private Shared s1;
private Shared s2;
// constructor to initialize fields
public Sh2Thread(Shared s1, Shared s2)
{
this.s1 = s1;
this.s2 = s2;
}
// run method to start a thread
@Override
public void run()
{
// taking object lock of s2
// enters into test2 method
s2.test2(s1);
}
}
public class DeadLockEg2 {
public static void main(String[] args) {
// creating one object
Shared s1 = new Shared();
// creating second object
Shared s2 = new Shared();
// creating first thread and starting it
Sh1Thread t1 = new Sh1Thread(s1, s2);
t1.start();
// creating second thread and starting it
Sh2Thread t2 = new Sh2Thread(s1, s2);
t2.start();
// sleeping main thread
Util.sleep(2000);
}
}
The above program would run indefinite time since dealock occurance. The developer has to take care to avoid DeadLock caused by usage of synchronized keyword.
InterThread Communication
Inter-thread communication or Co-operation is all about allowing synchronized threads to communicate with each other.
Cooperation (Inter-thread communication) is a mechanism in which a thread is paused running in its critical section and another thread is allowed to enter (or lock) in the same critical section to be executed. It is implemented by following methods of Object class:
wait()
notify()
notifyAll()
wait(), notify() and notifyall() methods
wait() method: Causes current thread to release the lock and wait until either another thread invokes the notify() method or the notifyAll() method for this object, or a specified amount of time has elapsed.
The current thread must own this object’s monitor, so it must be called from the synchronized method only otherwise it will throw exception.
Method | Description |
public final void wait()throws InterruptedException | waits until object is notified. |
public final void wait(long timeout)throws InterruptedException | waits for the specified amount of time. |
notify() method: Wakes up a single thread that is waiting on this object’s monitor. If any threads are waiting on this object, one of them is chosen to be awakened. The choice is arbitrary and occurs at the discretion of the implementation. Syntax:
prototype: public final void notify()
notifyAll() method: Wakes up all threads that are waiting on this object’s monitor. Syntax:
Prototype: public final void notifyAll()
the thread which is expecting updating is responsible to invoke wait() method.
The thread which is responsible to perform updation, after performing updation it is responsible to invoke notify() method. Then waiting method get notification.
These three methods are defined in Object class of java.lang package. Do you know why these three methods are defined in Object class instead of Thread class since these methods are only used with multithreading concept? A thread can call wait() method on any object belongs to a particular class but not like start() and run() methods where these two methods are called on a thread only.
If a thread wants to call these methods then it must be the owner of the object. The thread is said to be the owner of the object when it has the lock of the object. And the thread would get the lock of the object when it is entered into the synchronized area of the object. That means, these three methods should be used inside synchronized area of an object only. If you use these methods outside synchronized area then IllegalMonitorStateException will be raised.
A thread can have many locks in hand at a time. If a thread calls wait() method on any object then it releases the lock of the object immediately and enters into waiting state.
But when a thread calls notify() method on any object, it may not release the lock immediately.
//example coding showing how inter thread communication happens with wait() notify() methods
class Customer{
int amount=10000;
synchronized void withdraw(int amount){
System.out.println(“going to withdraw…”);
if(this.amount<amount){
System.out.println(“Less balance; waiting for deposit…”);
try{wait();}catch(Exception e){}
}
this.amount-=amount;
System.out.println(“withdraw completed…”);
}
synchronized void deposit(int amount){
System.out.println(“going to deposit…”);
this.amount+=amount;
System.out.println(“deposit completed… “);
notify();
}
}
public class WaitNotifyExample {
public static void main(String[] args) {
final Customer c=new Customer();
new Thread(){
public void run(){
c.withdraw(15000);}
}.start();
new Thread(){
public void run(){
c.deposit(10000);
}
}.start();
}
}
Exceptions Handling
Types of Errors occur during program development
It is common to occur any error during program development due to the ignorance of developer, program or some external resource. Basically, there are two types of errors occur during any program development. They are Compile time errors and Run-time errors. As their name saying, compile time errors occur at the time of compiling the source code while run-time errors occur at the time of executing the program.
Compile-time errors are two types, they are
Syntax Errors: occur when sentence construction rules are avoided.
Semantic Errors: occur when some useless code is founded.
Run-time Errors are also two types, they are
Logical Errors: occur due to ignorance or negligence of developer.
unExpected Errors: occur due to lack of or failure of some external resource.
Exception Handling of java is a mechanism to handle unexpected runtime errors only (the last one), but not any other types of errors discussed above. Exception can be defined as an unwanted situation during the execution of the program. Exception causes the abnormal termination of the program. This situation is not suitable for the following examples real-time scenarios
- ATM program is closed due to wrong password entry by a user.
- A network application is closed due to some mistake done by an user on a particular node.
Handling of exception is the concept of avoiding abnormal termination of the program due to exception so that the program would continue its execution by taking necessary steps regarding exception. The handling of exception is not providing solution for the exception but it is providing an alternative way to run the rest of the program which is not dependent on the code in which exception occurred.
//example code with run-time error
public class NoHandling{
public static void main(String args[]){
int data=50/0;
System.out.println(“rest of the code…”);
}
The output of the above code would be like below:
Exception in thread “main” java.lang.ArithmeticException: / by zero
at packageName. main(ClassName.java:LineNumber)
The exception raised in the above code is divisible by zero in the line “int data=50/0”. You can observe there is an output statement that is displaying a string “rest of the code…” is not executing even though it is not at all dependent on the code line in which exception occurred.
This is also known as abnormal termination or automatic exception handling handed over to JVM.
//same program with exception handling
public class WithHandling{
public static void main(String args[]){
try{
int data=50/0;
}
catch(ArithmeticException e){
System.out.println(e);
}
System.out.println(“rest of the code…”);
}
}
The output of the above program is :
java.lang.ArithmeticException: / by zero
rest of the code…
The difference you can get from the second example is, it continues with the printing of the string “rest of the code…” by showing respecting exception message. This is known as manual exception handling due to which the program would be terminated normally.
Java providing pre-defined classes to handle the exceptions. These classes provide various methods to handle exceptions by creating their respective objects. All the exception classes are the child classes are Throwable class. The Throwable class has two direct child classes known as Exception and Error.
The following diagram shows the hierarchy of exception classes of java language:
Exception and Error classes and their sub classes provide various pre-defined methods and properties to handle the exceptions by creating their respective objects.
Let us look at the scenarios when some exceptions may occur:
1) Scenario where ArithmeticException occurs
If we divide any number by zero, there occurs an ArithmeticException.
Eg: int a=50/0;//ArithmeticException
2) Scenario where NullPointerException occurs
If we have null value in any variable, performing any operation by the variable occurs a NullPointerException.
String s=null;
System.out.println(s.length());//NullPointerException
3) Scenario where NumberFormatException occurs
The wrong formatting of any value, may occur NumberFormatException. Suppose I have a string variable that have characters, converting this variable into digit will occur NumberFormatException.
String s=”abc”;
int i=Integer.parseInt(s);//NumberFormatException
4) Scenario where ArrayIndexOutOfBoundsException occurs
If you are inserting any value in the wrong index, it would result ArrayIndexOutOfBoundsException as shown below:
int a[]=new int[5];
a[10]=50; //ArrayIndexOutOfBoundsException
Exception | Meaning |
Arithmetic Exception | Occurred when Division by zero |
ArrayOutOfBoundsException | Array is used with invalid index |
ArrayStoreException | Array is assigned with different data type value rather than its own data type. |
IllegalArgumentException | When arguments for a method are given wrong |
NegativeArraySizeException | When array is declared with negative index value |
SecurityException | When there is a breach to the security |
ClassNotFoundException | When the specified class is not found |
Interrupted Exception | When a thread has been stopped forcefully |
Some useful methods defined under Throwable class, to print exception information on the console:
printStackTrace(): This method prints name of the exception, description along with complete stack trace information
//Example code using printStackTrace() method
public static void main(String[] args) {
try{
System.out.println(50/0);
}
catch(ArithmeticException e){
e.printStackTrace();
}
}
Output:
java.lang.ArithmeticException: / by zero
at PkgName.ClassName.main(ClassName.java:7)
In the above output
Name of the exception: java.lang.ArithmeticException
Description: / by zero
Stack trace: PkgName.ClassName.main(ClassName.java:7)
toString(): This method prints name of the exception with description only without any stack information. Whenever you are trying to print the reference of any object using println method toString() method will be called automatically. Hence, using toString() method is optional.
//Example code using printStackTrace() method
public static void main(String[] args) {
try{
System.out.println(50/0);
}
catch(ArithmeticException e){
System.out.println(e.toString()); //System.out.println(e);
}
}
Output:
java.lang.ArithmeticException: / by zero
getMessage(): this method is used to print description of exception only without any additional information.
//Example code using printStackTrace() method
public static void main(String[] args) {
try{
System.out.println(50/0);
}
catch(ArithmeticException e){
System.out.println(e.getMessage());
}
}
Output:
/ by zero
Exception Vs Error
The main difference between Exception and Error is, the Exception can be handled and recovered but the Error cannot be handled and even you try to handle, it cannot be recovered.
Types of Exceptions
There are two types of Exceptions, they are
- Checked exceptions: All sub classes of Exception class except RunTimeException and Error class of Throwable class are Checked Exceptions
- Unchecked exceptions: Runtime exceptions under Exception class and Error class of Throwable class are Unchecked Exceptions.
Difference between Checked and Unchecked Exceptions
Checked exception will be taken care by the compiler by warning or suggesting you to handle it while unchecked exceptions are ignored by the compiler.
In the case of Checked exceptions your program is connected to external resource while in the case of Unchecked exceptions your program is not connected to any external resource.
Examples of Checked Exceptions: SQLException, IOException, FileNotFoundException, InterruptedException
Examples of Unchecked Exceptions: ArithmeticException, ArrayOutofBoundException
//Example code for Checked Exception
public static void main(String[] args) {
PrintWriter x=new PrintWriter(“best.txt”);
x.println(“Hello”);
}
Above code gives a compile time error as Unhandled FileNotFoundException
The checked Exceptions are two types:
- Partially checked
- Fully Checked
Difference between partially vs fully checked exceptions:
Partially checked exceptions are the Checked exceptions where parent level exceptions are checked while child level classes are unchecked. The only two partially checked exceptions are Throwable and Exception
Fully checked exceptions are checked exceptions at both parent as well as child level. Except above mentioned two partially checked exceptions, all the remaining checked exceptions are fully checked.
There is no further category for unchecked exceptions like partial or full.
Manual Exception handling
It is not recommended to delegate the job of handling exceptions to the JVM since it causes abnormal termination of the program. Abnormal termination may result data loss or blockage of resources. Hence, java provides try…catch mechanism to handle exceptions manually by the developer.
Working mechanism of try…catch…
The risky code (the code which is prone to exception) would be kept inside try block. The catch block follows the try block. If any exception raised inside the try block then it will be thrown outside of try block by creating an object of exception to the matching catch block. The corresponding catch block will handle the exception with the information got from try block.
It is not possible to have a try block without catch or finally block anyone atleast. But finally block is optional. Each try block can have ‘0’ to multiple catch blocks but can have ‘0’ to ‘1’ finally block.
Multiple catch blocks
Multiple catch blocks can follow a single try block but only one catch block would be executed to handle the exception raised inside the try block. Hence the catch blocks must be in the order of most specific (Child) to most general (Parent).
//Example code to show multiple catch blocks to be ordered
public static void main(String[] args) {
try
{
System.out.println(10/0);
}
catch(Exception e)
{
System.out.println(“Handling Outer try”);
}
catch(ArithmeticException e)
{
System.out.println(“Handling Outer try”);
}
}
The above code would result a compile time error as “Unreachable code” since the parent Exception class is handling the exception of try block, there is no use of providing another catch block. The error can be corrected by changing the order of catch blocks as child class before and parent class after.
//another example of multiple catch blocks
public class TestMultipleCatchBlock{
public static void main(String args[]){
try{
int a[]=new int[3];
a[5]=30/0;
}
catch(ArrayIndexOutOfBoundsException e){
System.out.println(“task 2 completed”);
}
catch(ArithmeticException e){
System.out.println(“task1 is completed”);
}
catch(Exception e){
System.out.println(“common task completed”);
}
System.out.println(“rest of the code…”);
}
}
Output:
task1 is completed
rest of the code…
Propagation of Exception Handling
The exception raised inside the try block must be handled by a corresponding catch block. In case there is no catch block exists to handle the type of exception raised inside the try block, then the responsibility of handling of exception will be handed over to the caller of the method. In this manner, the handling of exception is propagated towards upper level.
//example code showing how exception handling is propagated towards upper level.
public static void main(String[] args) {
int a = 1;
int b = 0;
try
{
System.out.println(computeDivision(a,b));
}
catch(ArithmeticException ex)
{
System.out.println(ex.getMessage());
}
}
static int divideByZero(int a, int b){
int i = a/b;
return i;
}
static int computeDivision(int a, int b) {
int res =0;
try
{
res = divideByZero(a,b);
}
catch(NumberFormatException ex)
{
System.out.println(“NumberFormatException is occured”);
}
return res;
}
The finally block
The finally block is a special block that must be the last block after all catch blocks for a try block. The finally block will always be executed irrespective of the exception raising. Hence, usually clean up code would be placed inside finally block.
Try block without catch but with finally: If you use finally directly after try block, even though the program is terminated abnormally the cleanup code inside finally block will be executed.
//Example code showing how finally is executed always
public static void main(String[] args) {
try{
System.out.println(“code inside try block”);
}
catch(Exception e)
{
System.out.println(“code inside catch block”);
}
finally
{
System.out.println(“code inside finally block”);
}
System.out.println(“rest of the code in main…”);
}
//program describing that finally block is always executed if there is no exception also
class TestFinallyBlock{
public static void main(String args[]){
try{
int data=25/5;
System.out.println(data);
}
catch(NullPointerException e){System.out.println(e);}
finally{System.out.println(“finally block is always executed”);}
System.out.println(“rest of the code…”);
}
}
//Another program describing finally block when exception occurred but not handled
class TestFinallyBlock1{
public static void main(String args[]){
try{
int data=25/0;
System.out.println(data);
}
catch(NullPointerException e){System.out.println(e);}
finally{System.out.println(“finally block is always executed”);}
System.out.println(“rest of the code…”);
}
}
//finally block when exception occurred and handled
public class TestFinallyBlock2{
public static void main(String args[]){
try{
int data=25/0;
System.out.println(data);
}
catch(ArithmeticException e){System.out.println(e);}
finally{System.out.println(“finally block is always executed”);}
System.out.println(“rest of the code…”);
}
}
After checking all the above code segments, we can conclude that the finally block will be executed always in all the below situations:
- When no exception raised inside try or catch
- when exception raised inside try or catch, but not handled
- when exception raised inside try or catch, and handled
But there are some situations where finally block won’t be executed they are System.exit(0) command. The System.exit(0) method will cause shutdown JVM. The ‘0’ inside exit() method is the status code used by JVM to communicate with O/s. Here ‘0’ indicates normal termination while any non-zero value is treated as abnormal termination.
//Example code showing how finally block is skipped
public static void main(String[] args) {
try{
System.out.println(“code inside try block”);
System.exit(0);
}
catch(Exception e)
{
System.out.println(“code inside catch block”);
}
finally
{
System.out.println(“code inside finally block”);
}
System.out.println(“rest of the code in main…”);
}
The code inside finally block won’t be executed even the exception raised inside finally block.
//Example code
public static void main(String[] args) {
try{
System.out.println(“code inside try block”);
}
catch(Exception e)
{
System.out.println(“code inside catch block”);
}
finally
{
System.out.println(10/0);
System.out.println(“Other code in finally block”);
}
System.out.println(“rest of the code in main…”);
}
Difference between final, finalise and finally
You may have come to know final, finalise keyword before in this course. Now finally keyword is introduced to you. Let us look the difference between them. The final is keyword as well as non-access specifier of java that can be used with class, method and a variable. A final class cannot be inherited, a final method cannot be over ridden and a final variable cannot change its value. The finalise() method is used to explicitly call the garbage collector by the developer. And we have just understood that finally is a block related to manual exception handling with try…catch.
Nested try…catch
Nesting try…catch…finally can be done anywhere that is inside try, inside catch or even inside finally. If the inner catch block cannot handle the exception raised inside a inner try block then it will hand over the responsibility of handling to the outer catch block.
//example code for nested try…catch
public static void main(String[] args) {
try
{
System.out.println(“Outer Try”);
try
{
System.out.println(“Inner Try”);
System.out.println(10/0);
}
catch(ArithmeticException e)
{
System.out.println(“Handling Inner Try block”);
}
System.out.println(“Code after Inner try”);
}
catch(Exception e)
{
System.out.println(“Handling Outer try”);
}
finally
{
System.out.println(“outer finally”);
}
}
It is not possible to have two catch blocks to handle same type of exception but it is possible to have one outer catch block and one inner catch block to handle same type of exception.
//Example code
try
{
try
{
}
catch(X e)
{
}
}
catch(X e)
{
}
Even though the outer catch block can handle the exception raised inside inner try, it is not possible to have an inner try block without catch block. The outer catch takes the responsibility only when the inner catch block failed to handle the exception of inner try.
//example
try
{
try
{
}
}
catch(X e)
{
}
The above code would result in a compile time error.
The curly braces are mandatory for try…catch…finally structure even though they are controlling a zero or single statement. Compiler don’t care whether you have handled code inside catch block but checked whether you inserted catch block after try only.
//example
try
…..
catch(X e)
{
…..
}
finally
{
….
}
User Defined or Custom Exceptions
Java is also allowing to create your own exceptions in addition to the pre-defined exception classes. But any user-defined exception also must be under Throwable Class hierarchy only.
The ‘throw’ keyword is used to explicitly throw a user defined exception raised inside try block. The throw keyword can also be used for pre-defined exceptions but it is not necessary.
//program showing how throw keyword works
class AgeException extends RuntimeException
{
AgeException(String msg)
{
super(msg);
}
}
public class Training {
public static void main(String[] args) {
validate(23);
System.out.println(“rest of the code…”);
}
static void validate(int age)
{
if(age<18)
{
try
{
throw new AgeException(“not eligible to vote”);
}
catch(AgeException e)
{
System.out.println(e);
}
}
else
System.out.println(“welcome to vote”);
}
}
}
The throws keyword
The Java throws keyword is used to declare an exception. The throws keyword is used to hand over the responsibility of exception to the caller of a method. The throws keyword will be found in the header of the method to inform the caller of the method in advance, to provide the handling code for the exception that would be raised.
//Example code showing working of throws keyword
class Testthrows1{
void m()throws ArithmeticException{
throw new ArithmeticException(“device error”);//checked exception
}
void n()throws ArithmeticException{
m();
}
void p(){
try{
n();
}catch(Exception e){System.out.println(“exception handled”);}
}
}
public class Training {
public static void main(String[] args)
{
try
{
System.out.println(10/0);
}
catch(ArithmeticException e)
{
System.out.println(“/ by zero”);
}
}
}
Difference between throw and throws
The throw keyword is used to create and throw an Exception. It must be used only with Throwable classes. It can be used with pre-defined or user-defined exceptions but preferably used with user-defined exceptions.
The throws keyword is delegating the responsibility of handling the exception to the caller of the method.
The following are the differences between throw and throws
- The throw is used to explicitly throw an exception. The throws is used to declare an exception
- The throw can be seen inside a method definition while throws appear at method signature
- The throw cannot throw multiple exceptions at a time while the throws can declare multiple exceptions.
Manual Exception handling with throws Vs try…catch
It is best way to handle the try…catch but it is not recommended to use throws. The throws is only used to compromise the compiler from handling the exception.