Multithreading in Java | Part-2

In this tutorial series, we are learning multithreading in Java. This is the second article in the series.
In the first article, we learned about the basics of multithreading. 

Java_MultiThreading

Prevent Thread Execution

We can prevent the thread execution by using the following methods:

  1. yield()

  2. join()

  3. sleep()

yield()

yield() method pause the current execution of the thread and give the chance for waiting thread of the same priority. If there are no waiting thread having the same priority or all other waiting thread having low priority then the same thread continues its execution. If multiple threads are waiting with the same priority then which waiting thread will get the chance we cant to expect, it depends on the thread schedular. A thread which yield, when it will get a chance once again it depends on thread schedular and we cant expect exactly.

package mt;

class Mythread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            System.out.println("child thread!!!");
            Thread.yield();
        }
    }
}

public class ThreadYieldDemo {
    public static void main(String[] args) {
        Mythread mythread = new Mythread();
        mythread.start();
        mythread.setPriority(5);
        for (int i = 0; i < 3; i++) {
            System.out.println("main thread!!!");
        }
    }
}

/*
output - 

main thread!!!
main thread!!!
main thread!!!
child thread!!!
child thread!!!
child thread!!!
 */

In the above program, the main thread will complete execution before the child thread. If we commenting Thread.yield() line, then both thread run simultaneously and we cant except which thread will complete first.

join()

If a thread wants to wait until completing some other thread then we should go for the join() method. For example thread t1 wants to wait until completing t2, then t1 has to call t2.join(). If t1 executes t2.join(), then immediately t1 will be entered into the waiting state until t2 completes. Once t2 terminate then t1 can continue its execution.
Methods: -

  1. public final void join() throws InterruptedException //default milliseconds = 0

  2. public final synchronized void join(long millis) throws InterruptedException

  3. public final synchronized void join(long millis, int nanos) throws InterruptedException

join() throws InterruptedException which is checked exception, hence we should compulsorily handle this exception either by using a try-catch block or throws, otherwise we will get a compile-time error.

Case 1: main thread waits for completion of the child thread:

package mt;

class MyThread extends Thread {
    public void run() {
        for (int i = 0; i < 3; i++) {
            System.out.println("Child method.");
        }
    }
}

public class ThreadJoinDemo {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("Main thread will wait until child completes...");
        MyThread mt = new MyThread();
        mt.start();
        mt.join(); // Main thread for completion of child thread
        for (int i = 0; i < 3; i++) {
            System.out.println("Main method");
        }
    }
}

/*
output - 
Main thread will wait until child completes...
Child method.
Child method.
Child method.
Main method
Main method
Main method
 */

Case 2: child thread waits for completion of the main thread :

package mt;

class MyTh extends Thread {
    static Thread mainThread;

    @Override
    public void run() {
        try {
            mainThread.join(); // child thread waits for completion of main thread
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < 3; i++) {
            System.out.println("Child Thread");
        }
    }
}

public class ThreadJoinDemo_ChildWaitForMain {
    public static void main(String[] args) {
        MyTh.mainThread = Thread.currentThread();
        MyTh myTh = new MyTh();
        myTh.start();
        for (int i = 0; i < 3; i++) {
            System.out.println("Main Thread");
        }
    }
}

/*
Output - 

Main Thread
Main Thread
Main Thread
Child Thread
Child Thread
Child Thread
 */

Case 3: child thread waits for the main thread and the main thread waits for the child thread (deadlock):
package mt;

class JoinChildThread extends Thread {
    static Thread mainThread;

    @Override
    public void run() {
        try {
            mainThread.join();  // Child thread waiting for main thread completion
        } catch (InterruptedException e) {
            System.out.println(e);
        }
        for (int i = 0; i < 3; i++) {
            System.out.println("Child thread : " + i);
        }

    }
}

public class ThreadJoinDemo_DeadLock {
    public static void main(String[] args) throws InterruptedException {
        JoinChildThread thread = new JoinChildThread();
        JoinChildThread.mainThread = Thread.currentThread();
        thread.start();
        thread.join(); // Main thread waiting for child thread completion 
        for (int i = 0; i < 3; i++) {
            System.out.println("Main thread : " + i);
        }
    }
}

/*

Because of deadLock no output 
Both thread waiting for each other

 */

Case 4: main thread waits for completion of itself and leading deadlock :
package mt;

public class ThreadJoinDemo_SelfWaiting_Dedlock {
    public static void main(String[] args) throws InterruptedException {
        Thread.currentThread().join(); // Main thread waiting for completion of main thread - Deadlock
        for (int i = 0; i < 3; i++) {
            System.out.println("Main "+i);
        }
    }
}

sleep()

Thread.sleep causes the current thread to suspend execution for a specified period. Using Thread.sleep we can make processor time available to the other threads. Methods: -

  1. public static native void sleep(long millis) throws InterruptedException

  2. public static void sleep(long millis, int nanos) throws InterruptedException

A thread can interrupt a sleeping thread or waiting thread by using the interrupt() method of thread class.

package mt;

public class InterrutedExceptionDemo {

    public static void main(String[] args) {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("Started thread");
                    for (int i = 0; i < 10; i++) {
                        System.out.println(i);
                        Thread.sleep(5000);
                    }
                } catch (InterruptedException e) {
                    System.out.println("exiting  eblocking thread ");
                }
            }
        });
        t.start();
        t.interrupt(); // Child thread is interrupted.
    }
}

/*
Started thread
0
exiting  eblocking thread 
 */

Whenever we are calling the interrupt() method, if the target thread is not in waiting/sleeping state then there is no impact of an interrupt() call. Interrupt call waits until the target thread enters into a sleeping/waiting state. If the target thread enters into a waiting/sleeping state then immediately interrupt() call interrupt the thread.


InterThread Communication

Two threads can communicate with each other by using wait(), notify(), notifyAll() methods.

The thread which is expecting an update operation is responsible for calling the wait() method then immediately that thread enters into the waiting state. The thread which performs the update operation is responsible to call the notify() method. Then the waiting thread gets that notification and continues its execution with the updated value.

