0% found this document useful (0 votes)
62 views46 pages

Oops Notes

Uploaded by

animeshsingh2207
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
62 views46 pages

Oops Notes

Uploaded by

animeshsingh2207
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 46

EXCEPTION HANDLING

The Exception Handling in Java is one of the powerful mechanism to handle the runtime errors so that
the normal flow of the application can be maintained.

In Java, an exception is an event that disrupts the normal flow of the program. It is an object which is
thrown at runtime.

Hierarchy of Java Exception classes

The java.lang.Throwable class is the root class of Java Exception hierarchy inherited by two subclasses:
Exception and Error. The hierarchy of Java Exception classes is given below:

Difference between Checked and Unchecked Exceptions

CATEGORY 1 :

1) Checked Exception

The classes that directly inherit the Throwable class except RuntimeException and Error are known as
checked exceptions. For example, IOException, SQLException, etc. Checked exceptions are checked at
compile-time.

2) Unchecked Exception

The classes that inherit the RuntimeException are known as unchecked exceptions. For example,
ArithmeticException, NullPointerException, ArrayIndexOutOfBoundsException, etc. Unchecked
exceptions are not checked at compile-time, but they are checked at runtime.

3) Error

Errors represent irrecoverable conditions such as Java virtual machine (JVM) running out of memory,
memory leaks, stack overflow errors, library incompatibility, infinite recursion, etc. Errors are usually
beyond the control of the programmer.

CATEGORY 2 :

1. User-Defined Exceptions:

Sometimes, the built-in exceptions in Java are not able to describe a certain situation. In such cases,
users can also create exceptions of their own, which are called ‘user-defined Exceptions’.

------------------------------------------------------------------------------

The advantages of Exception Handling in Java are as follows:

1. Provision to Complete Program Execution


2. Easy Identification of Program Code and Error-Handling Code

3. Propagation of Errors

4. Meaningful Error Reporting

5. Identifying Error Types

Methods that prints the description of the exception.

1. printStackTrace()

This method prints exception information in the format of the Name of the exception: description of the
exception, stack trace(the line number and class name where the exception occurred.).

2. toString()

The toString() method prints exception information in the format of the Name of the exception:
description of the exception.

3. getMessage()

The getMessage() method prints only the description of the exception.

Common Scenarios of Java Exceptions

There are given some scenarios where unchecked exceptions may occur. They are as follows:

1) A scenario where ArithmeticException occurs

int a=50/0; //ArithmeticException

2) A scenario where NullPointerException occurs

If we have a null value in any variable, performing any operation on the variable throws a
NullPointerException.

String s=null;

System.out.println(s.length()); //NullPointerException

3) A scenario where NumberFormatException occurs

If the formatting of any variable or number is mismatched, it may result into NumberFormatException.
Suppose we have a string variable that has characters; converting this variable into digit will cause
NumberFormatException.

String s="abc";

int i=Integer.parseInt(s); //NumberFormatException


4) A scenario where ArrayIndexOutOfBoundsException occurs

When an array exceeds to it's size, the ArrayIndexOutOfBoundsException occurs. there may be other
reasons to occur ArrayIndexOutOfBoundsException.

int a[]=new int[5];

a[10]=50; //ArrayIndexOutOfBoundsException

----------------------------------------------------------

Default Exception Handling: Whenever inside a method, if an exception has occurred, the method
creates an Object known as an Exception Object and hands it off to the run-time system(JVM). The
exception object contains the name and description of the exception and the current state of the
program where the exception has occurred

How Does JVM Handle an Exception?

The run-time system searches the call stack to find the method that contains a block of code that can
handle the occurred exception. The block of the code is called an Exception handler.

The run-time system starts searching from the method in which the exception occurred and proceeds
through the call stack in the reverse order in which methods were called.

If it finds an appropriate handler, then it passes the occurred exception to it. An appropriate handler
means the type of exception object thrown matches the type of exception object it can handle.

If the run-time system searches all the methods on the call stack and couldn’t have found the
appropriate handler, then the run-time system handover the Exception Object to the default exception
handler, which is part of the run-time system. This handler prints the exception information in the
following format and terminates the program abnormally.

How Programmer Handle an Exception?

Customized Exception Handling: Java exception handling is managed via five keywords: try, catch,
throw, throws, and finally. Briefly, here is how they work.

Syntax of Java try-catch

try{

//code that may throw an exception

}catch(Exception_class_Name ref){}

Syntax of try-finally block


try{

//code that may throw an exception

}catch(Exception_class_Name ref){}

finally{}

Catch block

Java catch block is used to handle the Exception by declaring the type of exception within the parameter.
The declared exception must be the parent class exception ( i.e., Exception) or the generated exception
type. However, the good approach is to declare the generated type of exception.

The JVM firstly checks whether the exception is handled or not. If exception is not handled, JVM
provides a default exception handler that performs the following tasks:

Prints out exception description.

Prints the stack trace (Hierarchy of methods where the exception occurred).

Causes the program to terminate.

But if the application programmer handles the exception, the normal flow of the application is
maintained, i.e., rest of the code is executed.

Problem if not used Exception Handling :

REASON :

There might be 100 lines of code after the exception. If the exception is not handled, all the code below
the exception won't be executed.

Let's see an example to resolve the exception in a catch block.