Note - wait(), notify(), notifyAll() methods present in the Object class but not in the thread class because the thread can call this method on any java object.

To call wait(), notify(), notifyAll() methods on any java object, the thread should be the owner of that object i.e. thread should have the lock of that object i.e. thread should be inside a synchronized area. Hence we can call wait(), notify(), notifyAll() methods only from synchronized area otherwise we will get RuntimeException - IllegalMonitorStateException

Methods

public final void wait() throws InterruptedException;
public final native void wait(long timeout) throws InterruptedException;
public final void wait(long timeout, int Nanos) throws InterruptedException;
public final native void notify();
public final native void notifyAll();
Every wait() method throws InterruptedException which is a checked exception. Hence whenever we are using the wait() method, compulsory we should handle this InterruptedException by using the try-catch or by throws keyword, otherwise, we will get a compile-time error.

Producer-Consumer problem

package CoreJava.MultiThreading;

import java.util.LinkedList;
import java.util.List;

class Producer implements Runnable{
private List<Integer> sharedQueue;
private int MAX_SIZE = 2;
Producer(List<Integer> sharedQueue){
this.sharedQueue = sharedQueue;
}

@Override
public void run() {
for (int i = 1; i < 10; i++) {
try {
produce(i);
}catch (InterruptedException e){}
}
}

private void produce(int i) throws InterruptedException {
synchronized (sharedQueue){
if (sharedQueue.size()==MAX_SIZE){
System.out.println("Queue is full. Producer is waiting for Consumer to consume");
sharedQueue.wait();
}else {
sharedQueue.add(i);
Thread.sleep(1000);
System.out.println("Produced : "+i);
sharedQueue.notify();
}
}
}
}

class Cosumer implements Runnable{
private List<Integer> sharedQueue;
private int MIN_SIZE = 0;
Cosumer(List<Integer> sharedQueue){
this.sharedQueue = sharedQueue;
}

@Override
public void run() {
for (int i = 1; i < 10; i++) {
try{
consume();
}catch (InterruptedException e){

}
}
}

private void consume() throws InterruptedException {
synchronized (sharedQueue){
if (sharedQueue.size()==MIN_SIZE){
System.out.println("Queue is empty. Waiting for producer to produce");
sharedQueue.wait();
}else {
int num = sharedQueue.remove(0);
System.out.println("Consumed : "+num);
sharedQueue.notify();
}
}
}
}
public class ProducerConsumerDemo {
public static void main(String[] args) {
List<Integer> sharedQueue = new LinkedList<>();
Producer p = new Producer(sharedQueue);
Cosumer c = new Cosumer(sharedQueue);
Thread t1 = new Thread(p);
Thread t2 = new Thread(c);
t1.start();
t2.start();
}
}


Output
Produced : 1
Produced : 2
Queue is full. Producer is waiting for Consumer to consume
Consumed : 1
Consumed : 2
Queue is empty. Waiting for producer to produce
Produced : 4
Produced : 5
Queue is full. Producer is waiting for Consumer to consume
Consumed : 4
Consumed : 5
Queue is empty. Waiting for producer to produce
Produced : 7
Produced : 8
Queue is full. Producer is waiting for Consumer to consume
Consumed : 7
Consumed : 8
Queue is empty. Waiting for producer to produce

Difference between notify() and notifyAll()

-notify() is used to notify waiting thread.
-notifyAll() is used to notify all waiting threads.

If multiple threads are waiting then only one thread will be notified depends on JVM and the remaining threads continue in the waiting thread.


Thread LifeCycle

The thread life cycle is controlled by JVM.
A thread lies only in one of the following states at any instant. -New
-Runnable/Ready
-Running
-Blocked
-Waiting
-Sleeping
-Terminated


In this tutorial, we learned about how to prevent thread execution using the yield(), join(), sleep() method, Interthread communication using wait(), notify(), notifyAll() methods, producer-consumer problem, and life-cycle of a thread in Java.

Apache Kafka

In this tutorial, we are understanding about Apache Kafka. Apache Kafka is a highly scalable distributed messaging system. Kafka is useful where a large amount of data transfer from one end to another end and it should be scalably, fast, and reliable. We can transfer data between different sources. LinkedIn developed Kafka, and later on, it becomes open-sourced in early 2011.



Kafka Terminologies

Producer

A producer is an application that sends messages or data. For Kafka, it is an array of bytes.

Consumer

A consumer is an application that reads data from the Kafka.

Broker

A broker is the Kafka server or we can say that it is a software service running on virtual/physical machine. Producer and Consumer can't communicate directly. They always communicate through broker service.

Topic

The topic is a logical entity or in simple words, it's a unique name for Kafka stream. The producer produces topics and consumer consumes the topic.

Partitions

Topics are divided into a number of partitions. Partitions allow you to parallelize a topic by splitting the data in a particular topic across multiple brokers — each partition can be placed on a separate machine to allow for multiple consumers to read from a topic in parallel.

Offsets

It's nothing but sequence id given to message as they arrive in a partition. These ids are immutable. Offsets are local to partition.

Zookeeper

Apache Zookeeper is a distributed, open-source configuration, synchronization service along with the naming registry for distributed applications. Basically, Kafka – ZooKeeper stores a lot of shared information about Kafka Consumers and Kafka Brokers

All Kafka messages are organized into topics. Messages are sent to a specific topic and Messages are read from a specific topic. A consumer pulls messages off of a Kafka topic while producers push messages into a Kafka topic. Kafka runs in a cluster. Each node in the cluster is called a Kafka broker.

Broker-Partition


Kafka retains all published messages regardless of consumption. The retention period is configurable. The default retention time is 168 hrs or 7 days. The retention period is defined on a per topic basis.

Let's play with Kafka

NOTE: Your local environment must have Java 8+ installed.

STEP 1: GET KAFKA

Download the latest Kafka release and extract it:
$ tar -xzf kafka_2.13-2.6.0.tgz
$ cd kafka_2.13-2.6.0

STEP 2: START THE KAFKA ENVIRONMENT

Terminal-1: Start zookeeper service
$ bin/zookeeper-server-start.sh config/zookeeper.properties
Terminal-2: Start the Kafka broker service
$ bin/kafka-server-start.sh config/server.properties

STEP 3: CREATE A TOPIC TO STORE YOUR EVENTS

Terminal-3: Use terminal 3
$ bin/kafka-topics.sh --create --topic quickstart-events --bootstrap-server localhost:9092

STEP 4: DESCRIBE TOPIC

Terminal-3: Use terminal 3
$ bin/kafka-topics.sh --describe --topic quickstart-events --bootstrap-server localhost:9092
Topic:quickstart-events  PartitionCount:1    ReplicationFactor:1 Configs:
    Topic: quickstart-events Partition: 0    Leader: 0   Replicas: 0 Isr: 0

STEP 5: WRITE SOME EVENTS INTO THE TOPIC

Terminal-3: Use terminal 3
$ bin/kafka-console-producer.sh --topic quickstart-events --bootstrap-server localhost:9092
This is test event1.
test event2.
My test event3.

STEP 6: READ THE EVENTS

Terminal-4: Use terminal 4
$ bin/kafka-console-consumer.sh --topic quickstart-events --from-beginning --bootstrap-server localhost:9092
This is test event1.
test event2.
My test event3.

TERMINATE KAFKA

$ rm -rf /tmp/kafka-logs /tmp/zookeeper

Kafka UseCases

  • Kafka Messaging

  • Website Activity Tracking

  • Kafka Log Aggregation

  • Stream Processing

  • Kafka Event Sourcing

Companies using Kafka

LinkedIn,NetFlix,Twitter,Yahoo,Uber,Coursera,Microsoft,Mozilla,Bing,Oracle,GoldmanSachs and so many...

LinkedIn - Kafka

  • High Volume

  • - 1.4 trillion msg/day
    - 175 TB/day
    - 433 million users

  • Velocity

  • - peak 13 million msg/second

  • Variety

  • - Multiple RDBMS
    - Multiple NoSQL DB - Hadoop, spark, etc

Advantages of Kafka

  • High-throughput

  • Low Latency

  • Fault-Tolerant

  • Durability

  • Scalability

  • High Concurrency

  • Real-time processing

Multithreading in Java | Part-1

In this tutorial series, we are learning multithreading in Java. This is the first article in the series. Here we are going through the basic concept of multithreading.


Multitasking

Executing several tasks simultaneously is the concept of multitasking
There are two types of multitasking:

  1. Process-based Multitasking

  2. Thread based Multitasking

Process-based Multitasking

Executing several tasks simultaneously where each task is a separate independent program(process) is called process-based multitasking.
For e.g. While typing java code, you can listen to songs, at the same time you can download your favorite movie. So all these tasks are executing simultaneously and independently of each other.
It is best suitable at the Operating System level.

Thread based Multitasking

Executing several tasks simultaneously where each task is a separate path of the same program. Each independent path is nothing but the thread.
It is best suitable at the Programming level.

The objective of multithreading is to reduce the idle time of the processor and improve the performance of the system

Application of Multithreading:

  1. To develop multimedia graphics

  2. To develop Animation

  3. To develop Video games

  4. To develop Application server and Webserver

Developing multithreading application in java is very easy because Java provides inbuilt support for multithreading with rich API

The way of defining a thread


We can define a thread in the following two ways:

  1. By extending Thread class

  2. By implementing Runnable Interface

1) By extending Thread class

class MyThread extends Thread{
    public void run(){
        for (int i = 0; i < 5; i++) {
            System.out.println("Child thread : "+i);
        }

    }
}
public class Test1 {
    public static void main(String[] args) {
        MyThread mt = new MyThread();
        mt.start();
        for (int i = 0; i < 5; i++) {
            System.out.println("Parent thread : "+i);
        }
    }
}
o/p:-
Main Thread - 0
Main Thread - 1
Child Thread - 0
Main Thread - 2
Child Thread - 1
Main Thread - 3
Child Thread - 2
Main Thread - 4
Child Thread - 3
Child Thread - 4

2) By implementing Runnable Interface

Runnable Interface present in java.lang package and contains only one method i.e. public void run()

class MyRunnable implements Runnable {
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("Child thread : " + i);
        }

    }
}

public class Test1 {
    public static void main(String[] args) {
        MyRunnable mr = new MyRunnable();
        Thread mt = new Thread(mr);
        mt.start();
        for (int i = 0; i < 5; i++) {
            System.out.println("Parent thread : " + i);
        }
    }
}
Parent thread : 0
Parent thread : 1
Parent thread : 2
Child thread : 0
Child thread : 1
Child thread : 2
Child thread : 3
Parent thread : 3
Child thread : 4
Parent thread : 4

Thread Scheduler

It is part of JVM responsible to schedule threads i.e if multiple threads are waiting for execution then which thread execute next is decided by the thread scheduler. We can't expect an exact algorithm followed by thread schedular. It is varied from JVM to JVM. Hence we can't predict order and exact output.

Difference between t.start() and t.run()

  • When t.start() called new thread will be created, which is responsible for the execution of the run() method.

  • When t.run() called new thread won't be created, and run() method will be executed just like a normal method called by the main thread.
    In above program if we replace mt.start() with mt.run() then o/p will be:

    Child thread : 0
    Child thread : 1
    Child thread : 2
    Child thread : 3
    Child thread : 4
    Parent thread : 0
    Parent thread : 1
    Parent thread : 2
    Parent thread : 3
    Parent thread : 4
    

Importance of thread class start() method

The Thread class start() method is responsible for registering the thread with the thread schedular and all other registration activities. Hence without executing the start() method there is no chance of starting a new thread in java.

t.start(){
	1) Registring this thread in thread schedular.
	2) Perform all mandatory activities.
	3) Call run() method.
}

Overload run() method

We can overload run() method, but Thread classes start() method can invoke only no-args run() method. The other overloaded methods we have to call explicitly like normal methods.