public class TryCatchExample6 {

public static void main(String[] args) {

int i=50;

int j=0;

int data;

try

data=i/j; //may throw exception

}
// handling the exception

catch(Exception e)

// resolving the exception in catch block

System.out.println(i/(j+2));

Multi Catch Blocks

A try block can be followed by one or more catch blocks. Each catch block must contain a different
exception handler. So, if you have to perform different tasks at the occurrence of different exceptions,
use java multi-catch block.

Points to remember

* Order of the catch blokcs should be from the most specific to the most general.

* only one exception can occur at a given point of time and it will be handled only by any one excetion
handler.

EXAMPLE

public class MultipleCatchBlock1 {

public static void main(String[] args) {

try{

int a[]=new int[5];

a[5]=30/0;

catch(ArithmeticException e)

System.out.println("Arithmetic Exception occurs");

catch(ArrayIndexOutOfBoundsException e)

System.out.println("ArrayIndexOutOfBounds Exception occurs");

}
catch(Exception e)

System.out.println("Parent Exception occurs");

System.out.println("rest of the code");

NESTED TRY BLOCK

In Java, using a try block inside another try block is permitted. It is called as nested try block. Every
statement that we enter a statement in try block, context of that exception is pushed onto the stack.

WHY USE NESTED TRY ?

Sometimes a situation may arise where a part of a block may cause one error and the entire block
itself may cause another error. In such cases, exception handlers have to be nested.

Syntax:

....

//main try block

try

statement 1;

statement 2;

//try catch block within another try block

try

statement 3;

statement 4;

//try catch block within nested try block

try

statement 5;

statement 6;
}

catch(Exception e2)

//excepti*on message

} *

catch(Exception e1)

//exception message

//catch block of parent (outer) try block

catch(Exception e3)

//exception message

FINALLY

Java finally block is a block used to execute important code such as closing the connection, etc.

Java finally block is always executed whether an exception is handled or not. Therefore, it contains all
the necessary statements that need to be printed regardless of the exception occurs or not.

The finally block follows the try-catch block.

Note: If you don't handle the exception, before terminating the program, JVM executes finally block (if
any).

Note: For each try block there can be zero or more catch blocks, but only one finally block.

Note: The finally block will not be executed if the program exits (either by calling System.exit() or by
causing a fatal error that causes the process to abort).

THROW

The Java throw keyword is used to throw an exception explicitly.

We specify the exception object which is to be thrown. The Exception has some message with it that
provides the error description. These exceptions may be related to user inputs, server, etc.
We can throw either checked or unchecked exceptions in Java by throw keyword. It is mainly used to
throw a custom exception.

3: Throwing User-defined Exception

exception is everything else under the Throwable class.

TestThrow3.java

// class represents user-defined exception

class UserDefinedException extends Exception

public UserDefinedException(String str)

// Calling constructor of parent Exception

super(str);

// Class that uses above MyException

public class TestThrow3

public static void main(String args[])

try

// throw an object of user defined exception

throw new UserDefinedException("This is user-defined exception");

catch (UserDefinedException ude)

System.out.println("Caught the exception");

// Print the message from MyException object

System.out.println(ude.getMessage());
}

ANOTHER EXAMPLE OF EXCEPTION HANDLING USING TRY CATCH THROW AND THROWS.