class MyRunnable implements Runnable {
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("Child thread : " + i);
        }
    }
    public void run(int i){
        for (int j = 0; j < i; j++) {
            System.out.println("run method call : "+ j);
        }
    }
}

public class Test1 {
    public static void main(String[] args) {
        MyRunnable mr = new MyRunnable();
        Thread mt = new Thread(mr);
        mt.start();
        mr.run(2);
        for (int i = 0; i < 5; i++) {
            System.out.println("Parent thread : " + i);
        }
    }
}
O/P:
run method call : 0
Child thread : 0
run method call : 1
Child thread : 1
Parent thread : 0
Child thread : 2
Parent thread : 1
Child thread : 3
Child thread : 4
Parent thread : 2
Parent thread : 3
Parent thread : 4

If we are not overriding run() method the Thread class run() method will be executed which has empty implementation and we can't get any output. Hence it is highly recommended to override run() method otherwise don't go for the multithreading concept.

class MyThread extends Thread {
}

public class Test1 {
    public static void main(String[] args) {
        MyThread mt = new MyThread();
        mt.start();
    }
}

O/P - // No output

Overriding start() method

If we override the start method then our start() method will be executed just like a normal method call and a new thread won't be created.

class MyThread extends Thread {
    public void start(){
        System.out.println("Override start()");
    }
    public void run(){
        System.out.println("Child method.");
    }
}

public class Test1 {
    public static void main(String[] args) {
        MyThread mt = new MyThread();
        mt.start();
        System.out.println("Main method");
    }
}
Override start()
Main method

It is not recommended to override start() method, otherwise don't go for multithreading.

Note:- After starting a thread if we are trying to restart the same thread then we will get runtime exception Illegalthreadstateexception.

Example
class MyThread extends Thread {
    public void run(){
        System.out.println("Child method.");
    }
}

public class Test1 {
    public static void main(String[] args) {
        MyThread mt = new MyThread();
        mt.start();
        mt.start();
    }
}

Let's see what will happen in the following cases:

MyRunnable r = new MyRunnable();
Thread t1 = new Thread();
Thread t2 = new Thread(r)

t1.start()

  • A new thread will be created which is responsible for the execution of the Thread class run() method, which has an empty implementation.

t1.run()

  • No new thread will be created. Thread class run() method will be executed just like a normal method

t2.start()

  • A new thread will be created which is responsible for the execution of MyRnnable run() method will be executed just like normal method

t2.run()

  • New thread will not be created and MyRunnable run() method will be executed just like normal method

r.start()

  • Get compile-time error saying that MyRunnable class doesn't have the capability to start a thread

r.run()

  • No new thread will be created and MyRunnable run() method will be executed just like a normal method call

Which approach is best to define thread?

Among 2 ways of defining thread, implements a runnable approach is recommended to use. Because in the 1st approach our class extends thread class, there is no chance of extending any other class hence we are missing inheritance benefits here. But in the second approach while implementing the Runnable interface we can extend any other class.

Summary of thread constructors

  Thread t = new Thread()
Thread t = new Thread(Runnable r)
Thread t = new Thread(String name)
Thread t = new Thread(Runnable r, String name)
Thread t = new Thread(ThreadGroup g, String name)
Thread t = new Thread(ThreadGroup g, Runnable r)
Thread t = new Thread(ThreadGroup g, Runnable r, String name)

Getting and Setting name to the thread

Every thread in java has some name, it may be the default name generated by JVM or a customized name provided by the programmer.
Methods :

  • getName() - To get thread name

  • setName() - To set thread name

Thread Priorities

- Priorities is always in range of 1 to 10
- Min Priority = 1
- Max Priority = 10
Every thread in Java has some priority. It may be default priority generated by JVM or priority is given by the programmer.

Default Priorities by Thread class :

  • Thread.MIN_PRIORITY = 1

  • Thread.MAX_PRIORITY = 10

  • Thread.NORM_PRIORITY = 5

Thread schedular will use priorities while allocating processor. Thread having the highest priority will get the chance first. If 2 threads having the same priority then we can't expect the exact execution order. It depends on the thread schedular.
Example of getting and setting the priority of thread:

package mt;

public class ThreadPriorityExample {
    public static void main(String[] args) {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    System.out.println(Thread.currentThread().getName() + " : " + i);
                }
            }
        });
        
        System.out.println("Main class thread name : " + Thread.currentThread().getName());
        System.out.println("Newly created thread name : " + t.getName());

        t.setName("Local worker thread");
        System.out.println("Name assigned to new thread using - t.setName() : " + t.getName());

        t.setPriority(2);
        Thread.currentThread().setPriority(10);
        System.out.println("Main class thread priority : " + Thread.currentThread().getPriority());
        System.out.println("Assigned highest priority to new thread using - t.setPriority() : " + t.getPriority());
        
        t.start();

        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + " : " + i);
        }
    }
}

/*

Output -
Main class thread name : main
Newly created thread name : Thread-0
Name assigned to new thread using - t.setName() : Local worker thread
Main class thread priority : 10
Assigned highest priority to new thread using - t.setPriority() : 2
main : 0
main : 1
main : 2
main : 3
main : 4
Local worker thread : 0
Local worker thread : 1
Local worker thread : 2
Local worker thread : 3
Local worker thread : 4
 */

Note: The default priority of the main thread is 5. For all remaining thread except the main thread, the default priority is inherited from its parent thread.

Summary of this post:

What we learned?

  • What is multitasking?

  • Difference between process-based and thread-based multitasking

  • Way of defining threads

  • What is thread schedular

  • Differenc between t.start() and t.run()

  • Importance of start() method

  • Impact of overloading run() method

  • Overriding start() method

  • Overriding start() method

With this, we also came to the end of this article. Please let us know your views and opinions in the comment section below. I hope you enjoyed this post. Please stay with us for more posts.
For more details on multithreading please refer Video

Exception Handling in Java | Part-3

This is the third post on a series of Exception Handling in Java. In this article, we will revise exception handling keywords, various possible compile-time errors, in detail about customized or user-defined exceptions and enhancement. Before starting these, please go through Exception Handling in Java | Part-1 and Exception Handling in Java | Part-2so that you clear with the basics of Exception Handling.



Exception Handling keyword summary :


  1. try: To maintain risky code

  2. catch: to maintain exception handling code

  3. finally: to maintain cleanup code

  4. throw: to handover created an exception object to the JVM manually

  5. throws: to delegate the responsibility of exception handling to the caller


Various possible compile-time exceptions :


  • Unreported exception XYZ must be caught or declared to be thrown

  • Exception XYZ has already be caught

  • Exception XYZ is never thrown in body of corresponding try statement

  • Unreachable statement

  • Incompatible types - Found: XYZ required: Throwable

  • try without a catch or finally

  • catch without try

  • finally without try


Customized or User-defined exceptions :


Sometimes we need to define our own exception to meet the programming requirement, such type of exceptions are called user-defined exceptions.

Note :

  1. The throw keyword is best suitable for user-defined exceptions

  2. The custom exception should extend RuntimeException if you want to make it unchecked else extend it with Exception.

  3. Checked – Extends java.lang.Exception, need to handle it explicitly

  4. class MyException extends Exception {
        MyException(String s) {
            super(s);
        }
    }
    
    public class Test1 {
        public static void main(String[] args) {
            int demoninator = 0;
            if (demoninator == 0) {
                try {
                    throw new MyException("Denominator as 0 is not allowed");
                } catch (MyException e) {
                    System.out.println(e);
                }
            } else {
                System.out.println(25 / demoninator);
            }
        }
    }
    
    o/p:
    ExceptionHandling.MyException: Denominator as 0 is not allowed
      
  5. Unchecked – Extends java.lang.RuntimeException no need handle. Be careful while throwing RuntimeException.

  6. class MyException1 extends RuntimeException {
        MyException1(String s) {
            super(s);
        }
    }
    
    public class Test {
        public static void main(String[] args) {
            int demoninator = 0;
            if (demoninator == 0) {
                throw new MyException1("Denominator as 0 is not allowed");
            }
        }
    }
    
    o/p:
    Exception in thread "main" ExceptionHandling.MyException1: Denominator as 0 is not allowed
    	at ExceptionHandling.Test.main(Test.java:11)
      

Top 10 exceptions :


Based on the person who is raising an exception all exceptions are divided into two parts:

JVM Exceptions :

Exceptions which are raised automatically by JVM whenever a particular event occurs are called JVM exceptions
For e.g. ArithmeticException, NullPointerException

Programmatic Exceptions :

The exceptions which are raised explicitly either by the programmer or by API developer to indicate that something goes wrong are called programmatic exceptions.

    Raised by JVM:
  1. ArrayIndexOutOfBoundsException

  2. NullPointerException

  3. ClassCastException

  4. StackOverflowError

  5. ClassNotFoundException

  6. ExceptionInInitializerError

  7. Raised by programmer or API developer:
  8. IllegalArgumentException

  9. NumberFormatException

  10. IllegalThreadStateException

  11. AssertionError

Try with resources :


Until Java 1.6 it is highly recommended to write finally block to close the resources which are open as a part of the try block. In Java 1.7 introduced a new concept try with the resource.

The problem with the old approach is
- It's mandatory for a programmer to close resources used in try block using finally block.
- It increases the complexity of a program, length of code, and reduces readability.

The main advantage of try with resources is whatever resources we open as a part of the try block will be closed automatically once control reaches the end of the try block.

try with finally :

public class FNFExceptionDemo {
    public static void main(String[] args) {
        BufferedReader br = null;
        try{
            br = new BufferedReader(new FileReader("abc.txt"));
            br.read();
        }catch (FileNotFoundException f){
            System.out.println("Use local file.");
        }finally {
            if (br!=null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

output

java.io.FileNotFoundException: abc.txt (No such file or directory)
	at java.io.FileInputStream.open0(Native Method)
	at java.io.FileInputStream.open(FileInputStream.java:195)
	at java.io.FileInputStream.(FileInputStream.java:138)
	at java.io.FileInputStream.(FileInputStream.java:93)
	at java.io.FileReader.(FileReader.java:58)
	at ExceptionHandling.FNFExceptionDemo.main(FNFExceptionDemo.java:8)

try without finally :

public class FNFExceptionDemo {
    public static void main(String[] args) {
        try(BufferedReader br = new BufferedReader(new FileReader("abc.txt"))){
            br.read();
        } catch (IOException f){
            System.out.println("Use local file.");
        }
    }
}
output

java.io.FileNotFoundException: abc.txt (No such file or directory)
	at java.io.FileInputStream.open0(Native Method)
	at java.io.FileInputStream.open(FileInputStream.java:195)
	at java.io.FileInputStream.(FileInputStream.java:138)
	at java.io.FileInputStream.(FileInputStream.java:93)
	at java.io.FileReader.(FileReader.java:58)
	at ExceptionHandling.FNFExceptionDemo.main(FNFExceptionDemo.java:8)

We can write multiple resources in a try but these resources should be separated with (;)

try(r1;r2;r3){
   //risky code        
}catch (IOException f){
    
}

Note :

  • All resources should be AutoCloseable Resources. The resource is said to be AutoCloseable if and only if the corresponding class implements Interface AutoCloseable

  • All I/O, Database, Network related resources are already implements autoCloseable interface

  • AutoCloseable interface introduced in 1.7 and it has only one method i.e. close()

  • All resource reference variables are implicitly final and hence within the try block, we can't perform reassignment otherwise we will get a compile-time error

  • public class Test1 {
        public static void main(String[] args) {
            try(BufferedReader br = new BufferedReader(new FileReader("abc.txt"))){
                br = new BufferedReader(new FileReader("xyz.txt"));
            } catch (IOException f){
                System.out.println("Use local file.");
            }
        }
    }
    
    o/p:
    Error:(4, 6) java: auto-closeable resource br may not be assigned
    

Until Java 1.6, try should be associated with either catch or finally. But from Java 1.7 onwards we can take only try with resources and without catch/finally

try(r1;r2;r3){
   //risky code r1,r2,r3 are resources       
}

Multi catch block :


Until Java 1.6 even though multiple different exceptions having the same handling code but for every exception type, we have to write a separate catch block. So it increases the length of the code and reduces the readability of code.
For e.g.

try{

}catch(ArithmeticException e){
	e.printStackTrace();
}catch(NullPointerException e){
	e.printStackTrace();
}catch(InterruptedException e){
	e.printStackTrace();
}

To overcome this problem java introduces new concept multiple catch block in Java 1.7

try{

}catch(ArithmeticException/IOException e){
	e.printStackTrace();
}catch(NullPointerException/InterruptedException e){
	e.getMessage();
}

Re-throwing exception:


We can use this approach to convert one exception to another exception type

try{
	System.out.println(10/0);
}catch(ArithmeticException e){
	throw new NullPointerException();
}

UncaughtExceptionHandler


Method invoked when the given thread terminates due to the given uncaught exception.
Any exception thrown by this method will be ignored by the Java Virtual Machine.

package mt;

public class ThreadUncaughtExceptionHandlerDemo {
    public static void main(String[] args) {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Run method started performing 10/0");
                throw new RuntimeException("Intentional exception thrown");
            }
        });
        t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                System.out.println("Runtime exception occured for thread : " + t.getName());
                System.out.println(e);
            }
        });
        t.setName("LocalThread");
        t.start();
    }
}