public class BankAccount {

private double balance;

public BankAccount(double balance) {

this.balance = balance;

public void withdraw(double amount) throws InsufficientFundsException {

if (balance < amount) {

throw new InsufficientFundsException("Insufficient funds.");

balance -= amount;

public static void main(String[] args) {

BankAccount account = new BankAccount(100.00);

try {

account.withdraw(150.00); // This will throw InsufficientFundsException

} catch (InsufficientFundsException e) {

System.out.println("Error: " + e.getMessage());

Which exception should be declared?


Ans: Checked exception only, because:

unchecked exception: under our control so we can correct our code.

error: beyond our control. For example, we are unable to do anything if there occurs
VirtualMachineError or StackOverflowError.

Declare An Exception Using Throws

In case we declare the exception, if exception does not occur, the code will be executed fine.

In case we declare the exception and the exception occurs, it will be thrown at runtime because throws
does not handle the exception.

DIFFERENCE BETWEEN THROW AND THROWS

DIFFERENCE BETWEEN FINAL , FINNALY AND FINALIZE

THREAD Thread represents the smallest processing unit and serves as an autonomous execution path
within a code.

In the context of Java, a thread signifies an individual execution sequence within a Java program. Java
programs can encompass multiple threads, each capable of concurrent and autonomous operation.
Threads find application in various tasks, including background processing, handling multiple user
interactions, and implementing animations.

By using threads, a Java program can perform multiple tasks simultaneously, increasing its overall
responsiveness and performance.

Different Ways to Build a Thread in Java

1. By extending java.lang.Thread class: The java.lang.Thread class implements the java.lang.Runnable


interface and allows you to create a new thread by extending the Thread class and overriding its run()
method. The run() method defines the task that the thread will perform when it starts. To start the
thread, you need to call the start() method.

class MyThread extends Thread {

public void run() {

// Task to be performed by the thread

}
public static void main(String[] args) {

MyThread myThread = new MyThread();

myThread.start();

2. By implementing java.lang.Runnable interface : The java.lang.Runnable interface is a functional


interface that defines a single method, run(), which contains the code that the thread will execute. To
create a new thread, you need to create an instance of java.lang.Thread and pass the Runnable instance
to its constructor. To start the thread, you need to call the start() method on the java.lang.Thread
instance.

class MyRunnable implements Runnable {

public void run() {

// Task to be performed by the thread

public static void main(String[] args) {

MyRunnable myRunnable = new MyRunnable();

Thread myThread = new Thread(myRunnable);

myThread.start();

What are Thread Methods in Java?

The java.lang.Thread class provides several methods for creating and managing threads in Java. Some of
the commonly used methods include.

start(): Starts the execution of the thread. This method calls the run() method in a new thread of
execution.

run(): Contains the code that the thread will execute when it starts.

sleep(long millis): Causes the current thread to pause execution for the specified amount of time (in
milliseconds).

join(): Causes the current thread to wait for the completion of the specified thread.

yield(): Causes the current thread to temporarily pause execution and allow other threads to run.

interrupt(): Interrupts the current thread.


getName(): Returns the name of the thread.

setName(String name): Changes the name of the thread.

isAlive(): Returns a Boolean indicating whether the thread is still running.

setPriority(int priority): Changes the priority of the thread.

Thread Life Cycle in Java

The thread life cycle in Java consists of the following stages:

multiple threads can coexist in the same state simultaneously.

New

Active

Blocked/Waiting

Timed Waiting

Terminated

1. New State - In this state, a thread object has been instantiated, but the start() method has not yet
been called on it, so the thread has not begun executing. The thread remains in the "New" state until the
start() method is called, at which point it transitions to the "Active" state and is ready to be executed by
the Java virtual machine.

2. Active State -When a thread calls the start() method, it transitions from the new to the active state.
The active state contains two states: one that is runnable and one that is running.

(i) Runnable State - Runnable :

The "Runnable" state in the life cycle of thread in Java refers to the state where a thread is ready to run,
but may be waiting for resources to become available.

In this state, a thread has been created and started, but has not yet begun execution. The thread is
waiting for the Java virtual machine to execute it. The thread remains in this state until the JVM
schedules it to run and moves it to the "Running" state.

(ii) Running State - Running :

The "Running" state in the life cycle of thread in Java refers to the state where a thread is currently
executing.
In this state, a thread has been scheduled by the Java virtual machine to run and is actively executing its
code. The thread remains in the "Running" state until it completes its execution, is blocked waiting for a
resource or synchronization lock, or is voluntarily paused using methods such as sleep() or yield().

A thread can enter the "Running" state from the "Runnable" state, when the JVM schedules it to run, or
from the "Blocked" state, after it has acquired the necessary resources or synchronization locks.

3. Blocked/Waiting State - The "Blocked/Waiting" state in the life cycle of thread in Java refers to the
state where a thread is waiting for a resource or synchronization lock.

In this state, a thread is unable to proceed with its execution until it acquires the necessary resources or
synchronization locks. The thread continues in the "Blocked/Waiting" state until the resource becomes
available or the lock is released, at which time it changes to the "Runnable" state and is ready for
execution by the Java virtual machine.

4. Timed Waiting State - When we call the sleep() method on a specified thread, we are using timed
waiting. The sleep() function places the thread in timed wait mode. When the timer expires, the thread
wakes up and resumes execution from where it left off.

because NORMAL Waiting can sometimes lead to starvation

5. Termination State - The “Termination” state in the life cycle of thread in Java refers to the state where
a thread has completed its execution.

In this state, a thread has run to completion and has exited its run() method. The thread remains in the
“Termination” state until its resources are cleaned up by the Java virtual machine. After that, the thread
is considered to be terminated and no longer exists.

--------------------------------------------------------------------------------------------------------------------------------

DAEMON THREAD

Daemon Thread in Java is a special type of thread that runs in the background and provides support to
the other threads present in the applications. Daemon Thread in Java is known as the background thread
as they run continuously in the background until the application terminates. The Daemon Threads in Java
are designed to support the application’s used threads.

The Daemon Thread in Java is given the lowest possible priority and the JVM terminates them
automatically when all the user threads have terminated.

PROPERTIES

The following are some properties of Daemon Thread in Java.

It is the lowest-priority thread.

They are automatically terminated by the JVM if all other used threads have been terminated.

Daemon Thread in Java cannot prevent the JVM from terminating if all other threads have completed
their tasks.
The JVM does not know the status of the Daemon Thread in Java whether it is active or not.

METHODS PRESENT IN DAEMON THREAD

public void setDaemon(boolean status)

This method is used for declaring the current thread as a daemon thread or a user thread.

public final boolean isDaemon()

This method returns a boolean value whether the current thread is a Daemon Thread or not.

EXAMPLE OF DAEMON THREAD

Daemn thread can be implemeted by implementig the runnable interface and passing it to the Thread
Constructor.

class DaemonThread1 extends Thread{

public void run(){

if(Thread.currentThread().isDaemon()){

System.out.println("Daemon Thread executing");

} else {

System.out.println("User thread excuting");

public static void main(String[] args){

DaemonThread1 t1 = new DaemonThread1();

DaemonThread1 t2 = new DaemonThread1();

DaemonThread1 t3 = new DaemonThread1();

t1.setDaemon(true);

t1.start();

t2.start();

t3.start();

USES OF DAEMON THREAD


Here are some common uses of the Daemon Thread in Java.

The Daemon Thread in Java is quite useful in situations where we need to perform the background
processes in a continuous manner.

Daemon Thread in Java is also used when an application need to perform maintenance tasks in the
background.

Daemon threads are also used in some standard Java Classes.

OUTPUT

Daemon Thread executing

User thread excuting

User thread excuting

----------------------------------------------------------------

In the multifaceted world of Java threading, the concept of Daemon Threads plays a distinctive role.
Daemon threads are a special category of threads in Java that run in the background and provide
support to non-daemon threads. Unlike user threads, daemon threads do not prevent the Java Virtual
Machine (JVM) from exiting when all non-daemon threads have completed their execution.
Understanding the nuances of daemon threads is crucial for Java developers seeking to optimize
resource management and streamline concurrent programming.

Daemon threads are commonly used for tasks such as garbage collection and other maintenance
activities, where they operate silently in the background without obstructing the main execution flow.
This introduction explores the significance of daemon threads in Java and sheds light on their pivotal role
in creating efficient and responsive applications.

Exceptions in Daemon Thread in Java

The Daemon Thread in Java, if not handled carefully throws exceptions. The following Exceptions are
thrown if Daemon Thread is not used in the correct manner.

IllegalThreadStateException: This exception is thrown if you call the setDaemon() method on a thread
that has already been started.

SecurityException: This exception is thrown when the current thread is not able to change the thread.

SYNCHRONIZATION OF THREADS

Thread Synchronization is used to coordinate and ordering of the execution of the threads in a multi-
threaded program. There are two types of thread synchronization are mentioned below:

Mutual Exclusive

Cooperation (Inter-thread communication in Java)


MUTUAL EXCLUSIVE

Mutual Exclusive helps keep threads from interfering with one another while sharing data. There are
three types of Mutual Exclusive mentioned below:

Synchronized method.

A method can be synchronized by using the synchronized keyword in its declaration. When a method is
synchronized, the thread holds the monitor (lock) for the object on which the method is called. Only
one thread can execute a synchronized method on the same object at a time.

Example :

class Sender {

public synchronized void send(String msg)

System.out.println("Sending\t" + msg);

try {

Thread.sleep(1000);

catch (Exception e) {

System.out.println("Thread interrupted.");

System.out.println("\n" + msg + "Sent");

Synchronized block.

A synchronized block is used to synchronize a specific block of code within a method. This provides
more fine-grained control over synchronization compared to synchronizing the entire method. It allows
synchronization on a particular object, which can improve performance and reduce contention.

EXAMPLE :

class Sender

public void send(String msg)

synchronized(this)

{
System.out.println("Sending\t" + msg );

try

Thread.sleep(1000);

catch (Exception e)

System.out.println("Thread interrupted.");

System.out.println("\n" + msg + "Sent");

static synchronization.

Static synchronization involves synchronizing static methods or blocks. When a static method is
synchronized, the lock is held on the Class object associated with the class. This ensures that only one
thread can execute a static synchronized method or block at a time across all instances of the class.

//program to demonstrate working of

// synchronized THREADS

import java.io.*;

import java.util.*;

// A Class used to send a message

class Sender {

public void send(String msg)

System.out.println("Sending\t" + msg);

try {

Thread.sleep(1000);

catch (Exception e) {
System.out.println("Thread interrupted.");

System.out.println("\n" + msg + "Sent");

// Class for send a message using Threads

class ThreadedSend extends Thread {

private String msg;

Sender sender;

// Receives a message object and a string

// message to be sent

ThreadedSend(String m, Sender obj)

msg = m;

sender = obj;

public void run()

// Only one thread can send a message

// at a time.

synchronized (sender)

// synchronizing the send object

sender.send(msg);

// Driver class
class SyncDemo {

public static void main(String args[])

Sender send = new Sender();

ThreadedSend S1 = new ThreadedSend(" Hi ", send);

ThreadedSend S2 = new ThreadedSend(" Bye ", send);

// Start two threads of ThreadedSend type

S1.start();

S2.start();

// wait for threads to end

try {

S1.join();

S2.join();

catch (Exception e) {

System.out.println("Interrupted");

OUTPUT

Sending Hi

Hi Sent

Sending Bye

Bye Sent

EXPLANATION

In the above example, we choose to synchronize the Sender object inside the run() method of the
ThreadedSend class

ALTERNATIVELY.
we could define the whole send() block as synchronized, producing the same result. Then we don’t have
to synchronize the Message object inside the run() method in ThreadedSend class.

Sometimes it is preferable to synchronize only part of a method. Java synchronized blocks inside
methods make this possible

INTER THREAD COMMUNICATON :

Allows threads to communicate and cooperate with each other, often used to coordinate their execution
and share data. Java provides built-in mechanisms for inter-thread communication.

How Java multi-threading tackles this problem?

Polling : Polling in inter-thread communication is a technique where a thread repeatedly checks a


condition to determine if a certain event or state has occurred. Unlike blocking operations, where a
thread waits and gets notified (e.g., using wait() and notify()), polling involves actively checking the state
in a loop until the condition is met irrespective of wether the resource are availiabl or nt.

To avoid polling, Java uses three methods, namely, wait(), notify(), and notifyAll(). All these methods
belong to object class as final so that all classes have them. They must be used within a synchronized
block only.

wait(): It tells the calling thread to give up the lock and go to sleep until some other thread enters the
same monitor and calls notify().

notify(): It wakes up one single thread called wait() on the same object. It should be noted that calling
notify() does not give up a lock on a resource.

notifyAll(): It wakes up all the threads called wait() on the same object.

here one circle is the producer and other is the consumer.

EXAMPLE :

import java.util.LinkedList;

import java.util.Queue;

class SharedQueue {

private final Queue<Integer> queue = new LinkedList<>();

private final int capacity;

public SharedQueue(int capacity) {

this.capacity = capacity;

}
public synchronized void produce(int item) throws InterruptedException {

while (queue.size() == capacity) {

wait(); // Wait if the queue is full

queue.offer(item);

System.out.println("Produced: " + item);

notify(); // Notify consumers that an item has been added

public synchronized int consume() throws InterruptedException {

while (queue.isEmpty()) {

wait(); // Wait if the queue is empty

int item = queue.poll();

System.out.println("Consumed: " + item);

notify(); // Notify producers that an item has been removed

return item;

class Producer implements Runnable {

private final SharedQueue sharedqueue;

public Producer(SharedQueue sharedQueue) {

this.sharedQueue = sharedqueue;

@Override

public void run() {


try {

for (int i = 0; i < 50; i++) {

sharedQueue.produce(i);

Thread.sleep(100); // Simulate time taken to produce an item

} catch (InterruptedException e) {

Thread.currentThread().interrupt();

class Consumer implements Runnable {

private final SharedQueue sharedQueue;

public Consumer(SharedQueue sharedQueue) {

this.sharedQueue = sharedQueue;

@Override

public void run() {

try {

for (int i = 0; i < 50; i++) {

sharedQueue.consume();

Thread.sleep(150); // Simulate time taken to consume an item

} catch (InterruptedException e) {

Thread.currentThread().interrupt();

}
}

public class ProducerConsumerDemo {

public static void main(String[] args) {

SharedQueue sharedQueue = new SharedQueue(10);

Thread producerThread = new Thread(new Producer(sharedQueue));

Thread consumerThread = new Thread(new Consumer(sharedQueue));

producerThread.start();

consumerThread.start();

try {

producerThread.join();

consumerThread.join();

} catch (InterruptedException e) {

Thread.currentThread().interrupt();

THREAD GROUPS IN JAVA

Java provides a convenient way to group multiple threads in a single object. In such a way, we can
suspend, resume or interrupt a group of threads by a single method call.

Note: Now suspend(), resume() and stop() methods are deprecated.

Java thread group is implemented by java.lang.ThreadGroup class.

A ThreadGroup represents a set of threads. A thread group can also include the other thread group. The
thread group creates a tree in which every thread group except the initial thread group has a parent.

A thread is allowed to access information about its own thread group, but it cannot access the
information about its thread group's parent thread group or any other thread groups.

Constructors of ThreadGroup class

There are only two constructors of ThreadGroup class.


------------------------------------------------------------------------------------------------------------------------

--------------------------------------------------------------------------------------------------------------------------

GENERICS IN JAVA

Generics means parameterized types. The idea is to allow type (Integer, String, … etc., and user-defined
types) to be a parameter to methods, classes, and interfaces. Using Generics, it is possible to create
classes that work with different data types. An entity such as class, interface, or method that operates on
a parameterized type is a generic entity.

Why Generics?

The Object is the superclass of all other classes, and Object reference can refer to any object. These
features lack type safety. Generics add that type of safety feature.

Types of Java Generics

Generic Method: Generic Java method takes a parameter and returns some value after performing a
task. It is exactly like a normal function, however, a generic method has type parameters that are cited
by actual type. This allows the generic method to be used in a more general way. The compiler takes
care of the type of safety which enables programmers to code easily since they do not have to perform
long, individual type castings.

// Java program to show working of user defined

// Generic functions

class Test {

// A Generic method example

static <T> void genericDisplay(T element)

System.out.println(element.getClass().getName() + " = " + element);

// Driver method

public static void main(String[] args)

{
// Calling generic method with Integer argument

genericDisplay(11);

// Calling generic method with String argument

genericDisplay("GeeksForGeeks");

// Calling generic method with double argument

genericDisplay(1.0);

OUTPUT

java.lang.Integer = 11

java.lang.String = GeeksForGeeks

java.lang.Double = 1.0

Generic Classes: A generic class is implemented exactly like a non-generic class. The only difference is
that it contains a type parameter section. There can be more than one type of parameter, separated by
a comma. The classes, which accept one or more parameters, ?are known as parameterized classes or
parameterized types.

EXAMPLE

// Java program to show working of user defined

// Generic classes

// We use < > to specify Parameter type

class Test<T> {

// An object of type T is declared

T obj;

Test(T obj) {

this.obj = obj; // constructor

public T getObject() {
return this.obj;

// Driver class to test above

class Main {

public static void main(String[] args)

// instance of Integer type

Test<Integer> iObj = new Test<Integer>(15);

System.out.println(iObj.getObject());

// instance of String type

Test<String> sObj = new Test<String>("GeeksForGeeks");

System.out.println(sObj.getObject());

Output

15

GeeksForGeeks

----------------------------------------------

// Java program to show multiple

// type parameters in Java Generics

// We use < > to specify Parameter type

class Test<T, U>

T obj1; // An object of type T

U obj2; // An object of type U


// constructor

Test(T obj1, U obj2)

this.obj1 = obj1;

this.obj2 = obj2;

// To print objects of T and U

public void print()

System.out.println(obj1);

System.out.println(obj2);

// Driver class to test above

class Main

public static void main (String[] args)

Test <String, Integer> obj = new Test<String, Integer>("GfG", 15);

obj.print();

OUTPUT

GFG

15
------------------------------------------

Advantages of Generics:

Programs that use Generics has got many benefits over non-generic code.

1. Code Reuse: We can write a method/class/interface once and use it for any type we want.

2. Type Safety: Generics make errors to appear compile time than at run time (It’s always better to
know problems in your code at compile time rather than making your code fail at run time). Suppose
you want to create an ArrayList that store name of students, and if by mistake the programmer adds an
integer object instead of a string, the compiler allows it. But, when we retrieve this data from ArrayList, it
causes problems at runtime.

3. Individual Type Casting is not needed

4. Implementing Generic Algorithms: By using generics, we can implement algorithms that work on di
fferent types of objects.

There may be times when you want to restrict the types that can be used as type arguments in a
parameterized type. For example, a method that operates on numbers might only want to accept
instances of Numbers or their subclasses. This is what bounded type parameters are for.

Bounded Types with Generics in Java

Sometimes we don’t want the whole class to be parameterized. In that case, we can create a Java
generics method. Since the constructor is a special kind of method, we can use generics type in
constructors too.

Suppose we want to restrict the type of objects that can be used in the parameterized type. For
example, in a method that compares two objects and we want to make sure that the accepted objects
are Comparables.

The invocation of these methods is similar to the unbounded method except that if we will try to use any
class that is not Comparable, it will throw compile time error.

How to Declare a Bounded Type Parameter in Java?

List the type parameter’s name,

Along with the extends keyword

And by its upper bound. (which in the below example c is A.)

CODE !!

// This class only accepts type parameters as any class

// which extends class A or class A itself.


// Passing any other type will cause compiler time error

class Bound<T extends A>

private T objRef;

public Bound(T obj){

this.objRef = obj;

public void doRunTest(){

this.objRef.displayClass();

class A

public void displayClass()

System.out.println("Inside super class A");

class B extends A

public void displayClass()

{
System.out.println("Inside sub class B");

class C extends A

public void displayClass()

System.out.println("Inside sub class C");

public class BoundedClass

public static void main(String a[])

// Creating object of sub class C and

// passing it to Bound as a type parameter.

Bound<C> bec = new Bound<C>(new C());

bec.doRunTest();

// Creating object of sub class B and

// passing it to Bound as a type parameter.

Bound<B> beb = new Bound<B>(new B());

beb.doRunTest();

// similarly passing super class A


Bound<A> bea = new Bound<A>(new A());

bea.doRunTest();

Bound<String> bes = new Bound<String>(new String());

bea.doRunTest();

Output :

error: type argument String is not within bounds of type-variable T

Key Points:
Single Class Bound: You can only specify one class in the extends clause (e.g., T extends A), but that
class can have multiple subclasses.

Multiple Interface Bounds: You can specify multiple interfaces if you need (e.g., T extends A &
SomeInterface1 & SomeInterface2), but only one class can be used for the type bound.

Multiple Bounds

Bounded type parameters can be used with methods as well as classes and interfaces.

Java Generics supports multiple bounds also, i.e., In this case, A can be an interface or class. If A is class,
then B and C should be interfaces. We can’t have more than one class in multiple bounds

Syntax:

<T extends superClassName & Interface>

class Bound<T extends A & B>

private T objRef;

public Bound(T obj){

this.objRef = obj;

}
public void doRunTest(){

this.objRef.displayClass();

interface B

public void displayClass();

class A implements B

public void displayClass()

System.out.println("Inside super class A");

public class BoundedClass

public static void main(String a[])

//Creating object of sub class A and

//passing it to Bound as a type parameter.

Bound<A> bea = new Bound<A>(new A());

bea.doRunTest();
}

=> Limitations

Cannot Instantiate Generic Types with Primitive Types

class Pair<K, V> {

private K key;

private V value;

public Pair(K key, V value) {

this.key = key;

this.value = value;

// ...

Cannot Use Casts or instanceof with Parameterized Types

When creating a Pair object, you cannot substitute a primitive type for the type parameter K or V:

Pair<int, char> p = new Pair<>(8, 'a'); // compile-time error

Typically, you cannot cast to a parameterized type unless it is parameterized by unbounded wildcards.
For example:

List<Integer> li = new ArrayList<>();

List<Number> ln = (List<Number>) li; // compile-time error

Cannot Create Arrays of Parameterized Types

You cannot create arrays of parameterized types. For example, the following code does not compile:

List<Integer>[] arrayOfLists = new List<Integer>[2]; // compile-time error


Cannot Create, Catch, or Throw Objects of Parameterized Types

A generic class cannot extend the Throwable class directly or indirectly. For example, the following
classes will not compile:

// Extends Throwable indirectly

class MathException<T> extends Exception { /* ... */ } // compile-time error

--------------------------------------------------------------------------------------------------------------------------------

STREAMS :

Streams are a powerful feature introduced in Java 8 that revolutionized the way we work with
collections and data manipulation. Streams provide a concise and functional way to perform operations
on data, making code more readable, maintainable, and efficient. Whether you’re dealing with lists,
arrays, or any collection, streams offer a modern approach to transform, filter, and process data. Let’s
discuss what is stream in Java, and also types of streams in Java.

A java stream is a group of objects that can be piped together to produce the desired result.

Streams are used in Java to transfer data between programs and I/O devices like a file, network
connections, or consoles.

Different types of Streams in JAVA

1. Byte Streams

ByteStream classes are used to read bytes from and write bytes to an input stream. To put it another
way, ByteStream classes read and write 8-bit data. Using ByteStream classes, we can save video, audio,
characters, and so on. The java.io package contains these classes.

Byte Java streams have a three-phase mechanism:

Split: A spliterator divides the input data source into a stream. The Java Spliterator interface is an
internal iterator that divides the stream into smaller parts for traversal.

Apply: The elements in the stream are processed.

Combine: After the elements have been processed, they are combined once more to produce a single
result.

The ByteStream classes are classified into two types: InputStream and OutputStream. These are the
abstract super classes for all Input/Output stream classes
InputStream:

This type of java stream reads data from a source. An InputStream can read data from a file, network
connection, or any other I/O device. An InputStream can be used to read data from a file

Syntax of InputStream:

FileInputStream sourceStream = new FileInputStream("path_to_file");

OutputStream :

The outputstream is a java stream that takes data from a Java program and sends or writes it to the
destination (data sink). A data flow out of a program is represented by an output. The output stream
connects a Java program to a data sink.

Syntax of Output Stream :

FileOutputStream targetStream = new FileOutputStream("path_to_file");

Explanation

Let’s look at an example of using Byte Stream to copy the contents of one file to another. In this example,
we’ll make two FileInputStream and FileOutputStream objects.

The names of the source and destination files are passed to the FileInputStream and FileOutputStream
classes as parameters. The content of the source file is then copied to the destination file.

CODE !!

import java.io.*;

public class ByteStreamExample

public static void main(String[] args) throws IOException

FileInputStream sourceStream = null;

FileOutputStream targetStream = null;

try

sourceStream = new FileInputStream("source.txt");

targetStream = new FileOutputStream ("destination.txt");

// Reading source file using read method


// and write to file byte by byte using write method

int temp;

while ((temp = sourceStream.read()) != -1)

targetStream.write((byte)temp);

finally

if (sourceStream != null){

sourceStream.close();

if (targetStream != null){

targetStream.close();

2. Character Stream

The Character stream is used for 16-bit Unicode input and output operations. Character streams would
be advantageous if we wanted to copy a text file containing characters from one source to another
using streams because it deals with characters. Java characters are 2 bytes (or 16 bits) in
size.CharacterStream classes are provided by the java.io package to overcome the limitations of
ByteStream classes, which can only handle 8-bit bytes and are incompatible with working directly with
Unicode characters. CharacterStream classes are used to work with Unicode characters that are 16 bits
in length. They can work with characters, char arrays, and Strings.

CharacterStream classes are divided into two types for this purpose: Reader classes and Writer classes.

FileReader

It is used to read two bytes at a time from the source. The function Object() { [native code] } for creating
an instance of the FileReader class is as follows.

Syntax of FileReader:

FileFileWriter in = new FileWriter("path_to_file");

FileWriter

It is used to write two bytes at a time to the destination. The function Object() { [native code] } for
creating an instance of the FileWriter class is as follows.

Syntax of FileWriter:

FileWriter in = new FileWriter("path_to_file");

CODE !!

import java.io.*;

public class CharacterStreamExample {

public static void main(String args[]) throws IOException {

FileReader in = null;

FileWriter out = null;

// Reading source file using read method

// and write to file using write method

try {

in = new FileReader("source.txt");

out = new FileWriter("destination.txt");

int c;

while ((c = in.read()) != -1) {

out.write(c);

finally {

if (in != null) {

in.close();

if (out != null) {

out.close();

}
}

-------------------------------------------------------------------------------------------------------------------------

EXAMLPLE OF SWING COMPONENTS

import javax.swing.*;

public class SwingApp {

SwingApp() {

JFrame f = new JFrame();

JLabel firstName = new JLabel("First Name");

firstName.setBounds(20, 50, 80, 20);

JLabel lastName = new JLabel("Last Name");

lastName.setBounds(20, 80, 80, 20);

JLabel dob = new JLabel("Date of Birth");

dob.setBounds(20, 110, 80, 20);

JTextField firstNameTF = new JTextField();

firstNameTF.setBounds(120, 50, 100, 20);

JTextField lastNameTF = new JTextField();

lastNameTF.setBounds(120, 80, 100, 20);

JTextField dobTF = new JTextField();..


dobTF.setBounds(120, 110, 100, 20);

JButton sbmt = new JButton("Submit");

sbmt.setBounds(20, 160, 100, 30);

JButton reset = new JButton("Reset");

reset.setBounds(140, 160, 100, 30);

f.add(firstName);

f.add(lastName);

f.add(dob);

f.add(firstNameTF);

f.add(lastNameTF);

f.add(dobTF);

f.add(sbmt);

f.add(reset);

f.setsize(500 , 500);

f.setlayout(null);

f.setvisible(true);

public class Main {

public static void main(String[] args){

SwingApp obj = new SwingApp();

}
}

EXAMPLES OF AWT COMPONENTS

import java.awt.*;

public class AwtApp extends Frame {

AwtApp(){

Label firstName = new Label("First Name");

firstName.setBounds(20, 50, 80, 20);

Label lastName = new Label("Last Name");

lastName.setBounds(20, 80, 80, 20);

Label dob = new Label("Date of Birth");

dob.setBounds(20, 110, 80, 20);

TextField firstNameTF = new TextField();

firstNameTF.setBounds(120, 50, 100, 20);

TextField lastNameTF = new TextField();

lastNameTF.setBounds(120, 80, 100, 20);

TextField dobTF = new TextField();

dobTF.setBounds(120, 110, 100, 20);

Button sbmt = new Button("Submit");

sbmt.setBounds(20, 160, 100, 30);


Button reset = new Button("Reset");

reset.setBounds(120,160,100,30);

add(firstName);

add(lastName);

add(dob);

add(firstNameTF);

add(lastNameTF);

add(dobTF);

add(sbmt);

add(reset);

setSize(300,300);

setLayout(null);

setVisible(true);

public static void main(String[] args) {

// TODO Auto-generated method stub

AwtApp awt = new AwtApp();

DIFFERENCE BETWEEN SWING AND AWT

HIERARCHY OF SWING

HIERARCHY OF AWT
Write a swing program to that changes the background color whenever user click on the button and
displays the message "Welcome to Java Swing."

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

public class Bgcolor extends JFrame {

private JPanel panel;


private JButton button;
private JLabel label;

public Bgcolor() {
panel = new JPanel();
button = new JButton("Change Color");
label = new JLabel("Welcome to Java Swing", SwingConstants.CENTER);

// Set layout and add components


panel.setLayout(new BorderLayout());
panel.add(button, BorderLayout.SOUTH);
panel.add(label, BorderLayout.CENTER);

// Set initial background color


panel.setBackground(Color.WHITE);

// Add action listener to the button*


button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
changeBackgroundColor();
}
});

// Set up the frame


add(panel);
setTitle("Color Changer");
setSize(400, 300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null); // Center the frame
}

private void changeBackgroundColor() {


Random rand = new Random();
float r = rand.nextFloat();
float g = rand.nextFloat();
float b = rand.nextFloat();

Color randomColor = new Color(r, g, b);


panel.setBackground(randomColor);
}
}
import javax.swing.*;

//TIP To <b>Run</b> code, press <shortcut actionId="Run"/> or


// click the <icon s rc="AllIcons.Actions.Execute"/> icon in the gutter.
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable()( {
@Override
public void run() {
new Bgcolor().setVisible(true);
}
});
}
}

--------------------------------------------------------------------------------------------------------------------------------

Write an applet to print HUMAN FACE

import java.applet.Applet;
import java.awt.*;

public class Face extends Applet {

@Override
public void paint(Graphics g) {
// Draw the face
g.setColor(Color.YELLOW);
g.fillOval(50, 50, 200, 200);

// Draw the eyes


g.setColor(Color.BLACK);
g.fillOval(90, 100, 30, 30);
g.fillOval(180, 100, 30, 30);

// Draw the nose


g.setColor(Color.ORANGE);
int[] xPoints = {150, 130, 170};
int[] yPoints = {130, 180, 180};
g.fillPolygon(xPoints, yPoints, 3);

// Draw the mouth


g.setColor(Color.RED);
g.drawArc(110, 160, 80, 40, 0, -180);
}
}

USING HTML TO EMBBED THE APPLET

<!DOCTYPE html>

<html>

<head>
<title>Human Face Applet</title>

</head>

<body>

<applet code="Face.class" width="300" height="300">

Your browser does not support Java Applets.

</applet>

</body>

</html>

Event and Listener

Changing the state of an object is known as an event. For example, click on button, dragging mouse etc.
The java.awt.event package provides many event classes and Listener interfaces for event handling.

Steps to perform Event Handling

Following steps are required to perform event handling:

1. Register the component with the Listener.

For registering the component with the Listener, many classes provide the registration methods. For
example

Button

public void addActionListener(ActionListener a){}

MenuItem

public void addActionListener(ActionListener a){}

TextField

public void addActionListener(ActionListener a){}

public void addTextListener(TextListener a){}

TextArea

public void addTextListener(TextListener a){}

Checkbox
public void addItemListener(ItemListener a){}

Choice

public void addItemListener(ItemListener a){}

List

public void addActionListener(ActionListener a){}

public void addItemListener(ItemListener a){}

Java Event Handling Code

2. We can put the event handling code into one of the following places:

Within class

Other class

Anonymous class

import java.awt.*;

import java.awt.event.*;

class AEvent extends Frame implements ActionListener{

TextField tf;

AEvent(){

//create components

tf=new TextField();

tf.setBounds(60,50,170,20);

Button b=new Button("click me");

b.setBounds(100,120,80,30);

//register listener

b.addActionListener(this);//passing current instance


//add components and set size, layout and visibility

add(b);add(tf);

setSize(300,300);

setLayout(null);

setVisible(true);

public void actionPerformed(ActionEvent e){

tf.setText("Welcome");

public static void main(String args[]){

new AEvent();

OUTPUT :

You might also like