/*
output -
Run method started performing 10/0
Runtime exception occured for thread : LocalThread
java.lang.RuntimeException: Intentional exception thrown
 */

Lets quick summarise what we learn in this post:

  • Exception handling keyword summary

  • Various possible compile-time exceptions

  • Customized/User-Defined exceptions

  • Top 10 exceptions

  • try with resources

  • Multi catch block

With this, we also came to the end of this article and cover all the exception handling in Java. In the next article, we would start with the MultThreading concept in java. Please let us know your views and opinions in the comment section below. I hope you enjoyed this post. Please stay with us for more posts.
For more details on exception handling please refer Video

Exception Handling in Java | Part-2

This is the second post on a series of Exception Handling in Java. In this article, we will learn methods to print exception info, try with multiple catch blocks, finally block and most important difference between final, finally, finalize. Before starting these, please go through Exception Handling in Java | Part-1 so that you clear with the basics of Exception Handling.



Methods to print exception information :


Thowable class defines following methods to print exception information:

    Method                      printable format

  1. printStackTrace()   -   Name of exception : Description StackTrace

  2. toString()                 -   Name of exception : Description

  3. getMessage()           -   Description

For example :

class Test{
	public static void main(String[] args){
		try{
			sop(10/0);
		}catch(AE ae){
			sop(e.getMessge())          // "/ by zero"
			sop(e.toString());	    // "java.lang.AE : / by zero"
			sop(e.printStackTrace());   // "java.lang.AE : / by zero
								  at Test.main()"	
		}
	}
}

Note : Internally default exception handler will use the printStrackTrace() to print exception information to console.


Try with multiple catch blocks


The way of handling an exception is varied from exception to exception. Hence for every exception type, it is highly recommended to take a separate catch block i.e. try with multiple catch blocks.

Worst programming practice :

try{
  //riskey code
}catch(Exception e){
			
}

Best programming practice: use multiple catch blocks

try{
  //riskey code
}catch(ArithmeticException e){
			
}catch(SQLException e e){
			
}catch(FileNotFoundException e){
			
}catch(Exception e){
  //Defaullt exception
}

Note :
  • If try with multiple catch block is present then the order of catch block is very important.

  • We have to take the child first then the parent otherwise we will get a compile-time error saying Exception xxx has already been caught.

  • We can't declare two catch blocks for the same exception otherwise we will get a compile-time error.


Difference between final, finally, finalize

final :

  • final is modifier applicable for classes, methods, and variables

  • If the class is declared as final then we can't extend that class i.e. Inheritance is not possible for final classes

  • If a method is final then we can't use that method in the child class

  • If a variable is declared as final then we can't reassignment for that variable

finally():

try{
  // riskey code
}catch(Exception e){
  // handler code			
}finally{
  // clean-up code
}

The specialty of the finally block is it will be executed always irrespective of whether an exception is raised or not, handled, or not handled.

finalize():

It is a method always invoked by garbage collector just before destroying an object to perform cleanup activities.
once the finalize method completes immediately garbage collector destroys that object.


Note : 
  • finally block is responsible to perform clean up activity related to try block i.e. whatever resources as a part of try block will be closed inside finally block whereas the finalize method is responsible to perform clean up activity related to object i.e. whatever resources associated with the object will be deallocated by using finalize method


Various possible combinations of try-catch-finally


Note :

  1. In try-catch-finally order is very important

  2. try without a catch or finally is invalid otherwise Compile Time Error: try without a catch or finally is invalid

  3. Whenever we are writing catch block compulsory try block is required... try without a catch is invalid

  4. finally without try is invalid

  5. Inside try-catch and finally block we can declare try-catch and finally block i.e. nesting of try-catch-finally is allowed

  6. For try-catch and finally block curly bases are mandatory



throw in Java


Sometimes we can create exception objects explicitly and handover to JVM manually for these we have to use the throw keyword.
For e.g. throw new AE("/ by zero")
The main objective of throw keyword is handover our created exception object to the JVM manually
Hence the result of the following two programs are the same:
The main method is responsible to create the exception object and handover to JVM:

public class Test1{
    public static void main(String[] args) {
        System.out.println(10/0);
    }
}

o/p:
Exception in thread "main" java.lang.ArithmeticException: / by zero
	at ExceptionHandling.Test1.main(Test1.java:3)

Here Programmer creating exception object explicitly and handover to JVM manually

public class Test1{
    public static void main(String[] args) {
        throw new ArithmeticException("Divide by zero");
    }
}

o/p:
Exception in thread "main" java.lang.ArithmeticException: / by zero
	at ExceptionHandling.Test1.main(Test1.java:3)

The best use of the throw keyword is for user-defined exceptions.
Let's see some interesting example of custom exceptions:

Case 1: throw e, if e refers null then we will get NPE

public class Test1{
    static ArithmeticException e = new ArithmeticException();
    public static void main(String[] args) {
        throw e;
    }
}

o/p:
Exception in thread "main" java.lang.ArithmeticException
	at ExceptionHandling.Test1(Test1.java:2)
public class Test1{
    static ArithmeticException e;
    public static void main(String[] args) {
        throw e;
    }
}

o/p:
Exception in thread "main" java.lang.NullPointerException
	at ExceptionHandling.Test1.main(Test1.java:4)

Case 2: After throw statement, we are not allowed to write any statement directly otherwise we will get compile-time error unreachable statement


public class Test1 {
	public static void main(String[] args) {
		throw new ArithmeticException("/ by zero");
		System.out.println("print hello");
	}
}

o/p :
 Compile Time Error:(7, 9) java: unreachable statement
public class Test1 {
	public static void main(String[] args) {
		System.out.println(10/0);
		System.out.println("print hello");
	}
}

o/p: 
Run time Exception in thread "main" java.lang.ArithmeticException: / by zero
	at ExceptionHandling.Test1.main(Test1.java:5)

Case 3: We can use the throw keyword only for throwable type if we are trying for a normal java object then we will get a compile-time error saying incompatible types.


public class Test1 {
    public static void main(String[] args) {
        throw new Test1();
    }
}

o/p:
 Error:(5, 9) java: incompatible types: ExceptionHandling.Test1 cannot be converted to java.lang.Throwable
public class Test1 extends ArithmeticException{
    public static void main(String[] args) {
        throw new Test1();
    }
}

o/p:
Exception in thread "main" ExceptionHandling.Test1
	at ExceptionHandling.Test1.main(Test1.java:5)

throws in Java


In our program if there is a possibility of raising checked exception then compulsory we should handle it, otherwise we will get a compile-time error: Unreported exception java.io.FileNotFoundException; must be caught or declared to be thrown

e.g.
public class Test1{
    public static void main(String[] args) {
        PrintWriter pw = new PrintWriter("abc.txt");
        pw.write("a");
    }
}
o/p:
 Unreported exception java.io.FileNotFoundException; must be caught or declared to be thrown

We can handle this compile-time error by using two ways:

  1. By using try-catch

  2. By using throws

public class Test1{
    public static void main(String[] args) throws InterruptedException {
        Thread.sleep(1000);
    }
}

Note:

  • We can use the throws keyword to delegate the responsibility of exception handling to the caller(JVM/method) then the caller is responsible to handle the exception

  • It is used for only checked exceptions

  • Usage of throws keyword doesn't prevent abnormal termination of a program


public class Test1{
	public static void main(String[] args) throws InterruptedException {
        doMoreStuff();
    }
    public void doMoreStuff() throws InterruptedException {
        doStuff();
    }
	public void doStuff() throws InterruptedException {
        Thread.sleep(1000);
    }
}

In the above program, if we removed at least one throws statement then our program won't compile

Use of throws

  • We can use the throws keyword for method and constructor but not for classes.
    Class Test1 throws Exception - Invalid
    Test1() throws Exception - Valid
    public static void main(String[] args)throws Exception { - valid

  • We can use throws keyword only for throwable types otherwise we will get a compile-time error - incompatible type

  • Within try block if there is no chance of raising an exception, we can't write a catch block for that exception otherwise we will get a compile-time error saying Exception xxx is never thrown in body of corresponding try statement, but this rule is applicable for only fully checked exceptions

  • public class Test1{
        public static void main(String[] args){
            try {
                Thread.sleep(1000);
            }catch (SQLException e){
                System.out.println("sql exception");
            }
        }
    }
        
    o/p:
       Error:(5, 6) java: exception java.sql.SQLException is never thrown in body of corresponding try statement
       Error:(4, 25) java: unreported exception java.lang.InterruptedException; must be caught or declared to be thrown
      

Lets quick summarise what we learn in this post:

  • Methods to print exception information

  • How to use try with multiple catch blocks

  • Difference between final, finally, finalize

  • Various possible combinations of try-catch-finally

  • throw keyword

  • throws keyword

With this, we also came to the end of this article. In the next article, we would be revising and learning Exception handling keywords summary, Various possible compile-time errors in exception handling, Customized or user-defined exceptions, etc.. Please let us know about your views and opinions in the comment section below. I hope you enjoyed these posts. Please stay with us for more posts.
For more details on exception handling please refer Video

Exception Handling in Java | Part-1

In this article, we're going to talk about Exception in Java.



What is an exception?


An unexpected, unwanted event that disturbs the normal flow of the program is called an exception. It is highly recommended to handle the exception. The main objective of exception handling is the graceful termination of the program.

Exception handling doesn't mean repairing an exception, we have to provide an alternative way to continue the rest of the program normally is the concept of exception handling.

Ex. The program requirement is read data from the remote file but at runtime remote file is not available then our program should not be terminated abnormally. We have to provide some local file to continue the program normally. This way of defining alternative is nothing but exception handling

try{
   Read file from remote place
}catch (FileNotFoundException ex)
   use local file and continue rest of the program normally
}

Runtime stack mechanism:


For every thread, JVM will create a runtime stack. Each and every method call performed by that thread will be stored in the corresponding stack. Each entry in the stack is call stack frame or activation record.

After completing every method call, the corresponding entry from the stack will be removed. After completing all method calls the stack will become empty, that empty stack will be removed by JVM just before terminating the thread.

public class Test {
    public static void main(String[] args) {
        doStuff();
    }

    private static void doStuff() {
        doMoreStuff();
    }

    private static void doMoreStuff() {
        System.out.println("Hello");
    }
}

Internal stack details are described in the below diagram:



Default exception handling in java


Inside a method, if any exception occurs, the method in which it is raised is responsible to create an exception object by including the following information:

  • Name of exception

  • Description of Exception

  • Location at which exception occurs [StackTrace]

After creating an exception object, the method handovers the object to the JVM.JVM will check whether the method contains any exception handling code or not? If the method doesn't contain code for exception handling then JVM terminates that method abnormally and removes the corresponding entry from the stack.

Then JVM identifies the caller method and checks whether caller methods contain any handling code or not, If the caller method also doesn't contain handling code, then JVM also terminates the caller methods abnormally and removes the corresponding entry from the stack.

This process will be continued until the main method and if the main method doesn't contain exception handling then JVM terminates the main method abnormally and removes the corresponding entry from the stack. Then JVM handovers responsibility of exception handling to default exception handling, which is the part of JVM.

public class Test {
    public static void main(String[] args) {
        doStuff();
    }

    private static void doStuff() {
        doMoreStuff();
    }

    private static void doMoreStuff() {
        System.out.println(10/0);
    }
}
Exception in thread "main" java.lang.ArithmeticException: / by zero
	at ExceptionHandling.Test.doMoreStuff(Test.java:13)
	at ExceptionHandling.Test.doStuff(Test.java:9)
	at ExceptionHandling.Test.main(Test.java:5)

Default exception handling prints exception information in the following format and terminates program abnormally

Exception in thread "xxx" name of exception: Description StackTrace Note:


  • In a program, at least one method terminates abnormally then program termination is abnormal termination.

  • If all methods terminated normally then only program termination is normal termination.

Exception Hierarchy:


Throwable class acts as the root of the java exception hierarchy.
A throwable class defines two child classes:

  • Exception

  • Error

Exception:

Most of the time exceptions are caused by our program and these are recoverable. e.g. If your program required to read data from the remote file, at run time if the remote file is not available then we will get RunTimeException saying FileNotFoundException if FileNotFoundException exception occurs we can provide a local file and continue the rest of the program normally.


try{
   
   Read file from remote place

} catch (FileNotFoundException ex){

   Use local file and continue rest of the program normally

}

Error:

Most of the time errors are not caused by our program and these are due to lack of system resources. Errors are non-recoverable.

For e.g. If out of memory error occurs being a programmer we can't do anything and the program will be terminated abnormally. The system or server admin is responsible to increase heap memory.
If you have a function like these:

int foo()
{
    // more stuff
    foo();
}

Then foo() will keep calling itself until you get the StackOverflowError.


Checked vs Unchecked Exception:


The exceptions which are checked by the compiler for smooth execution of the program are called checked exceptions.
Here are the few other Checked Exceptions:

  • FileNotFoundException

  • SQLException

  • IOException

  • ClassNotFoundException

  • InvocationTargetException

If there is a chance of raising a checked exception then compulsory we should handle that checked exception(either by try-catch or by throws keywords) otherwise we will get a compile-time error.
The exceptions which are not checked by the compiler are called unchecked exceptions

Here are the few unchecked exception classes:

  • NullPointerException

  • ArrayIndexOutOfBoundsException

  • ArithmeticException

  • IllegalArgumentException

  • NumberFormatException

These exceptions are not caught at the compile time so we didn't get any report but it may result in complete failure of the application when it occurs during execution.
Note :

  • Every exception occurs at runtime only either it is checked or unchecked, there is no chance of occurring exception at compile time.

  • Runtime and its child classes, Error, and its child classes are unchecked, except this remaining are checked exceptions.

Fully Checked vs Partially Checked Exception:


A checked exception is said to be fully checked if and only if all its child classes are also checked.
e.g. IOException, IntteruptedException

A checked exception is said to be partially checked if and only if some of its child classes are unchecked
e.g. Exception, Throwable

Note: The only possible partially checked exception in java are exception and throwable.
Lets quick revision with few more examples :

  • IOException - checked (fully)

  • RunTimeException - unchecked

  • InterruptedException - checked(fully)

  • Error - unchecked

  • Throwable - checked(Partially)

  • AirthmeticException - unchecked

  • NullPointerException - unchecked

  • Exception - checked(Partially)

  • FileNotFoundException - checked(fully)


Customized exception handling using try-catch


Without try-catch :

public class Test1{
    public static void main(String[] args) {
        System.out.println("test1");
        System.out.println(10/0);
        System.out.println("test2");
    }
}
O/P : - 
test1
Exception in thread "main" java.lang.ArithmeticException: / by zero
	at ExceptionHandling.Test1.main(Test1.java:6)

With try-catch :

public class Test1{
    public static void main(String[] args) {
        System.out.println("test1");
        try {
            System.out.println(10/0);
        }catch (ArithmeticException e){
            System.out.println(10/2);
        }
        System.out.println("test2");
    }
}
O/P : - 
test1
5
test2

It is highly recommended to handle exceptions.
The code which may raise an exception i.e. risky code, we have to define that code inside try block and corresponding handling code we have to define inside catch block


try{
	stm1;
	stm2;
	stm3;
}catch(Exception e){
	stm4;
}
stm5;

case1 : If there is no exception - 1,2,3,5 - Normal termination
case2: If exception raised at 2 and the corresponding catch block is matched - 1,4,5 - Normal Termination
case3: If exception raised at 2 and the corresponding catch block is not matched - 1, Abnormal Termination
case4: If exception raised at 4 or 5 then it is always abnormal termination

Note:

  1. Within the try block, if an exception occurred anywhere then rest of the try block won't be executed event though we handled that exception. Hence within the try block, we have to take risky code only and length of the try block should be as least as possible

  2. In addition, to try block there may be a chance of raising exception inside catch and finally blocks

  3. If any statement which is not part of the try block and raises an exception then it is always abnormal termination


Lets quick summarise what we learn in this post:

  • Whats is an exception?

  • How the runtime stack mechanism works in exception handling?

  • Default exception handling in java

  • Exception Hierarchy - Exception and Error

  • Difference between Checked vs Unchecked Exception

  • What is mean by fully checked and partially checked exception

  • Customized exception handling using try-catch

With this, we also came to the end of this article. In the next article, we would be learning Control flow in try-catch, Methods to print exception info, try with multiple catch blocks, etc.. Please let us know about your views and opinions in the comment section below. I hope you enjoyed this post. Please stay with us for more posts.
For more details on exception handling please refer Video