Unit II :
Inheritance: Basic concepts - Types of inheritance - Member access rules - Usage of
this and Super key word - Method Overloading - Method overriding - Abstract classes
- Dynamic method dispatch - Usage of final keyword.
Packages: Definition - Access Protection - Importing Packages.
Interfaces: Definition – Implementation – Extending Interfaces.
Exception Handling: try – catch - throw - throws – finally – Built-in exceptions -
Creating own Exception classes.
Java Inheritance: Basic Concepts and Types of Inheritance
Inheritance is one of the fundamental concepts of Object-Oriented Programming
(OOP) in Java. It allows a class to inherit properties and behaviors (fields and
methods) from another class. Inheritance helps achieve reusability and method
overriding.
Basic Concepts of Inheritance in Java
Superclass (Parent Class): The class whose properties and methods are
inherited.
Subclass (Child Class): The class that inherits the properties and methods of
the superclass.
extends keyword: In Java, a subclass uses the extends keyword to inherit from
a superclass.
Key points of inheritance in Java:
A child class can inherit methods and fields from the parent class, but it
cannot inherit constructors.
A subclass can extend only one superclass (Java does not support multiple
inheritance via classes).
A subclass can override methods from the parent class to provide specific
implementations.
Example of Inheritance in Java:
class Animal {
void sound() {
System.out.println("Animals make sounds");
}
}
class Dog extends Animal {
@Override
void sound() {
System.out.println("Dog barks");
}
}
public class Main {
public static void main(String[] args) {
Dog d = new Dog();
d.sound(); // Outputs: Dog barks
}
}
In this example:
Dog is the subclass that inherits the sound() method from the Animal
superclass.
The sound() method is overridden in the Dog class to provide a more specific
implementation.
Types of Inheritance in Java
Java supports several types of inheritance. Here are the main ones:
1. Single Inheritance:
o A class inherits from only one superclass.
o This is the most basic type of inheritance.
Example:
class Animal {
void makeSound() {
System.out.println("Animal sound");
}
}
class Dog extends Animal {
void makeSound() {
System.out.println("Bark");
}
}
2. Multilevel Inheritance:
o In multilevel inheritance, a class inherits from another class, which itself
is a subclass of another class.
o It forms a chain of inheritance.
Example:
class Animal {
void makeSound() {
System.out.println("Animal sound");
}
}
class Dog extends Animal {
void makeSound() {
System.out.println("Bark");
}
}
class Puppy extends Dog {
void makeSound() {
System.out.println("Puppy yelps");
}
}
3. Hierarchical Inheritance:
o In this type, multiple classes inherit from a single parent class.
Example:
class Animal {
void makeSound() {
System.out.println("Animal sound");
}
}
class Dog extends Animal {
void makeSound() {
System.out.println("Bark");
}
}
class Cat extends Animal {
void makeSound() {
System.out.println("Meow");
}
}
4. Multiple Inheritance (Through Interfaces):
o Java does not support multiple inheritance through classes, but it does
support it through interfaces. A class can implement multiple interfaces,
inheriting behavior from multiple sources.
Example:
interface Animal {
void makeSound();
}
interface Pet {
void play();
}
class Dog implements Animal, Pet {
public void makeSound() {
System.out.println("Bark");
}
public void play() {
System.out.println("Dog plays fetch");
}
}
In this example, Dog implements both Animal and Pet interfaces.
5. Hybrid Inheritance:
o This is a combination of more than one type of inheritance (e.g.,
hierarchical and multiple inheritance). Java doesn't allow hybrid
inheritance through classes, but it can be done through interfaces.
Example:
interface Animal {
void makeSound();
}
interface Pet {
void play();
}
class Dog implements Animal, Pet {
public void makeSound() {
System.out.println("Bark");
}
public void play() {
System.out.println("Dog plays fetch");
}
}
class GoldenRetriever extends Dog {
void showAffection() {
System.out.println("Golden Retriever shows affection");
}
}
In this example, GoldenRetriever is a subclass of Dog, and Dog implements
two interfaces, Animal and Pet.
Key Points to Remember:
Single Inheritance: One class inherits from another.
Multilevel Inheritance: Inheritance occurs in a chain (class A → class B →
class C).
Hierarchical Inheritance: Multiple classes inherit from one parent class.
Multiple Inheritance: Supported through interfaces (not through classes).
Hybrid Inheritance: A mix of different types of inheritance (primarily
through interfaces).
Java’s inheritance system helps build modular, reusable, and organized code. It also
allows for method overriding, where a subclass can provide its own implementation
of methods defined in the superclass.
Member Access Rules in Java
In Java, access to class members (fields, methods, constructors) is governed by
access modifiers and certain rules for the this and super keywords.
Access Modifiers in Java:
1. public: The member is accessible from any other class.
2. protected: The member is accessible within the same package or by
subclasses.
3. default (no modifier): The member is accessible only within the same
package.
4. private: The member is accessible only within the class it is defined in.
These access modifiers control the visibility and accessibility of class members.
Usage of this Keyword
The this keyword in Java refers to the current instance of the class. It is commonly
used for the following purposes:
1. Referring to instance variables:
o When local variables (like method parameters) have the same name as
instance variables, this is used to differentiate between the two.
Example:
class Person {
String name;
// Constructor that uses 'this' to distinguish between parameter and field
Person(String name) {
this.name = name; // 'this.name' refers to the instance variable, 'name' is
the parameter
}
void display() {
System.out.println("Name: " + this.name); // Refers to the instance
variable
}
}
2. Invoking current class methods:
o this can be used to call other methods in the current class.
Example:
class Calculator {
void add(int a, int b) {
this.printResult(a + b); // Calling another method in the same class
}
void printResult(int result) {
System.out.println("Result: " + result);
}
}
3. Passing the current object as a parameter:
o this can be passed to another method or constructor, allowing the current
object to be passed as a parameter.
Example:
class Car {
String model;
Car(String model) {
this.model = model;
}
void display(Car car) {
System.out.println("Car model: " + car.model);
}
void showCar() {
this.display(this); // Passing the current object
}
}
4. Calling the constructor of the current class:
o this() can be used to invoke another constructor of the same class.
Example:
class Person {
String name;
int age;
Person(String name) {
this.name = name;
}
Person(String name, int age) {
this(name); // Calls the constructor Person(String name)
this.age = age;
}
}
Usage of super Keyword
The super keyword in Java refers to the parent (super) class and is used in the
following contexts:
1. Accessing superclass methods:
o The super keyword is used to call methods of the parent class. It is
useful when the subclass has overridden the method and you still want to
call the parent class's version of the method.
Example:
class Animal {
void sound() {
System.out.println("Animal makes a sound");
}
}
class Dog extends Animal {
void sound() {
super.sound(); // Calls the parent class method
System.out.println("Dog barks");
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.sound();
}
}
Output:
css
Copy code
Animal makes a sound
Dog barks
2. Accessing superclass constructors:
o super() is used to invoke the constructor of the parent class. If no
constructor is explicitly called in the subclass, the default constructor of
the superclass is invoked automatically (if it exists).
o You can use super() with parameters to call a parameterized constructor
of the superclass.
Example:
class Animal {
Animal(String name) {
System.out.println("Animal's name: " + name);
}
}
class Dog extends Animal {
Dog(String name) {
super(name); // Calls the constructor of the superclass
System.out.println("Dog's name: " + name);
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog("Buddy");
}
}
Output:
rust
Copy code
Animal's name: Buddy
Dog's name: Buddy
3. Accessing superclass instance variables:
o If a subclass has a field with the same name as a field in the parent class,
you can use super to refer to the field of the parent class.
Example:
java
Copy code
class Animal {
String color = "White";
}
class Dog extends Animal {
String color = "Black";
void display() {
System.out.println("Dog's color: " + color); // Refers to Dog's color
System.out.println("Animal's color: " + super.color); // Refers to
Animal's color
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.display();
}
}
Output:
mathematica
Copy code
Dog's color: Black
Animal's color: White
Note:
this Keyword:
o Refers to the current instance of the class.
o Used to differentiate between instance variables and local variables with
the same name.
o Can be used to call other methods in the current class or pass the current
object to other methods.
o Used to invoke another constructor of the same class using this().
super Keyword:
o Refers to the parent class and is used to access parent class methods,
constructors, and instance variables.
o It allows a subclass to invoke a method or constructor from the
superclass, even if it has been overridden in the subclass.
Both this and super are crucial for working with inheritance and for managing and
differentiating the members of the parent and child classes.
Method Overloading in Java
Method Overloading is a feature in Java where a class can have more than one
method with the same name, but the methods differ in the number or type of their
parameters. Method overloading helps increase the readability of the program and
allows performing similar tasks using the same method name.
Key Points about Method Overloading:
The methods must have the same name.
The methods must differ in their parameter list (number or type of parameters).
The return type can be different, but it alone is not enough to distinguish
overloaded methods.
Method overloading is resolved at compile time (also known as compile-time
polymorphism).
Example of Method Overloading:
class Calculator {
// Overloaded add method with two integer parameters
int add(int a, int b) {
return a + b;
}
// Overloaded add method with three integer parameters
int add(int a, int b, int c) {
return a + b + c;
}
// Overloaded add method with two double parameters
double add(double a, double b) {
return a + b;
}
}
public class Main {
public static void main(String[] args) {
Calculator calc = new Calculator();
// Calls add(int, int)
System.out.println(calc.add(2, 3));
// Calls add(int, int, int)
System.out.println(calc.add(2, 3, 4));
// Calls add(double, double)
System.out.println(calc.add(2.5, 3.5));
}
}
Output:
Copy code
5
9
6.0
In this example:
The add() method is overloaded with different parameter signatures.
The appropriate add() method is called based on the arguments passed.
Method Overriding in Java
Method Overriding occurs when a subclass provides a specific implementation of a
method that is already defined in its superclass. It is an example of runtime
polymorphism (dynamic method dispatch), where the method that gets executed is
determined at runtime based on the object type (not the reference type).
Key Points about Method Overriding:
The method in the subclass must have the same name, return type, and
parameter list as the method in the superclass.
The overriding method can provide a different implementation in the subclass.
The method in the subclass can call the superclass method using super.
Overriding is resolved at runtime.
Example of Method Overriding:
class Animal {
void sound() {
System.out.println("Animal makes a sound");
}
}
class Dog extends Animal {
// Overriding the sound method
@Override
void sound() {
System.out.println("Dog barks");
}
}
class Cat extends Animal {
// Overriding the sound method
@Override
void sound() {
System.out.println("Cat meows");
}
}
public class Main {
public static void main(String[] args) {
Animal a1 = new Dog(); // Polymorphism
a1.sound(); // Outputs: Dog barks
Animal a2 = new Cat(); // Polymorphism
a2.sound(); // Outputs: Cat meows
}
}
Output:
Copy code
Dog barks
Cat meows
In this example:
Both Dog and Cat override the sound() method of the Animal class.
The method that gets executed is determined at runtime (polymorphism).
Key Rules of Method Overriding:
The method signature (name, return type, and parameters) in the subclass
must be identical to the method in the superclass.
The access level of the overridden method must be the same or more
permissive than the method in the superclass (e.g., a private method cannot be
overridden).
The final, static, and abstract methods cannot be overridden.
If a method is marked as abstract in the superclass, the subclass must either
implement it (unless the subclass is abstract).
Abstract Classes in Java
An abstract class is a class that cannot be instantiated on its own and must be
subclassed. It may contain both abstract methods (methods without implementation)
and concrete methods (methods with implementation). Abstract classes are used to
provide a base class with some common functionality that subclasses can share and
extend.
Key Points about Abstract Classes:
An abstract method is a method declared in an abstract class but does not
have a body (i.e., it's not implemented).
A concrete method can be implemented in the abstract class.
An abstract class cannot be instantiated directly.
A subclass of an abstract class must provide implementations for all the
abstract methods, unless the subclass is also abstract.
Example of an Abstract Class:
java
Copy code
abstract class Animal {
abstract void sound(); // Abstract method (no implementation)
void eat() { // Concrete method
System.out.println("This animal eats food");
}
}
class Dog extends Animal {
@Override
void sound() {
System.out.println("Dog barks");
}
}
class Cat extends Animal {
@Override
void sound() {
System.out.println("Cat meows");
}
}
public class Main {
public static void main(String[] args) {
// Animal a = new Animal(); // Error: Cannot instantiate an abstract class
Animal dog = new Dog();
dog.sound(); // Outputs: Dog barks
dog.eat(); // Outputs: This animal eats food
Animal cat = new Cat();
cat.sound(); // Outputs: Cat meows
cat.eat(); // Outputs: This animal eats food
}
}
Output:
Copy code
Dog barks
This animal eats food
Cat meows
This animal eats food
In this example:
The Animal class is abstract and contains both an abstract method sound() and
a concrete method eat().
The Dog and Cat classes override the sound() method and provide their own
implementations.
We cannot create an instance of the Animal class directly, but we can
instantiate Dog or Cat, which are subclasses.
Definition:
1. Method Overloading:
o Methods with the same name but different parameter lists in the same
class.
o The compiler resolves which method to call based on the method
signature at compile time.
2. Method Overriding:
o A subclass provides a specific implementation of a method already
defined in its superclass.
o This enables runtime polymorphism, where the actual method invoked is
determined at runtime.
3. Abstract Classes:
o A class that cannot be instantiated directly and may contain abstract
methods that must be implemented by subclasses.
o Used as a blueprint for other classes to extend and provide concrete
implementations.
These concepts are fundamental for writing modular, reusable, and maintainable
object-oriented programs in Java.
Dynamic Method Dispatch in Java
Dynamic Method Dispatch (also known as runtime polymorphism) is a
mechanism in Java where a call to an overridden method is resolved at runtime rather
than compile-time. This is possible due to method overriding, where a subclass
provides a specific implementation of a method that is already defined in its
superclass.
In dynamic method dispatch, the object type (not the reference type) determines
which method gets called, making it a key feature of polymorphism.
How Dynamic Method Dispatch Works:
1. A method is overridden in the subclass.
2. The reference variable of the superclass points to an object of the subclass.
3. The method that gets called is based on the object type (the actual object, not
the reference type), and it is determined at runtime.
Example of Dynamic Method Dispatch:
class Animal {
void sound() {
System.out.println("Animal makes a sound");
}
}
class Dog extends Animal {
@Override
void sound() {
System.out.println("Dog barks");
}
}
class Cat extends Animal {
@Override
void sound() {
System.out.println("Cat meows");
}
}
public class Main {
public static void main(String[] args) {
Animal animal1 = new Dog(); // Animal reference but Dog object
Animal animal2 = new Cat(); // Animal reference but Cat object
animal1.sound(); // Outputs: Dog barks (determined at runtime)
animal2.sound(); // Outputs: Cat meows (determined at runtime)
}
}
Output:
Copy code
Dog barks
Cat meows
Explanation:
In this example, the reference type is Animal, but the object types are Dog and
Cat.
Even though both animal1 and animal2 are declared as Animal, the actual
method invoked is determined by the object type at runtime.
This is the essence of dynamic method dispatch—the method resolution
happens at runtime based on the actual object, not the reference type.
Usage of the final Keyword in Java
The final keyword in Java is used to define constants, prevent method overriding, and
prevent inheritance. It can be applied to variables, methods, and classes.
1. final with Variables:
A final variable can only be assigned once.
Once a final variable has been assigned a value, it cannot be changed.
Example:
class Circle {
final double PI = 3.14159; // Constant value of PI
double area(double radius) {
return PI * radius * radius; // PI cannot be changed
}
}
public class Main {
public static void main(String[] args) {
Circle circle = new Circle();
System.out.println("Area: " + circle.area(5)); // Area calculation using PI
}
}
Explanation:
The PI variable is declared as final, meaning it cannot be reassigned once it has
been given a value.
It helps ensure that the value of PI remains constant throughout the program.
2. final with Methods:
A final method cannot be overridden by subclasses.
This is used when we want to ensure that the behavior defined in the superclass
method is preserved in all subclasses.
Example:
class Animal {
final void sound() {
System.out.println("Animal makes a sound");
}
}
class Dog extends Animal {
// This will cause a compile-time error because sound() is final
// void sound() {
// System.out.println("Dog barks");
// }
}
public class Main {
public static void main(String[] args) {
Animal animal = new Dog();
animal.sound(); // Outputs: Animal makes a sound
}
}
Explanation:
The sound() method in the Animal class is marked as final, so it cannot be
overridden in the Dog class.
Trying to override the sound() method in the Dog class would result in a
compile-time error.
3. final with Classes:
A final class cannot be subclassed or inherited.
This is useful when you want to prevent further inheritance of a class, ensuring
that the class’s behavior cannot be altered.
Example:
final class Animal {
void sound() {
System.out.println("Animal makes a sound");
}
}
// This will cause a compile-time error because Animal is final
/class Dog extends Animal {
// void sound() {
// System.out.println("Dog barks");
// }
// }
public class Main {
public static void main(String[] args) {
Animal animal = new Animal();
animal.sound(); // Outputs: Animal makes a sound
}
}
Explanation:
The Animal class is marked as final, so it cannot be subclassed.
Trying to create a Dog class that extends Animal would result in a compile-
time error.
Key Points to Remember About final:
Final Variables: A final variable can only be assigned once. After
initialization, it cannot be changed.
Final Methods: A final method cannot be overridden in subclasses.
Final Classes: A final class cannot be subclassed (inherited).
Packages in Java
In Java, a package is a namespace that organizes a set of related classes, interfaces,
and sub-packages. Packages help in managing the complexity of large systems by
grouping related classes together. They provide a mechanism for encapsulation,
preventing naming conflicts, and controlling access to classes and their members.
1. Definition of Packages in Java
A package in Java is a collection of classes, interfaces, and sub-packages that are
grouped together. Packages are used to avoid class name conflicts and to provide
access control.
Built-in Packages: Java provides many built-in packages like java.util, java.io,
java.lang, etc., that contain commonly used classes, interfaces, and functions.
User-defined Packages: Developers can also create their own packages to
organize classes based on their functionalities.
Types of Packages in Java:
1. Built-in Packages:
o These packages are part of the Java standard library (Java API).
Examples include java.util, java.io, and java.lang.
2. User-defined Packages:
o Developers can define their own packages to group related classes. To
create a user-defined package, we use the package keyword.
Example of a Package Declaration:
java
Copy code
package com.myapp.utils; // Package declaration at the start of the class file
public class MathUtils {
public static int add(int a, int b) {
return a + b;
}
}
Here, the MathUtils class is part of the com.myapp.utils package.
2. Access Protection in Packages
Access control in Java is provided using access modifiers. These modifiers control
the visibility of classes, methods, and variables across packages and help in
encapsulating data and ensuring that only intended users can access certain members.
Access Modifiers in Java:
1. public:
o The member is accessible from any other class in any package.
o Classes, methods, or variables marked public are accessible to all other
classes and packages.
2. protected:
o The member is accessible within the same package and by subclasses
(even if they are in different packages).
o Note: protected access only applies to methods and fields, not top-level
classes.
3. default (no modifier):
o The member is package-private, meaning it is accessible only within
the same package. No keyword is used for this access level.
4. private:
o The member is accessible only within the same class.
o It cannot be accessed from outside the class, even by subclasses.
Example of Access Protection:
// In com/myapp/utils/MathUtils.java
package com.myapp.utils;
public class MathUtils {
public int add(int a, int b) {
return a + b; // Accessible anywhere
}
protected int subtract(int a, int b) {
return a - b; // Accessible within the same package or by subclass
}
int multiply(int a, int b) {
return a * b; // Accessible within the same package
}
private int divide(int a, int b) {
return a / b; // Accessible only within the MathUtils class
}
}
In this example:
The add() method is public, so it can be accessed anywhere.
The subtract() method is protected, so it can be accessed within the same
package or by subclasses.
The multiply() method is package-private (no modifier), so it can be accessed
only within the same package.
The divide() method is private, so it can only be accessed within the MathUtils
class.
3. Importing Packages in Java
To use classes from other packages, you need to import them. Java provides two
types of importing mechanisms:
1. Single Class Import:
o You can import a single class from a package using the import
statement.
Example:
import com.myapp.utils.MathUtils; // Importing a specific class from the
package
public class Main {
public static void main(String[] args) {
MathUtils math = new MathUtils();
System.out.println(math.add(5, 3));
}
}
2. Wildcard Import:
o You can import all the classes from a package using the wildcard (*)
symbol.
Example:
import com.myapp.utils.*; // Importing all classes from the com.myapp.utils
package
public class Main {
public static void main(String[] args) {
MathUtils math = new MathUtils();
System.out.println(math.add(5, 3));
}
}
Note: Wildcard imports are less efficient because they import all classes from
the package, even if you are not using all of them.
Interfaces in Java
An interface in Java is a reference type, similar to a class, that is used to specify a set
of abstract methods (methods without body) that a class must implement. It can also
contain constants and default methods (methods with implementations). Interfaces
allow us to achieve abstraction and multiple inheritance in Java.
1. Definition of an Interface
An interface in Java defines a contract for what a class can do, without specifying
how it does it. It only contains method signatures (abstract methods), and the classes
that implement the interface must provide the actual method implementations.
Key Points about Interfaces:
An interface can only declare abstract methods (methods without body).
A class implements an interface by providing concrete implementations for all
its methods.
Interfaces cannot contain instance fields. They can only contain constants
(public, static, final variables).
An interface can extend other interfaces.
Java allows a class to implement multiple interfaces, making it a way to
achieve multiple inheritance.
Syntax for Declaring an Interface:
interface InterfaceName {
// abstract methods (no body)
void method1();
void method2();
// constants
int CONSTANT = 100;
}
2. Implementation of Interfaces
To implement an interface, a class must:
Use the implements keyword.
Provide concrete implementations for all the abstract methods declared in the
interface.
Example of Implementing an Interface:
// Define an interface
interface Animal {
void sound(); // Abstract method
void eat(); // Abstract method
}
// Implement the interface in a class
class Dog implements Animal {
// Providing implementation of sound()
@Override
public void sound() {
System.out.println("Dog barks");
}
// Providing implementation of eat()
@Override
public void eat() {
System.out.println("Dog eats meat");
}
}
class Main {
public static void main(String[] args) {
Animal animal = new Dog(); // Creating an object of the Dog class
animal.sound(); // Outputs: Dog barks
animal.eat(); // Outputs: Dog eats meat
}
}
Explanation:
The Animal interface defines two methods: sound() and eat().
The Dog class implements the Animal interface and provides concrete
implementations for both methods.
In the Main class, we create a Dog object and use it via the Animal reference.
3. Extending Interfaces
An interface in Java can extend another interface, allowing a subclass to inherit
multiple method declarations from more than one interface. This is a way of
achieving multiple inheritance of method signatures, unlike classes, which can only
inherit from one class.
Syntax for Extending an Interface:
interface InterfaceA {
void methodA();
}
interface InterfaceB {
void methodB();
}
// A new interface can extend multiple interfaces
interface CombinedInterface extends InterfaceA, InterfaceB {
void methodC();
}
In this example:
CombinedInterface extends both InterfaceA and InterfaceB, so it inherits all
the methods from both interfaces and can declare additional methods like
methodC().
Example of Implementing an Interface that Extends Other Interfaces:
// Define the first interface
interface Animal {
void sound();
}
// Define the second interface
interface Mammal {
void eat();
}
// Define a third interface that extends Animal and Mammal
interface Dog extends Animal, Mammal {
void sleep();
}
// Implement the Dog interface
class Bulldog implements Dog {
@Override
public void sound() {
System.out.println("Bulldog barks");
}
@Override
public void eat() {
System.out.println("Bulldog eats bones");
}
@Override
public void sleep() {
System.out.println("Bulldog sleeps in the kennel");
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Bulldog();
dog.sound(); // Outputs: Bulldog barks
dog.eat(); // Outputs: Bulldog eats bones
dog.sleep(); // Outputs: Bulldog sleeps in the kennel
}
}
Explanation:
The Dog interface extends both the Animal and Mammal interfaces, inheriting
the methods sound() and eat().
The Bulldog class implements the Dog interface and provides concrete
implementations for all methods.
The Bulldog class is now forced to implement the methods from both Animal
and Mammal, as well as the additional method sleep() declared in the Dog
interface.
Exception Handling in Java
Exception Handling in Java is a powerful mechanism that allows programs to
handle runtime errors, maintaining the normal flow of application execution. It helps
in managing unexpected conditions that may occur during program execution, such
as input/output errors, network failures, or incorrect data processing.
In Java, exceptions are objects that represent an error or an exceptional condition
during the execution of a program. Exception handling in Java is accomplished using
the try, catch, throw, throws, and finally keywords.
1. Keywords in Exception Handling
try-catch Block:
The try block contains code that might throw an exception.
The catch block catches the exception and handles it. It specifies the type of
exception it will handle.
If an exception occurs in the try block, the control is transferred to the
appropriate catch block.
Syntax:
try {
// Code that may throw an exception
} catch (ExceptionType e) {
// Handling the exception
}
Example of try-catch:
public class Main {
public static void main(String[] args) {
try {
int[] arr = new int[5];
arr[10] = 50; // This will throw an ArrayIndexOutOfBoundsException
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Exception caught: " + e);
}
}
}
Output:
Exception caught: java.lang.ArrayIndexOutOfBoundsException: Index 10 out of
bounds for length 5
In this example:
The code inside the try block throws an ArrayIndexOutOfBoundsException
because we are trying to access an invalid index of the array.
The catch block catches the exception and prints a message with the exception
details.
throw:
The throw keyword is used to explicitly throw an exception from a method or
block of code.
It is followed by an instance of an exception class.
Syntax:
java
Copy code
throw new ExceptionType("Error message");
Example of throw:
public class Main {
public static void main(String[] args) {
try {
throw new ArithmeticException("Custom Arithmetic Exception");
} catch (ArithmeticException e) {
System.out.println("Exception caught: " + e.getMessage());
}
}
}
Output:
Exception caught: Custom Arithmetic Exception
In this example:
We use throw to explicitly throw an ArithmeticException with a custom error
message.
The catch block handles this exception.
throws:
The throws keyword is used in a method declaration to specify that the method
might throw certain exceptions.
It is used when a method calls other methods that may throw exceptions and
does not handle them internally.
Syntax:
public void method() throws ExceptionType {
// Code that might throw an exception
}
Example of throws:
public class Main {
public static void main(String[] args) {
try {
testMethod(); // Calling method that throws an exception
} catch (IOException e) {
System.out.println("Exception caught: " + e.getMessage());
}
}
// Method that throws an exception
public static void testMethod() throws IOException {
throw new IOException("Custom I/O Exception");
}
}
Output:
mathematica
Copy code
Exception caught: Custom I/O Exception
In this example:
The testMethod() declares that it throws an IOException.
In the main method, we handle this exception using a try-catch block.
finally:
The finally block is used to execute code that must always run, regardless of
whether an exception was thrown or not.
It is typically used to close resources like files, network connections, or
database connections.
Syntax:
try {
// Code that may throw an exception
} catch (ExceptionType e) {
// Handling the exception
} finally {
// Code that will always execute
}
Example of finally:
public class Main {
public static void main(String[] args) {
try {
int result = 10 / 0; // This will throw ArithmeticException
} catch (ArithmeticException e) {
System.out.println("Exception caught: " + e.getMessage());
} finally {
System.out.println("This will always execute");
}
}
}
Output:
Exception caught: / by zero
This will always execute
In this example:
The try block throws an ArithmeticException.
The catch block handles the exception.
The finally block always executes, regardless of whether an exception occurred
or not.
2. Built-in Exceptions in Java
Java provides a rich set of built-in exceptions to handle various types of errors. These
exceptions are subclasses of the Throwable class, which has two main categories:
Error: Represents severe errors (e.g., OutOfMemoryError).
Exception: Represents conditions that a program can catch and handle (e.g.,
IOException, SQLException, NullPointerException).
Some common built-in exceptions include:
1. ArithmeticException: Thrown when an exceptional arithmetic condition
occurs, like division by zero.
2. ArrayIndexOutOfBoundsException: Thrown when trying to access an
invalid index of an array.
3. NullPointerException: Thrown when trying to use a reference that points to
null.
4. IOException: Thrown when there is an issue with input/output operations.
5. FileNotFoundException: Thrown when a file is not found during I/O
operations.
6. ClassNotFoundException: Thrown when a class is not found during runtime.
Example of Built-in Exception:
public class Main {
public static void main(String[] args) {
try {
int[] arr = new int[3];
arr[5] = 10; // This will throw ArrayIndexOutOfBoundsException
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Array index out of bounds: " + e.getMessage());
}
}
}
3. Creating Custom Exception Classes
Java allows you to create your own exceptions by extending the Exception class or
any of its subclasses.
Steps to Create a Custom Exception:
1. Create a new class that extends the Exception class (or any of its subclasses).
2. Provide constructors to initialize the exception, such as a default constructor
and one that accepts a message.
3. You can add custom behavior if necessary, such as logging or specific error
messages.
Example of Custom Exception:
// Custom exception class
class InvalidAgeException extends Exception {
public InvalidAgeException(String message) {
super(message);
}
}
// Main class to use the custom exception
public class Main {
public static void main(String[] args) {
try {
validateAge(15); // This will throw InvalidAgeException
} catch (InvalidAgeException e) {
System.out.println("Exception caught: " + e.getMessage());
}
}
public static void validateAge(int age) throws InvalidAgeException {
if (age < 18) {
throw new InvalidAgeException("Age must be 18 or above.");
} else {
System.out.println("Age is valid");
}
}
}
Output:
Exception caught: Age must be 18 or above.
In this example:
We create a custom exception InvalidAgeException that extends the Exception
class.
The validateAge() method throws this exception if the age is less than 18.
In the main method, we catch and handle the custom exception.
Note:
1. try-catch Block:
o Used to catch and handle exceptions. The code that may throw an
exception is placed inside the try block, and the exception is caught and
handled inside the catch block.
2. throw:
o Used to explicitly throw an exception.
3. throws:
o Used in method declarations to specify that the method may throw
exceptions, passing the responsibility of handling the exception to the
calling method.
4. finally:
o Code in the finally block always executes, regardless of whether an
exception is thrown or not. It is typically used to clean up resources.
5. Built-in Exceptions:
o Java provides many built-in exceptions (e.g., ArithmeticException,
IOException, ArrayIndexOutOfBoundsException), which can be caught
and handled.
6. Creating Custom Exceptions:
o You can create your own exceptions by extending the Exception class or
its subclasses. Custom exceptions are useful for handling specific error
conditions in your application.
Exception handling is an essential part of robust and reliable Java applications,
allowing developers to manage unexpected conditions gracefully and improve user
experience.
UNIT III Multithreaded Programming: Thread Class-Runnable interface–Synchronization–
Using synchronized methods– Using synchronized statement – Inter thread
Communication–Deadlock.
I/O Streams: Concepts of streams-Stream classes-Byte and Character stream -
Reading console Input and Writing Console output – File Handling.
1
2
Multithreading in Java is a process of executing multiple threads simultaneously.
A thread is a lightweight sub-process, the smallest unit of processing. Multiprocessing and multithreading,
both are used to achieve multitasking
Multitasking
Multitasking is a process of executing multiple tasks simultaneously. We use multitasking to utilize the
CPU. Multitasking can be achieved in two ways:
o Process-based Multitasking (Multiprocessing)
o Thread-based Multitasking (Multithreading)
1) Process-based Multitasking (Multiprocessing)
o Each process has an address in memory. In other words, each process allocates a separate memory
area.
o A process is heavyweight.
o Cost of communication between the process is high.
o Switching from one process to another requires some time for saving and loading registers, memory
maps, updating lists, etc.
2) Thread-based Multitasking (Multithreading)
o Threads share the same address space.
o A thread is lightweight.
o Cost of communication between the thread is low.
Note: At least one process is required for each thread.
What is Thread in Java?
A thread is a lightweight subprocess, the smallest unit of processing. It is a separate path of execution.
Threads are independent. If there occurs exception in one thread, it doesn't affect other threads. It uses a
shared memory area.
Java Thread class
Java provides Thread class to achieve thread programming. Thread class provides constructors and
methods to create and perform operations on a thread. Thread class extends Object class and implements
Runnable interface.
Thread States:
o New: A thread that has been created but not yet started.
o Runnable: A thread that is ready to run and waiting for CPU time.
o Blocked: A thread that is blocked waiting for a monitor lock.
o Waiting: A thread that is waiting indefinitely for another thread to perform a particular action.
o Timed Waiting: A thread that is waiting for another thread to perform an action for up to a
specified waiting time.
o Terminated: A thread that has completed its task.
Life cycle of a Thread (Thread States)
In Java, a thread always exists in any one of the following states. These states are:
1. New
2. Active
o Runnable
o Running
3. Blocked / Waiting(Non-runnable state)
4. Timed Waiting
5. Terminated (Dead)
3
Explanation of Different Thread States
New: Whenever a new thread is created, it is always in the new state. For a thread in the new state, the code
has not been run yet and thus has not begun its execution.
Active: When a thread invokes the start() method, it moves from the new state to the active state. The
active state contains two states within it: one is runnable, and the other is running.
o Runnable: A thread, that is ready to run is then moved to the runnable state. In the runnable state,
the thread may be running or may be ready to run at any given instant of time.
o Running: When the thread gets the CPU, it moves from the runnable to the running state.
Generally, the most common change in the state of a thread is from runnable to running and again
back to runnable.
Blocked or Waiting: Whenever a thread is inactive for a span of time then, either the thread is in the
blocked state or is in the waiting state
Timed Waiting: Sometimes, waiting for leads to starvation. For example, a thread (its name is A) has
entered the critical section of a code and is not willing to leave that critical section. A real example of timed
waiting is when we invoke the sleep() method on a specific thread. The sleep() method puts the thread in
the timed wait state.
Terminated: A thread reaches the termination state because of the following reasons:
o When a thread has finished its job, then it exists or terminates normally.
o Abnormal termination: It occurs when some unusual events such as an unhandled exception or
segmentation fault.
A terminated thread means the thread is no more in the system.
The following diagram shows the different states involved in the life cycle of a thread.
Thread States in Java
A thread is a path of execution in a program that enters any one of the following five states during its life
cycle. The five states are as follows:
1. New State:
When we create a thread object using the Thread class, the thread is born and enters the New state. This
means the thread is created, but the start() method has not yet been called on the instance.
2. Runnable State:
Runnable state means a thread is ready for execution of any statement. When the start() method is called on
a new thread, thread enters into from New to a Runnable state.
3. Running State:
4
Running means Processor (CPU) has allocated time slot to thread for its execution. When thread scheduler
selects a thread from the runnable state for execution, it goes into running state. Look at the above figure.
his code is an example of thread’s state transitions. When start() method is called, the thread enters the
Runnable state. Once the CPU schedules it, the thread transitions to the Running state, executing the run()
method.
A running thread may give up its control in any one of the following situations and can enter into the
blocked state.
a) When sleep() method is invoked on a thread to sleep for specified time period, the thread is out of queue
during this time period. The thread again reenters into the runnable state as soon as this time period is
elapsed.
b) When a thread is suspended using suspend() method for some time in order to satisfy some conditions. A
suspended thread can be revived by using resume() method.
c) When wait() method is called on a thread to wait for some time. The thread in wait state can be run again
using notify() or notifyAll() method.
4. Blocked State:
A thread is considered to be in the blocked state when it is suspended, sleeping, or waiting for some time in
order to satisfy some condition.
For example, a thread enters the Blocked state when it is waiting to acquire a lock or a monitor that is held
by another thread. This generally happens when multiple threads are trying to access a synchronized block
or method.
Java Multithreading - The Thread Model
1. Introduction to Multithreading
Multithreading allows multiple tasks to execute simultaneously within the same program.
Java’s runtime system depends on threads for many operations, making Java a multithreaded
language.
It eliminates inefficiencies like polling and blocking by using an asynchronous execution model.
2. Single-Threaded vs. Multi-Threaded Execution
🔹 Single-threaded Execution (Event Loop with Polling)
Traditional single-threaded systems rely on event loops to check for pending tasks.
If a task is waiting (blocked) (e.g., for user input), the entire program stops.
Wastes CPU time and can cause delays in execution.
🔹 Multi-threaded Execution (Java Approach)
Java allows multiple threads to execute concurrently.
A thread can pause (block) without stopping other parts of the program.
For example, while one thread waits for user input, another thread can continue running.
3. The Java Thread Model
🔹 Key Features of Java’s Multithreading Model
Preemptive multitasking: A higher-priority thread can preempt a lower-priority thread.
Time-slicing (Round-robin scheduling): Threads of equal priority are given CPU time in cycles.
Context switching: When a thread yields or blocks, another thread gets CPU time.
🔹 Thread Lifecycle
A thread in Java exists in different states:
5
State Description
New Thread is created but not started (Thread t = new Thread();)
Runnable Thread is ready to run but waiting for CPU time (start())
Running Thread is currently executing
Blocked Thread is waiting for a resource (e.g., file I/O, synchronized block)
Waiting Thread is indefinitely waiting (wait())
Timed Waiting Thread waits for a specific time (sleep(1000))
Terminated Thread has completed execution
Method Description
start() Starts a new thread and calls run()
run() Defines the code executed by the thread
sleep(ms) Makes the thread sleep for ms milliseconds
join() Waits for the thread to complete
interrupt() Interrupts the thread execution
setPriority(int) Sets thread priority (1 to 10)
getName() Returns the thread name
setName(String) Sets a custom name for the thread
isAlive() Checks if the thread is still running
4. Creating a Thread in Java
🔹 Using the Thread Class
class MyThread extends Thread {
public void run() {
System.out.println("Thread is running...");
}
public static void main(String[] args) {
MyThread t1 = new MyThread();
t1.start(); // Start the thread
} }
📌 Key Methods of Thread Class
🔹 Using the Runnable Interface
class MyRunnable implements Runnable {
public void run() {
System.out.println("Thread is running...");
}
public static void main(String[] args) {
Thread t1 = new Thread(new MyRunnable());
t1.start();
}
6
}
5. Synchronization in Java
🔹 Why Synchronization?
Prevents race conditions when multiple threads access shared resources.
Ensures only one thread modifies a critical section at a time.
🔹 Using Synchronized Methods
class SharedResource {
synchronized void printNumbers(int n) {
for (int i = 1; i <= 5; i++) {
System.out.println(n * i);
try {
Thread.sleep(500);
} catch (Exception e) {
System.out.println(e);
}
}
}
}
class MyThread extends Thread {
SharedResource obj;
MyThread(SharedResource obj) {
this.obj = obj;
}
public void run() {
obj.printNumbers(5);
}
}
public class SyncExample {
public static void main(String[] args) {
SharedResource obj = new SharedResource();
MyThread t1 = new MyThread(obj);
MyThread t2 = new MyThread(obj);
t1.start();
t2.start();
}
}
📌 Key Point: synchronized ensures only one thread accesses printNumbers() at a time.
🔹 Using Synchronized Blocks
Instead of locking an entire method, lock only a specific block of code.
class Shared {
void printNumbers(int n) {
synchronized (this) { // Locking only this block
7
for (int i = 1; i <= 5; i++) {
System.out.println(n * i);
try { Thread.sleep(500); } catch (Exception e) {}
}
}
}
}
📌 Synchronized blocks improve efficiency by reducing the locked code region.
6. Inter-Thread Communication
🔹 Using wait(), notify(), and notifyAll()
wait(): Makes a thread pause execution until another thread notifies it.
notify(): Wakes up one waiting thread.
notifyAll(): Wakes up all waiting threads.
🔹 Example
class SharedResource {
synchronized void produce() {
System.out.println("Producing...");
try {
wait(); // Thread waits
} catch (Exception e) {}
System.out.println("Resumed...");
}
synchronized void consume() {
System.out.println("Consuming...");
notify(); // Notify waiting thread
}
}
public class ThreadCommExample {
public static void main(String[] args) {
SharedResource obj = new SharedResource();
new Thread(() -> obj.produce()).start();
try { Thread.sleep(1000); } catch (Exception e) {}
new Thread(() -> obj.consume()).start();
}
}
📌 Key Point: wait() and notify() help coordinate communication between threads.
7. Deadlock in Java
🔹 What is a Deadlock?
Occurs when two or more threads wait indefinitely for each other to release a lock.
🔹 Example of Deadlock
class DeadlockExample {
8
static final Object lock1 = new Object();
static final Object lock2 = new Object();
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
synchronized (lock1) {
System.out.println("Thread 1: Holding lock 1...");
try { Thread.sleep(100); } catch (Exception e) {}
synchronized (lock2) {
System.out.println("Thread 1: Holding lock 2...");
}
}
});
Thread t2 = new Thread(() -> {
synchronized (lock2) {
System.out.println("Thread 2: Holding lock 2...");
try { Thread.sleep(100); } catch (Exception e) {}
synchronized (lock1) {
System.out.println("Thread 2: Holding lock 1...");
}
}
});
t1.start();
t2.start();
}
}
Creating Threads in Java (Simplified Explanation)
Java provides two ways to create a thread:
1️⃣ By implementing the Runnable interface
2️⃣ By extending the Thread class
1. Implementing Runnable Interface (Recommended Way)
In this approach:
✔️We create a class that implements the Runnable interface.
✔️We define the run() method, which contains the code that will execute in a separate thread.
✔️We create a Thread object and pass our Runnable object to it.
✔️We call the start() method to begin execution.
Example:
class MyRunnable implements Runnable {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println("Thread is running: " + i);
try {
Thread.sleep(500); // Sleep for 500 milliseconds
9
} catch (InterruptedException e) {
System.out.println(e);
}
}
}
}
public class RunnableExample {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable(); // Create Runnable object
Thread thread = new Thread(myRunnable); // Create Thread object
thread.start(); // Start the thread
}
}
✔️Output: This will print numbers 1 to 5 in a separate thread, pausing for 500ms between each.
2. Extending the Thread Class
In this approach:
✔️We create a class that extends the Thread class.
✔️We override the run() method.
✔️We create an instance of our class and call start() to begin execution.
Example:
class MyThread extends Thread {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println("Thread is running: " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
System.out.println(e);
}
}
}
}
public class ThreadExample {
public static void main(String[] args) {
MyThread myThread = new MyThread(); // Create Thread object
myThread.start(); // Start the thread
}
}
✔️Output: Similar to the Runnable example.
Which Method is Better?
✅ Implementing Runnable is preferred because:
Java allows only one class to extend another (so extending Thread limits flexibility).
10
It keeps your design cleaner by separating the "task" (Runnable) from the "execution" (Thread).
Key Thread Methods
start() → Starts the thread, calling the run() method.
run() → Contains the code that executes in the thread.
sleep(ms) → Makes the thread pause for a given time (in milliseconds).
join() → Makes the current thread wait until another thread completes.
isAlive() → Checks if the thread is still running.
1️⃣ Thread Priorities
Threads in Java have priorities that help the thread scheduler decide which thread to run first.
📌 Priority Levels:
Thread.MIN_PRIORITY = 1
Thread.NORM_PRIORITY = 5 (Default)
Thread.MAX_PRIORITY = 10
✅ Setting Thread Priority:
Thread t1 = new Thread();
t1.setPriority(Thread.MAX_PRIORITY);
🔍 Note:
Higher priority doesn't guarantee more CPU time.
Different operating systems handle priorities differently.
2️⃣ Thread Synchronization
When multiple threads share a resource, synchronization ensures only one thread accesses it at a time to
avoid errors.
📌 Using synchronized Method:
class SharedResource {
synchronized void printMessage(String msg) {
System.out.print("[" + msg);
try { Thread.sleep(1000); } catch (InterruptedException e) {}
System.out.println("]");
}
}
🔍 Key Points:
synchronized ensures only one thread can execute the method at a time.
Other threads must wait until the current thread completes execution.
3️⃣ Inter-thread Communication (wait(), notify())
Instead of polling, Java provides wait(), notify(), and notifyAll() to let threads communicate.
📌 Example:
class SharedData {
int value;
boolean available = false;
synchronized void produce(int num) {
while (available) try { wait(); } catch (InterruptedException e) {}
value = num;
11
available = true;
notify();
}
synchronized int consume() {
while (!available) try { wait(); } catch (InterruptedException e) {}
available = false;
notify();
return value;
}
}
🔍 Key Points:
wait() → Makes a thread pause and release the lock.
notify() → Wakes one waiting thread.
notifyAll() → Wakes all waiting threads.
4️⃣ Deadlock (Thread Blocking Issue)
Deadlock occurs when two or more threads wait for each other indefinitely.
📌 Example:
class Resource {
synchronized void methodA(Resource r) {
r.methodB(this); // Thread waiting on another thread
}
synchronized void methodB(Resource r) {
r.methodA(this); // Circular dependency (Deadlock!)
}
}
🔍 Solution:
Avoid nested locks.
Use tryLock() from ReentrantLock.
5️⃣ Suspending & Resuming Threads
Old methods (suspend(), resume(), stop()) are deprecated due to safety issues. Instead, use:
✅ Modern Approach:
class MyThread extends Thread {
private volatile boolean running = true;
public void run() {
while (running) {
System.out.println("Thread is running...");
try { Thread.sleep(1000); } catch (InterruptedException e) {}
}
}
public void stopThread() {
running = false; // Graceful stopping
}}
12
🔍 Key Points:
Use volatile boolean flag to control execution.
Avoid stop() as it may leave shared resources in an inconsistent state.
💡 Summary:
Use priorities (setPriority()) but don’t rely on them.
Use synchronization (synchronized) to avoid data inconsistency.
Use wait() & notify() for better thread communication.
Avoid deadlocks by managing resource locks properly.
Use modern thread control (volatile flag) instead of old methods.
Example: Creating Threads in Java
1. Using Thread Class
class MyThread extends Thread {
public void run() {
System.out.println("Thread Running: " + Thread.currentThread().getName());
} }
public class ThreadExample {
public static void main(String[] args) {
MyThread t1 = new MyThread();
t1.start(); // Start the thread
} }
2. Using Runnable Interface
class MyRunnable implements Runnable {
public void run() {
System.out.println("Thread Running: " + Thread.currentThread().getName());
}
}
public class RunnableExample {
public static void main(String[] args) {
Thread t1 = new Thread(new MyRunnable());
t1.start();
} }
Thread Class
Java provides two primary ways to create a thread:
1. Extending the Thread class
2. Implementing the Runnable interface (preferred for better code reusability)
Method 1: Extending the Thread Class
You can create a thread by subclassing Thread and overriding the run() method.
Example: Creating a Thread using Thread Class
class MyThread extends Thread {
public void run() {
System.out.println("Thread running: " + Thread.currentThread().getName());
}
}
public class ThreadExample {
public static void main(String[] args) {
13
MyThread t1 = new MyThread(); // Creating a thread object
t1.start(); // Starting the thread
}
}
Method 2: Implementing Runnable Interface (Preferred)
Instead of extending Thread, implementing Runnable is a better approach because Java does not support
multiple inheritance.
class MyRunnable implements Runnable {
public void run() {
System.out.println("Thread running: " + Thread.currentThread().getName());
}
}
public class RunnableExample {
public static void main(String[] args) {
Thread t1 = new Thread(new MyRunnable()); // Creating a thread object
t1.start(); // Starting the thread
}
}
2. Important Methods of the Thread Class
3. Thread Lifecycle (States)
A thread can be in one of the following states:
1. New – Thread is created but not started.
2. Runnable – start() has been called, and it is ready to run.
3. Running – The thread is currently executing.
4. Blocked/Waiting – The thread is waiting due to synchronization or sleep().
5. Terminated – The thread has completed execution.
4. Example: Thread Sleep and Join
class MyThread extends Thread {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println(Thread.currentThread().getName() + " - " + i);
try {
Thread.sleep(500); // Sleep for 500ms
} catch (InterruptedException e) {
System.out.println("Thread interrupted");
}
}
}
}
public class ThreadMethodsExample {
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
14
t1.start();
try {
t1.join(); // Main thread waits for t1 to finish
} catch (InterruptedException e) {
System.out.println("Interrupted");
}
t2.start();
}
}
Output
Thread-0 - 1
Thread-0 - 2
Thread-0 - 3
Thread-0 - 4
Thread-0 - 5
Thread-1 - 1
Thread-1 - 2
Thread-1 - 3
Thread-1 - 4
Thread-1 - 5
Here, join() ensures that t2 starts only after t1 completes execution.
5. Example: Thread Priority
Java allows setting priorities to threads using setPriority(). However, thread scheduling is dependent on the
JVM and OS.
class PriorityThread extends Thread {
public void run() {
System.out.println(Thread.currentThread().getName() + " - Priority: " +
Thread.currentThread().getPriority());
}
}
public class ThreadPriorityExample {
public static void main(String[] args) {
PriorityThread t1 = new PriorityThread();
PriorityThread t2 = new PriorityThread();
t1.setPriority(Thread.MIN_PRIORITY); // Priority 1
t2.setPriority(Thread.MAX_PRIORITY); // Priority 10
t1.start();
t2.start();
}
}
Output
Thread-0 - Priority: 1
15
Thread-1 - Priority: 10
(Note: The execution order is not guaranteed.)
6. Daemon Threads
A daemon thread is a background thread that automatically terminates when all user threads finish
execution.
class DaemonExample extends Thread {
public void run() {
while (true) {
System.out.println("Daemon thread running...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("Interrupted");
}
}
}
}
public class DaemonThreadExample {
public static void main(String[] args) {
DaemonExample daemon = new DaemonExample();
daemon.setDaemon(true); // Set the thread as a daemon thread
daemon.start();
System.out.println("Main thread sleeping...");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
System.out.println("Main thread interrupted");
}
System.out.println("Main thread finished execution.");
}
}
Output
Main thread sleeping...
Daemon thread running...
Daemon thread running...
Daemon thread running...
Main thread finished execution.
The daemon thread stops automatically when the main thread exits.
7. Summary
The Thread class provides methods to create and manage threads in Java.
The start() method initiates a new thread, while run() contains the thread’s logic.
The sleep(), join(), and yield() methods control thread execution.
The synchronized keyword ensures thread-safe execution.
Thread priority can be set but is OS-dependent.
16
Daemon threads run in the background and terminate when all user threads finish.
Runnable Interface
1. Why Use Runnable Interface?
Java provides two ways to create a thread:
1. Extending the Thread class
2. Implementing the Runnable interface (Preferred)
Using Runnable is better because:
✔ Java does not support multiple inheritance, so extending Thread limits class flexibility.
✔ It promotes better object-oriented design by separating thread logic from class hierarchy.
2. Implementing the Runnable Interface
The Runnable interface has only one method:
public interface Runnable {
void run(); // Must be implemented by any Runnable class
}
When a class implements Runnable, it must override run() and then pass an instance of the class to a
Thread object.
3. Example: Implementing Runnable
class MyRunnable implements Runnable {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println(Thread.currentThread().getName() + " - " + i);
try {
Thread.sleep(500); // Sleep for 500ms
} catch (InterruptedException e) {
System.out.println("Thread interrupted");
}
}
}
}
public class RunnableExample {
public static void main(String[] args) {
MyRunnable obj = new MyRunnable(); // Create a Runnable instance
Thread t1 = new Thread(obj); // Pass the instance to a Thread object
Thread t2 = new Thread(obj);
t1.start(); // Start thread 1
t2.start(); // Start thread 2
}
}
Output (Threads run independently)
Thread-0 - 1
Thread-1 - 1
17
Thread-0 - 2
Thread-1 - 2
...
4. Thread Synchronization Using Runnable
When multiple threads share a common resource, synchronization is necessary to avoid race conditions.
class Counter implements Runnable {
private int count = 0;
public synchronized void run() { // Synchronizing run method
for (int i = 0; i < 5; i++) {
count++;
System.out.println(Thread.currentThread().getName() + " - Count: " + count);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
System.out.println("Interrupted");
}
}
}
}
public class SynchronizedRunnable {
public static void main(String[] args) {
Counter counter = new Counter();
Thread t1 = new Thread(counter);
Thread t2 = new Thread(counter);
t1.start();
t2.start();
}
}
Output (Avoids race conditions)
Thread-0 - Count: 1
Thread-0 - Count: 2
Thread-1 - Count: 3
Thread-1 - Count: 4
...
5. Using Runnable with Lambda Expressions (Java 8+)
Java 8 introduced lambda expressions, allowing a cleaner way to define a Runnable:
public class LambdaRunnable {
public static void main(String[] args) {
Runnable task = () -> {
for (int i = 1; i <= 5; i++) {
System.out.println(Thread.currentThread().getName() + " - " + i);
}
18
};
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
}
}
6. Advantages of Using Runnable
✅ Better Object-Oriented Design - Separates thread logic from class inheritance.
✅ Multiple Inheritance - A class can extend another class while implementing Runnable.
✅ Reusability - The same Runnable instance can be used with multiple threads.
Synchronization in Java
1. Why Synchronization?
When multiple threads access a shared resource (e.g., a variable or an object), data inconsistency can
occur. Synchronization ensures that only one thread accesses the critical section of the code at a time.
2. Types of Synchronization in Java
1. Synchronized Methods
2. Synchronized Blocks
3. Static Synchronization
4. Using ReentrantLock (Java 5+)
3. Synchronized Methods
A synchronized method ensures that only one thread can execute it at a time.
Example: Synchronizing a Counter
class Counter {
private int count = 0;
// Synchronized method
public synchronized void increment() {
count++;
System.out.println(Thread.currentThread().getName() + " - Count: " + count);
}
}
class MyThread extends Thread {
Counter counter;
public MyThread(Counter counter) {
this.counter = counter;
}
public void run() {
for (int i = 0; i < 5; i++) {
counter.increment();
19
try {
Thread.sleep(100);
} catch (InterruptedException e) {
System.out.println("Interrupted");
}
}
}
}
public class SyncExample {
public static void main(String[] args) {
Counter counter = new Counter();
Thread t1 = new MyThread(counter);
Thread t2 = new MyThread(counter);
t1.start();
t2.start();
}
}
Output (Ensures proper count updates)
Thread-0 - Count: 1
Thread-1 - Count: 2
Thread-0 - Count: 3
Thread-1 - Count: 4
...
4. Synchronized Blocks
Instead of synchronizing the entire method, we can synchronize only the critical section of the code.
Example: Synchronizing a Block of Code
class Counter {
private int count = 0;
public void increment() {
synchronized (this) { // Synchronized block
count++;
System.out.println(Thread.currentThread().getName() + " - Count: " + count);
}
}
}
Why Use Synchronized Blocks?
✔ Reduces the performance overhead of synchronizing the entire method.
✔ Only locks the required section instead of the whole method.
5. Static Synchronization
If a method is static, synchronization applies to the class level, not the instance level. This means only one
thread can access a static synchronized method across all instances.
20
Example: Synchronizing a Static Method
class SharedResource {
private static int count = 0;
public static synchronized void increment() { // Static synchronized method
count++;
System.out.println(Thread.currentThread().getName() + " - Count: " + count);
}
}
class MyThread extends Thread {
public void run() {
SharedResource.increment();
}
}
public class StaticSyncExample {
public static void main(String[] args) {
Thread t1 = new MyThread();
Thread t2 = new MyThread();
t1.start();
t2.start();
}
}
Static synchronization is needed when:
✔ A shared resource is static (belongs to the class, not instances).
✔ We need to synchronize across all objects of the class.
Synchronized Methods
1. Why Use Synchronized Methods?
When multiple threads access a shared resource, there is a chance of data inconsistency. A synchronized
method ensures that only one thread can execute the method at a time.
2. Syntax of a Synchronized Method
synchronized returnType methodName(parameters) {
// Critical section - only one thread can access at a time
}
3. Example: Using a Synchronized Method
Problem Without Synchronization
Without synchronization, multiple threads can modify a shared resource simultaneously, leading to
incorrect results.
class Counter {
private int count = 0;
21
public void increment() { // Not synchronized
count++;
System.out.println(Thread.currentThread().getName() + " - Count: " + count);
}
}
class MyThread extends Thread {
Counter counter;
public MyThread(Counter counter) {
this.counter = counter;
}
public void run() {
for (int i = 0; i < 5; i++) {
counter.increment();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
System.out.println("Interrupted");
}
}
}
}
public class WithoutSynchronization {
public static void main(String[] args) {
Counter counter = new Counter();
Thread t1 = new MyThread(counter);
Thread t2 = new MyThread(counter);
t1.start();
t2.start();
}
}
Output (Data inconsistency)
Thread-0 - Count: 1
Thread-1 - Count: 2
Thread-0 - Count: 3
Thread-1 - Count: 3 <-- Wrong count!
...
Here, multiple threads modify the count variable simultaneously, causing inconsistent results.
4. Solving the Problem with Synchronized Methods
By making increment() synchronized, we ensure that only one thread can modify the shared variable at a
time.
class Counter {
22
private int count = 0;
// Synchronized method
public synchronized void increment() {
count++;
System.out.println(Thread.currentThread().getName() + " - Count: " + count);
}
}
class MyThread extends Thread {
Counter counter;
public MyThread(Counter counter) {
this.counter = counter;
}
public void run() {
for (int i = 0; i < 5; i++) {
counter.increment();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
System.out.println("Interrupted");
}
}
}
}
public class WithSynchronization {
public static void main(String[] args) {
Counter counter = new Counter();
Thread t1 = new MyThread(counter);
Thread t2 = new MyThread(counter);
t1.start();
t2.start();
}
}
Output (Correct Count)
Thread-0 - Count: 1
Thread-0 - Count: 2
Thread-0 - Count: 3
Thread-1 - Count: 4
Thread-1 - Count: 5
...
Now, one thread completes execution before the next thread can access increment(), ensuring correct
values.
23
5. Important Points About Synchronized Methods
✅ A synchronized method locks the entire object (this), allowing only one thread to access it at a time.
✅ If one thread is inside a synchronized method, other threads must wait until the method is free.
✅ It is useful for instance methods that modify shared data.
6. Synchronized Methods in Static Context
If a method is static, synchronization applies at the class level instead of the instance level.
Example: Static Synchronized Method
class SharedResource {
private static int count = 0;
public static synchronized void increment() { // Static synchronized method
count++;
System.out.println(Thread.currentThread().getName() + " - Count: " + count);
}
}
class MyThread extends Thread {
public void run() {
SharedResource.increment();
}
}
public class StaticSyncExample {
public static void main(String[] args) {
Thread t1 = new MyThread();
Thread t2 = new MyThread();
t1.start();
t2.start();
}
}
Why Use Static Synchronization?
✔ Locks the entire class, ensuring that multiple threads do not access the static method at the same
time.
✔ Prevents data corruption in shared static resources.
7. When to Use Synchronized Methods?
Use synchronized methods when:
✔ You have shared resources that multiple threads access.
✔ You need thread safety without blocking too many operations.
✔ You want to avoid data inconsistency issues (e.g., race conditions).
When Not to Use Synchronized Methods?
❌ If synchronization is not necessary, using it slows down performance.
❌ For small sections of code, use synchronized blocks instead (to reduce the performance overhead).
24
8. Alternative: Using Synchronized Blocks
If synchronizing the entire method is too restrictive, use synchronized blocks instead.
class Counter {
private int count = 0;
public void increment() {
synchronized (this) { // Synchronized block
count++;
System.out.println(Thread.currentThread().getName() + " - Count: " + count);
}
}
}
✔ Synchronized blocks reduce the performance overhead by locking only the critical section of the code.
Using Synchronized Statement in Java
A synchronized statement (synchronized block) in Java is used to provide fine-grained control over
synchronization. Instead of locking an entire method, you can lock only a critical section of code.
🔹 Why use synchronized statements?
Increases performance by reducing the lock area.
Prevents unnecessary blocking of non-critical code.
Provides better thread efficiency compared to synchronized methods.
2. Syntax of Synchronized Statement
synchronized (lockObject) {
// Critical section - only one thread can execute at a time
}
Here, lockObject is the object used for synchronization. Only one thread can access this block at a time.
3. Example Without Synchronization (Data Corruption)
class Counter {
private int count = 0;
public void increment() { // Not synchronized
count++;
System.out.println(Thread.currentThread().getName() + " - Count: " + count);
}
}
class MyThread extends Thread {
Counter counter;
public MyThread(Counter counter) {
this.counter = counter;
}
public void run() {
25
for (int i = 0; i < 5; i++) {
counter.increment();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
System.out.println("Interrupted");
}
}
}
}
public class WithoutSyncBlock {
public static void main(String[] args) {
Counter counter = new Counter();
Thread t1 = new MyThread(counter);
Thread t2 = new MyThread(counter);
t1.start();
t2.start();
}
}
Output (Incorrect Count due to Race Condition)
Thread-0 - Count: 1
Thread-1 - Count: 2
Thread-0 - Count: 3
Thread-1 - Count: 3 <-- Wrong count!
...
Multiple threads are modifying count simultaneously, leading to incorrect results.
4. Solution Using Synchronized Statement
We can fix the issue by using a synchronized block inside the method instead of synchronizing the entire
method.
class Counter {
private int count = 0;
public void increment() {
synchronized (this) { // Synchronized block
count++;
System.out.println(Thread.currentThread().getName() + " - Count: " + count);
}
}
}
class MyThread extends Thread {
Counter counter;
public MyThread(Counter counter) {
26
this.counter = counter;
}
public void run() {
for (int i = 0; i < 5; i++) {
counter.increment();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
System.out.println("Interrupted");
}
}
}
}
public class WithSyncBlock {
public static void main(String[] args) {
Counter counter = new Counter();
Thread t1 = new MyThread(counter);
Thread t2 = new MyThread(counter);
t1.start();
t2.start();
}
}
Output (Correct Count)
Thread-0 - Count: 1
Thread-1 - Count: 2
Thread-0 - Count: 3
Thread-1 - Count: 4
Thread-0 - Count: 5
...
Here, the synchronized block ensures that only one thread modifies count at a time.
5. Why Use Synchronized Blocks Instead of Synchronized Methods?
Feature Synchronized Method Synchronized Block
Lock Scope Locks entire method Locks only a part of the method
Performance Slower (more lock contention) Faster (minimizes lock area)
When entire method must be When only a critical section needs
Use Case
synchronized synchronization
6. Example: Synchronizing a Shared Resource (Bank Account)
class BankAccount {
private int balance = 1000;
public void withdraw(int amount) {
27
synchronized (this) { // Only this block is synchronized
if (balance >= amount) {
System.out.println(Thread.currentThread().getName() + " is withdrawing: " + amount);
balance -= amount;
System.out.println("Remaining Balance: " + balance);
} else {
System.out.println(Thread.currentThread().getName() + " - Not enough balance!");
}
}
}
}
class UserThread extends Thread {
BankAccount account;
int amount;
public UserThread(BankAccount account, int amount) {
this.account = account;
this.amount = amount;
}
public void run() {
account.withdraw(amount);
}
}
public class SyncBlockExample {
public static void main(String[] args) {
BankAccount account = new BankAccount();
Thread t1 = new UserThread(account, 600);
Thread t2 = new UserThread(account, 500);
t1.start();
t2.start();
}
}
Output
Thread-0 is withdrawing: 600
Remaining Balance: 400
Thread-1 - Not enough balance!
🔹 Here, the synchronized block ensures that only one user withdraws at a time, preventing over-
withdrawal.
7. Synchronizing a Static Method (Class-Level Lock)
If a method is static, we should use a class-level lock (ClassName.class).
class SharedResource {
28
private static int count = 0;
public static void increment() {
synchronized (SharedResource.class) { // Class-level lock
count++;
System.out.println(Thread.currentThread().getName() + " - Count: " + count);
}
}
}
class MyThread extends Thread {
public void run() {
SharedResource.increment();
}
}
public class StaticSyncBlock {
public static void main(String[] args) {
Thread t1 = new MyThread();
Thread t2 = new MyThread();
t1.start();
t2.start();
}
}
✔ Class-level synchronization ensures that even if multiple objects exist, only one thread can execute the
block.
8. When to Use Synchronized Statements?
✅ Use synchronized statements when you need to:
Protect only a specific section of the code.
Improve performance by reducing lock contention.
Synchronize static methods or resources (ClassName.class).
❌ Do not use synchronized statements when:
The entire method must be thread-safe (use synchronized methods instead).
There are better alternatives (e.g., ReentrantLock).
Inter-Thread Communication
1. What is Inter-Thread Communication?
Inter-thread communication allows multiple threads to communicate and coordinate their actions in a
synchronized manner. It is primarily used in producer-consumer problems, where one thread produces
data, and another thread consumes it.
🔹 Key Methods for Inter-Thread Communication (From Object Class)
Method Description
wait() Causes the thread to wait until another thread calls notify() or notifyAll().
notify() Wakes up a single thread that is waiting on the object's monitor.
29
Method Description
notifyAll() Wakes up all threads that are waiting on the object's monitor.
💡 These methods must be called inside a synchronized block or synchronized method; otherwise, Java
will throw IllegalMonitorStateException.
2. Example: Producer-Consumer Problem (Using wait() and notify())
class SharedResource {
private int data;
private boolean available = false; // Flag to check if data is ready
// Producer method
public synchronized void produce(int value) {
while (available) { // If data is already available, wait
try {
wait(); // Wait until consumer consumes the data
} catch (InterruptedException e) {
System.out.println("Producer interrupted");
}
}
data = value;
System.out.println("Produced: " + value);
available = true;
notify(); // Notify the consumer that data is ready
}
// Consumer method
public synchronized void consume() {
while (!available) { // If no data is available, wait
try {
wait(); // Wait until producer produces data
} catch (InterruptedException e) {
System.out.println("Consumer interrupted");
}
}
System.out.println("Consumed: " + data);
available = false;
notify(); // Notify producer that data is consumed
}
}
// Producer Thread
class Producer extends Thread {
SharedResource resource;
public Producer(SharedResource resource) {
this.resource = resource;
30
}
public void run() {
for (int i = 1; i <= 5; i++) {
resource.produce(i);
try {
Thread.sleep(1000); // Simulating time to produce
} catch (InterruptedException e) {
System.out.println("Producer interrupted");
}
}
}
}
// Consumer Thread
class Consumer extends Thread {
SharedResource resource;
public Consumer(SharedResource resource) {
this.resource = resource;
}
public void run() {
for (int i = 1; i <= 5; i++) {
resource.consume();
try {
Thread.sleep(1500); // Simulating time to consume
} catch (InterruptedException e) {
System.out.println("Consumer interrupted");
}
}
}
}
// Main Class
public class InterThreadCommunication {
public static void main(String[] args) {
SharedResource resource = new SharedResource();
Producer producer = new Producer(resource);
Consumer consumer = new Consumer(resource);
producer.start();
consumer.start();
}
}
4. Using notifyAll() for Multiple Consumers
31
If multiple consumers are waiting, we use notifyAll() to wake up all threads.
public synchronized void produce(int value) {
while (available) {
try {
wait();
} catch (InterruptedException e) {
System.out.println("Producer interrupted");
}
}
data = value;
System.out.println("Produced: " + value);
available = true;
notifyAll(); // Wakes up all waiting threads
}
5. Alternative: Using Lock and Condition (Modern Approach)
Instead of wait() and notify(), we can use ReentrantLock and Condition (introduced in Java 5).
import java.util.concurrent.locks.*;
class SharedResource {
private int data;
private boolean available = false;
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
public void produce(int value) {
lock.lock();
try {
while (available) {
condition.await(); // Wait until data is consumed
}
data = value;
System.out.println("Produced: " + value);
available = true;
condition.signal(); // Notify waiting consumer
} catch (InterruptedException e) {
System.out.println("Producer interrupted");
} finally {
lock.unlock();
}
}
public void consume() {
lock.lock();
try {
while (!available) {
condition.await(); // Wait until data is produced
32
}
System.out.println("Consumed: " + data);
available = false;
condition.signal(); // Notify waiting producer
} catch (InterruptedException e) {
System.out.println("Consumer interrupted");
} finally {
lock.unlock();
}
}
}
✔ Lock and Condition provide better control and avoid spurious wakeups compared to wait() and
notify().
6. Summary
Feature wait() & notify() Lock & Condition
Synchronization Uses intrinsic object lock Uses explicit lock (ReentrantLock)
notify() wakes only one thread, notifyAll() More precise control with signal() and
Wake-Up Control
wakes all signalAll()
Performance Slightly slower due to JVM overhead Faster and more efficient
Use Case Simple producer-consumer problems Complex synchronization scenarios
7. When to Use Inter-Thread Communication?
✅ Use wait() and notify() when:
You need basic thread communication.
You are working with older Java versions (< Java 5).
You are fine with spurious wakeups.
✅ Use Lock and Condition when:
You need precise control over thread wake-ups.
You want better performance and avoid spurious wakeups.
You are using Java 5 or later.
Deadlock in Java
Deadlock
A deadlock occurs in a multi-threaded program when two or more threads are waiting for each other to
release resources, and none can proceed. This leads to an infinite waiting state, effectively freezing the
program.
2. How Does Deadlock Happen?
Deadlocks typically occur when:
1. Multiple threads hold locks on different resources.
2. Each thread waits for a resource that another thread is holding.
3. The cycle of dependency causes a situation where no thread can proceed.
🔹 Example of a Deadlock Situation
Thread A locks Resource 1 and waits for Resource 2 (held by Thread B).
Thread B locks Resource 2 and waits for Resource 1 (held by Thread A).
33
Neither thread can proceed, causing a deadlock.
3. Example: Deadlock in Java
class SharedResource {
static final Object RESOURCE_1 = new Object();
static final Object RESOURCE_2 = new Object();
}
// Thread 1 tries to lock RESOURCE_1 first, then RESOURCE_2
class ThreadA extends Thread {
public void run() {
synchronized (SharedResource.RESOURCE_1) {
System.out.println("Thread A: Locked RESOURCE_1");
try { Thread.sleep(100); } catch (InterruptedException e) {}
System.out.println("Thread A: Waiting for RESOURCE_2...");
synchronized (SharedResource.RESOURCE_2) {
System.out.println("Thread A: Locked RESOURCE_2");
}
}
}
}
// Thread 2 tries to lock RESOURCE_2 first, then RESOURCE_1
class ThreadB extends Thread {
public void run() {
synchronized (SharedResource.RESOURCE_2) {
System.out.println("Thread B: Locked RESOURCE_2");
try { Thread.sleep(100); } catch (InterruptedException e) {}
System.out.println("Thread B: Waiting for RESOURCE_1...");
synchronized (SharedResource.RESOURCE_1) {
System.out.println("Thread B: Locked RESOURCE_1");
}
}
}
}
public class DeadlockExample {
public static void main(String[] args) {
ThreadA threadA = new ThreadA();
ThreadB threadB = new ThreadB();
threadA.start();
threadB.start();
34
}
}
4. Output (Illustrating Deadlock)
Thread A: Locked RESOURCE_1
Thread B: Locked RESOURCE_2
Thread A: Waiting for RESOURCE_2...
Thread B: Waiting for RESOURCE_1...
Both threads are waiting for each other to release a resource, causing a deadlock.
5. How to Prevent Deadlocks?
✅ Solution 1: Always Lock Resources in the Same Order
By ensuring that all threads acquire locks in the same order, deadlock can be prevented.
class ThreadA extends Thread {
public void run() {
synchronized (SharedResource.RESOURCE_1) {
System.out.println("Thread A: Locked RESOURCE_1");
synchronized (SharedResource.RESOURCE_2) {
System.out.println("Thread A: Locked RESOURCE_2");
}
}
}
}
class ThreadB extends Thread {
public void run() {
synchronized (SharedResource.RESOURCE_1) { // Same order as ThreadA
System.out.println("Thread B: Locked RESOURCE_1");
synchronized (SharedResource.RESOURCE_2) {
System.out.println("Thread B: Locked RESOURCE_2");
}
}
}
}
Now, both threads lock resources in the same order, preventing a cycle.
35
I/O Streams in Java
1. What are I/O Streams?
I/O (Input/Output) streams in Java allow programs to read data from and write data to different sources,
such as files, memory, or network connections.
🔹 Types of Streams in Java
Java provides two main categories of I/O streams:
1. Byte Streams (InputStream & OutputStream) → Handle binary data (e.g., images, audio files).
2. Character Streams (Reader & Writer) → Handle text data (e.g., .txt, .csv files).
2. Byte Streams (For Binary Data)
These streams are used to handle raw byte data, making them suitable for files like images, videos, and
audio.
🔹 Key Classes for Byte Streams
Class Description
InputStream Abstract class for reading byte data.
OutputStream Abstract class for writing byte data.
FileInputStream Reads byte data from a file.
FileOutputStream Writes byte data to a file.
BufferedInputStream Improves performance using buffering.
BufferedOutputStream Enhances output efficiency.
🔹 Example: Reading a File Using Byte Stream
import java.io.FileInputStream;
import java.io.IOException;
public class ByteStreamExample {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("example.txt")) {
int byteData;
while ((byteData = fis.read()) != -1) {
System.out.print((char) byteData); // Convert byte to char
}
} catch (IOException e) {
System.out.println("Error reading file: " + e.getMessage());
}
}
}
Uses FileInputStream to read raw bytes and convert them into characters.
try-with-resources ensures the file is automatically closed.
3. Character Streams (For Text Data)
Character streams process text-based data (Unicode characters).
🔹 Key Classes for Character Streams
Class Description
Reader Abstract class for reading character data.
Writer Abstract class for writing character data.
36
Class Description
FileReader Reads character data from a file.
FileWriter Writes character data to a file.
BufferedReader Improves reading performance using buffering.
BufferedWriter Enhances writing efficiency.
🔹 Example: Reading a File Using Character Stream
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class CharacterStreamExample {
public static void main(String[] args) {
try (BufferedReader br = new BufferedReader(new FileReader("example.txt"))) {
String line;
while ((line = br.readLine()) != null) { // Reads line by line
System.out.println(line);
}
} catch (IOException e) {
System.out.println("Error reading file: " + e.getMessage());
}
}
}
Uses BufferedReader to read text files line by line, improving performance.
4. Buffered Streams (For Efficiency)
Buffered streams improve performance by reducing disk I/O operations.
🔹 Example: Writing a File Using BufferedWriter
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class BufferedWriterExample {
public static void main(String[] args) {
try (BufferedWriter bw = new BufferedWriter(new FileWriter("output.txt"))) {
bw.write("Hello, this is a BufferedWriter example.");
bw.newLine(); // Writes a new line
bw.write("It improves file writing performance!");
} catch (IOException e) {
System.out.println("Error writing file: " + e.getMessage());
}
}
}
Uses buffering to reduce direct disk writes, improving efficiency.
5. Data Streams (For Primitive Data Types)
Used for reading and writing primitive data types (int, double, boolean, etc.).
37
🔹 Example: Writing & Reading Primitive Data Using Data Streams
import java.io.DataOutputStream;
import java.io.DataInputStream;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
public class DataStreamExample {
public static void main(String[] args) {
String file = "data.bin";
// Writing primitive data to a file
try (DataOutputStream dos = new DataOutputStream(new FileOutputStream(file))) {
dos.writeInt(100);
dos.writeDouble(99.99);
dos.writeBoolean(true);
} catch (IOException e) {
System.out.println("Error writing file: " + e.getMessage());
}
// Reading primitive data from the file
try (DataInputStream dis = new DataInputStream(new FileInputStream(file))) {
System.out.println("Integer: " + dis.readInt());
System.out.println("Double: " + dis.readDouble());
System.out.println("Boolean: " + dis.readBoolean());
} catch (IOException e) {
System.out.println("Error reading file: " + e.getMessage());
}
}
}
DataOutputStream writes primitive types.
DataInputStream reads primitive values.
7. Summary: Types of Java I/O Streams
Stream Type Purpose Classes
Process binary data (e.g., images, InputStream, OutputStream, FileInputStream,
Byte Streams
audio) FileOutputStream
Character
Process text data Reader, Writer, FileReader, FileWriter
Streams
Buffered
Improve performance BufferedReader, BufferedWriter
Streams
Data Streams Read/write primitive data DataInputStream, DataOutputStream
Object Streams Read/write objects (serialization) ObjectInputStream, ObjectOutputStream
Concepts of Streams in Java
38
1. Introduction to Streams
A stream in Java is a continuous flow of data from a source to a destination. Java provides built-in classes
to handle input and output (I/O) operations efficiently.
Streams abstract low-level data transfer between:
Programs and files
Programs and memory
Programs and network connections
🔹 Key Characteristics of Streams
✔ Unidirectional (Either input or output)
✔ Sequential flow of data
✔ Abstracts complex I/O operations
2. Types of Streams in Java
Java provides two main types of streams based on data type:
🔹 1. Byte Streams (For Binary Data)
Used to read and write raw binary data (e.g., images, audio, video).
Works with 8-bit bytes.
Uses InputStream and OutputStream.
🔹 2. Character Streams (For Text Data)
Used for text-based data (Unicode characters).
Works with 16-bit Unicode characters.
Uses Reader and Writer.
Stream Type Base Class (Abstract) Used For
Byte Input Stream InputStream Reading binary data
Byte Output Stream OutputStream Writing binary data
Character Input Stream Reader Reading text data
Character Output Stream Writer Writing text data
3. Byte Streams (Handling Binary Data)
Used for reading and writing binary files (images, videos, audio, etc.).
🔹 Key Classes for Byte Streams
Class Description
InputStream Base class for byte input.
OutputStream Base class for byte output.
FileInputStream Reads bytes from a file.
FileOutputStream Writes bytes to a file.
BufferedInputStream Improves performance by buffering input.
BufferedOutputStream Enhances output efficiency.
🔹 Example: Reading a File Using Byte Stream
import java.io.FileInputStream;
import java.io.IOException;
public class ByteStreamExample {
public static void main(String[] args) {
39
try (FileInputStream fis = new FileInputStream("image.jpg")) {
int byteData;
while ((byteData = fis.read()) != -1) {
System.out.print(byteData + " "); // Print raw byte data
}
} catch (IOException e) {
System.out.println("Error reading file: " + e.getMessage());
}
}
}
Reads raw bytes from image.jpg and prints byte values.
4. Character Streams (Handling Text Data)
Used for reading and writing text files.
🔹 Key Classes for Character Streams
Class Description
Reader Base class for character input.
Writer Base class for character output.
FileReader Reads characters from a file.
FileWriter Writes characters to a file.
BufferedReader Reads text efficiently.
BufferedWriter Writes text efficiently.
🔹 Example: Reading a File Using Character Stream
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class CharacterStreamExample {
public static void main(String[] args) {
try (BufferedReader br = new BufferedReader(new FileReader("example.txt"))) {
String line;
while ((line = br.readLine()) != null) { // Reads line by line
System.out.println(line);
}
} catch (IOException e) {
System.out.println("Error reading file: " + e.getMessage());
}
}
}
Reads line by line using BufferedReader.
5. Buffered Streams (For Performance Enhancement)
Buffered streams use an internal buffer to improve I/O efficiency.
🔹 Example: Writing a File Using BufferedWriter
import java.io.BufferedWriter;
import java.io.FileWriter;
40
import java.io.IOException;
public class BufferedWriterExample {
public static void main(String[] args) {
try (BufferedWriter bw = new BufferedWriter(new FileWriter("output.txt"))) {
bw.write("Hello, this is a BufferedWriter example.");
bw.newLine(); // Writes a new line
bw.write("It improves file writing performance!");
} catch (IOException e) {
System.out.println("Error writing file: " + e.getMessage());
}
}
}
Buffers data before writing to reduce disk access.
6. Data Streams (Handling Primitive Data)
Java provides Data Streams for reading and writing primitive types (int, double, boolean, etc.).
🔹 Example: Writing & Reading Primitive Data
import java.io.DataOutputStream;
import java.io.DataInputStream;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
public class DataStreamExample {
public static void main(String[] args) {
String file = "data.bin";
// Writing primitive data to a file
try (DataOutputStream dos = new DataOutputStream(new FileOutputStream(file))) {
dos.writeInt(100);
dos.writeDouble(99.99);
dos.writeBoolean(true);
} catch (IOException e) {
System.out.println("Error writing file: " + e.getMessage());
}
// Reading primitive data from the file
try (DataInputStream dis = new DataInputStream(new FileInputStream(file))) {
System.out.println("Integer: " + dis.readInt());
System.out.println("Double: " + dis.readDouble());
System.out.println("Boolean: " + dis.readBoolean());
} catch (IOException e) {
System.out.println("Error reading file: " + e.getMessage());
}
}
}
41
Efficiently reads and writes primitive data.
7. Object Streams (Serialization & Deserialization)
Java allows objects to be converted into byte streams (serialization) and restored (deserialization).
🔹 Example: Serializing & Deserializing an Object
import java.io.*;
class Person implements Serializable {
private static final long serialVersionUID = 1L;
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
public class ObjectStreamExample {
public static void main(String[] args) {
String file = "person.dat";
// Serialization
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file))) {
Person p = new Person("John Doe", 30);
oos.writeObject(p);
} catch (IOException e) {
System.out.println("Error writing object: " + e.getMessage());
}
// Deserialization
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))) {
Person p = (Person) ois.readObject();
System.out.println("Deserialized Person: " + p.name + ", Age: " + p.age);
} catch (IOException | ClassNotFoundException e) {
System.out.println("Error reading object: " + e.getMessage());
}
}
}
Stores and retrieves Java objects from files.
Byte and Character Streams in Java
1. Introduction to Streams
Java uses streams to perform input and output (I/O) operations efficiently. Streams provide a common
interface for reading and writing data between different sources (files, memory, network, etc.).
Byte Streams – Handle binary data (images, audio, etc.).
42
Character Streams – Handle text data (Unicode characters).
2. Byte Streams (Binary Data Handling)
Byte streams are used to read and write raw binary data.
They do not perform character encoding/decoding.
🔹 Byte Stream Classes
Type Input Stream Output Stream
Base Class InputStream OutputStream
File Handling FileInputStream FileOutputStream
Array Handling ByteArrayInputStream ByteArrayOutputStream
Buffered Stream BufferedInputStream BufferedOutputStream
Primitive Data Handling DataInputStream DataOutputStream
Object Handling ObjectInputStream ObjectOutputStream
🔹 Example: Using Byte Streams (File Copy)
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class ByteStreamExample {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("input.bin");
FileOutputStream fos = new FileOutputStream("output.bin")) {
int byteData;
while ((byteData = fis.read()) != -1) { // Read byte by byte
fos.write(byteData); // Write byte by byte
}
System.out.println("File copied successfully using Byte Streams.");
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
}
}
}
📝 Explanation:
Reads data byte by byte.
Suitable for binary files (e.g., images, videos).
Uses FileInputStream and FileOutputStream.
3. Character Streams (Text Data Handling)
Character streams read and write Unicode characters.
They automatically handle character encoding/decoding.
🔹 Character Stream Classes
Type Reader (Input) Writer (Output)
Base Class Reader Writer
File Handling FileReader FileWriter
43
Type Reader (Input) Writer (Output)
Buffered Stream BufferedReader BufferedWriter
Array Handling CharArrayReader CharArrayWriter
String Handling StringReader StringWriter
🔹 Example: Using Character Streams (Read Text File)
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class CharacterStreamExample {
public static void main(String[] args) {
try (BufferedReader br = new BufferedReader(new FileReader("example.txt"))) {
String line;
while ((line = br.readLine()) != null) { // Read line by line
System.out.println(line);
}
} catch (IOException e) {
System.out.println("Error reading file: " + e.getMessage());
}
}
}
📝 Explanation:
Reads text line by line.
Uses BufferedReader for efficient reading.
Suitable for text files (e.g., .txt, .csv).
4. Key Differences: Byte vs Character Streams
Feature Byte Stream Character Stream
Base Class InputStream / OutputStream Reader / Writer
Data Type Binary data (bytes) Text data (characters)
Used For Images, audio, videos Text files, documents
Encoding Handling No encoding/decoding Supports Unicode encoding
Example Classes FileInputStream, FileOutputStream FileReader, FileWriter
5. Buffered Streams (For Performance)
Buffered Streams improve efficiency by reducing the number of I/O operations.
🔹 Buffered Byte Streams
BufferedInputStream
BufferedOutputStream
🔹 Buffered Character Streams
BufferedReader
BufferedWriter
🔸 Example: Using Buffered Character Stream
import java.io.BufferedWriter;
import java.io.FileWriter;
44
import java.io.IOException;
public class BufferedWriterExample {
public static void main(String[] args) {
try (BufferedWriter bw = new BufferedWriter(new FileWriter("output.txt"))) {
bw.write("Buffered Writer Example");
bw.newLine();
bw.write("Enhances file writing performance!");
System.out.println("Text written successfully.");
} catch (IOException e) {
System.out.println("Error writing file: " + e.getMessage());
}
}
}
📝 Key Points:
✔ Improves efficiency by reducing disk I/O operations.
✔ Best for large files or frequent reads/writes.
6. When to Use Byte vs. Character Streams
Use Case Recommended Stream Type
Copying an image or video Byte Stream (FileInputStream)
Reading a text file (UTF-8 encoded) Character Stream (BufferedReader)
Writing a log file Character Stream (BufferedWriter)
Processing binary data (e.g., encryption) Byte Stream (ByteArrayInputStream)
7. Summary
Feature Byte Stream Character Stream
Data Type Binary (0s and 1s) Text (Unicode characters)
Used For Images, audio, video Text, documents
Example Classes FileInputStream, FileOutputStream FileReader, FileWriter
Buffered Variant BufferedInputStream, BufferedOutputStream BufferedReader, BufferedWriter
Reading Console Input
1. Introduction
Java provides multiple ways to read input from the console, which is useful for interacting with users.
The main methods include:
1. Using Scanner (Preferred method)
2. Using BufferedReader
3. Using System.console()
4. Using DataInputStream (Legacy method, not recommended)
2. Using Scanner (Most Common Method)
The Scanner class (introduced in Java 5) makes it easy to read different types of user input.
🔹 Example: Reading Different Inputs
import java.util.Scanner;
45
public class ScannerExample {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Read an integer
System.out.print("Enter an integer: ");
int num = scanner.nextInt();
// Read a float
System.out.print("Enter a float: ");
float decimal = scanner.nextFloat();
// Read a string (single word)
System.out.print("Enter a single word: ");
String word = scanner.next();
// Read a full line
scanner.nextLine(); // Consume the leftover newline
System.out.print("Enter a full sentence: ");
String sentence = scanner.nextLine();
// Print the user inputs
System.out.println("\nYou entered:");
System.out.println("Integer: " + num);
System.out.println("Float: " + decimal);
System.out.println("Word: " + word);
System.out.println("Sentence: " + sentence);
scanner.close(); // Close the scanner
}
}
✅ Output Example
Enter an integer: 5
Enter a float: 3.14
Enter a single word: Java
Enter a full sentence: Java is powerful!
You entered:
Integer: 5
Float: 3.14
Word: Java
Sentence: Java is powerful!
📌 Why use Scanner? ✔ Supports various data types (int, float, double, string, etc.).
✔ Simple syntax and easy to use.
✔ Handles parsing of primitive data types automatically.
46
3. Using BufferedReader (Efficient for Large Inputs)
BufferedReader is faster than Scanner for large input because it reads input as a stream.
🔹 Example: Reading Input Using BufferedReader
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class BufferedReaderExample {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// Read a string
System.out.print("Enter your name: ");
String name = br.readLine();
// Read an integer
System.out.print("Enter your age: ");
int age = Integer.parseInt(br.readLine());
System.out.println("\nHello, " + name + "! You are " + age + " years old.");
}
}
✅ Output Example
Enter your name: Alice
Enter your age: 25
Hello, Alice! You are 25 years old.
📌 Why use BufferedReader? ✔ Faster than Scanner (used in high-performance applications).
✔ Best for reading large text input efficiently.
✔ Does not parse primitive types automatically (must use Integer.parseInt(), etc.).
4. Using System.console() (For Password Input)
System.console() is useful for reading passwords securely since it does not display them on the screen.
🔹 Example: Reading Password Securely
import java.io.Console;
public class ConsoleExample {
public static void main(String[] args) {
Console console = System.console();
if (console != null) {
String username = console.readLine("Enter username: ");
char[] password = console.readPassword("Enter password: ");
System.out.println("Welcome, " + username + "!");
47
// Clear the password array
java.util.Arrays.fill(password, ' ');
} else {
System.out.println("Console is not available.");
}
}
}
✅ Output Example
Enter username: John
Enter password: (hidden input)
Welcome, John!
📌 Why use System.console()? ✔ Secure (hides password input).
✔ Best for command-line applications.
⚠ Not available in some IDEs (like Eclipse, IntelliJ).
5. Using DataInputStream (Legacy Method, Not Recommended)
This method was used in older Java versions but is now deprecated.
🔹 Example (Legacy Code)
import java.io.DataInputStream;
import java.io.IOException;
public class DataInputStreamExample {
public static void main(String[] args) throws IOException {
DataInputStream dis = new DataInputStream(System.in);
System.out.print("Enter your name: ");
String name = dis.readLine(); // Deprecated method
System.out.println("Hello, " + name + "!");
}
}
📌 Why Avoid DataInputStream? ❌ readLine() method is deprecated.
❌ No automatic parsing of primitive types.
❌ Use Scanner or BufferedReader instead.
6. Comparison Table: Console Input Methods
Handles Data Types Handles Large Input Secure for
Method Best For
Automatically? Efficiently? Passwords?
General input
Scanner ✅ Yes ❌ No ❌ No
(numbers, text)
BufferedReader Large text input ❌ No (needs parsing) ✅ Yes ❌ No
Secure password
System.console() ❌ No ❌ No ✅ Yes
input
DataInputStream Legacy applications ❌ No (deprecated) ❌ No ❌ No
48
7. Best Practices for Console Input
🔹 Use Scanner for small, simple inputs.
🔹 Use BufferedReader for large inputs (performance-efficient).
🔹 Use System.console() for password input (secure).
🔹 Avoid DataInputStream, as it is deprecated.
8. Summary
Method Key Features
Scanner Best for small user inputs, handles multiple data types
BufferedReader Best for large text input, high performance
System.console() Best for secure password input
DataInputStream Deprecated, not recommended
Writing Console Output in Java
1. Introduction
Java provides several ways to write output to the console, primarily using:
1. System.out.print() & System.out.println()
2. System.out.printf() (for formatted output)
3. System.out.format() (alternative to printf)
4. PrintWriter (for advanced output handling)
2. Using System.out.print() and System.out.println()
These are the most commonly used methods for console output.
🔹 Example: Using print() and println()
public class PrintExample {
public static void main(String[] args) {
System.out.print("Hello, "); // Prints without newline
System.out.println("World!"); // Prints with a newline
System.out.println("Java is powerful!");
}
}
✅ Output
Hello, World!
Java is powerful!
📌 Difference between print() and println()
✔ print(): Prints text without a newline.
✔ println(): Prints text and moves to the next line.
3. Using System.out.printf() for Formatted Output
The printf() method allows formatting similar to C-style printf().
🔹 Example: Formatting Output with printf()
public class PrintfExample {
public static void main(String[] args) {
int age = 25;
double score = 95.75;
49
System.out.printf("Age: %d years\n", age);
System.out.printf("Score: %.2f points\n", score);
}
}
✅ Output
Age: 25 years
Score: 95.75 points
📌 Format Specifiers in printf()
Specifier Meaning
%d Integer (Decimal)
%f Floating-point Number
%.2f Floating-point with 2 decimal places
%s String
%c Character
%n Newline (same as \n)
4. Using System.out.format() (Same as printf())
format() is an alias for printf().
🔹 Example: Using format()
public class FormatExample {
public static void main(String[] args) {
String name = "Alice";
double salary = 50000.50;
System.out.format("Employee: %s earns $%.2f per year%n", name, salary);
}
}
✅ Output
Employee: Alice earns $50000.50 per year
📌 format() is identical to printf() but improves readability.
5. Using PrintWriter for Advanced Output
The PrintWriter class provides more control over output, including writing to both console and files.
🔹 Example: Using PrintWriter for Console Output
import java.io.PrintWriter;
public class PrintWriterExample {
public static void main(String[] args) {
PrintWriter writer = new PrintWriter(System.out, true);
writer.println("Hello from PrintWriter!");
writer.printf("Formatted Number: %.3f%n", 123.456);
}
}
✅ Output
50
Hello from PrintWriter!
Formatted Number: 123.456
📌 Why use PrintWriter?
✔ Supports auto-flushing (ensures output appears immediately).
✔ Can write both to console and files.
✔ More flexible than System.out.
6. Comparison Table: Console Output Methods
Method Usage Supports Formatting? Best For
System.out.print() Print without newline ❌ No Simple text output
System.out.println() Print with newline ❌ No Line-by-line output
System.out.printf() Formatted output ✅ Yes Numbers, strings, custom formats
System.out.format() Same as printf() ✅ Yes Readable formatted output
PrintWriter Advanced output ✅ Yes Writing to console or files
7. Best Practices for Console Output
🔹 Use println() for normal text output.
🔹 Use printf() for formatted text and numbers.
🔹 Use PrintWriter for advanced console and file writing.
🔹 Use \t for tab spacing and \n for newlines if needed.
8. Summary
Method Key Features
print() Prints without newline
println() Prints with newline
printf() Formatted output (numbers, strings, etc.)
format() Same as printf(), improves readability
PrintWriter Advanced writing, supports auto-flushing
File Handling in Java
1. Introduction to File Handling in Java
Java provides a rich set of I/O classes in the java.io package for handling files.
Common file operations include:
✔ Reading from a file
✔ Writing to a file
✔ Appending data to a file
✔ Deleting a file
2. File Class (java.io.File)
The File class is used to represent file and directory paths.
🔹 Example: Checking if a File Exists
import java.io.File;
public class FileExample {
51
public static void main(String[] args) {
File file = new File("example.txt");
if (file.exists()) {
System.out.println("File exists: " + file.getAbsolutePath());
} else {
System.out.println("File does not exist.");
}
}
}
✅ Output (if file exists)
File exists: C:\Users\Documents\example.txt
📌 File Class Methods:
Method Description
exists() Checks if file exists
getName() Returns file name
getAbsolutePath() Returns absolute path
canRead() Checks if file is readable
canWrite() Checks if file is writable
length() Returns file size in bytes
delete() Deletes the file
3. Writing to a File using FileWriter
The FileWriter class allows writing characters to a file.
🔹 Example: Writing Data to a File
import java.io.FileWriter;
import java.io.IOException;
public class WriteToFile {
public static void main(String[] args) {
try {
FileWriter writer = new FileWriter("output.txt");
writer.write("Hello, this is a sample file!\n");
writer.write("Java file handling is easy.");
writer.close(); // Close the file
System.out.println("File written successfully.");
} catch (IOException e) {
System.out.println("An error occurred: " + e.getMessage());
}
}
}
✅ Output
File written successfully.
📌 Always close the file (writer.close()) to save changes!
4. Reading from a File using FileReader
52
The FileReader class reads characters from a file.
🔹 Example: Reading Data from a File
import java.io.FileReader;
import java.io.IOException;
public class ReadFromFile {
public static void main(String[] args) {
try {
FileReader reader = new FileReader("output.txt");
int character;
while ((character = reader.read()) != -1) {
System.out.print((char) character);
}
reader.close();
} catch (IOException e) {
System.out.println("Error reading file: " + e.getMessage());
}
}
}
✅ Output (File Content)
Hello, this is a sample file!
Java file handling is easy.
5. Using BufferedWriter for Efficient Writing
The BufferedWriter class improves performance by buffering data.
🔹 Example: Writing Data with BufferedWriter
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class BufferedWriteExample {
public static void main(String[] args) {
try {
BufferedWriter writer = new BufferedWriter(new FileWriter("buffered_output.txt"));
writer.write("This is a buffered writer example.");
writer.newLine();
writer.write("It improves writing performance.");
writer.close();
System.out.println("File written successfully using BufferedWriter.");
} catch (IOException e) {
System.out.println("An error occurred: " + e.getMessage());
}
}
}
6. Using BufferedReader for Efficient Reading
The BufferedReader class reads data line-by-line, improving performance.
53
🔹 Example: Reading Data with BufferedReader
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class BufferedReadExample {
public static void main(String[] args) {
try {
BufferedReader reader = new BufferedReader(new FileReader("buffered_output.txt"));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
reader.close();
} catch (IOException e) {
System.out.println("Error reading file: " + e.getMessage());
}
}
}
✅ Output
This is a buffered writer example.
It improves writing performance.
📌 Use readLine() to read one line at a time instead of character-by-character.
7. Appending Data to an Existing File
To add content without overwriting, use FileWriter(filename, true)
🔹 Example: Appending Data
import java.io.FileWriter;
import java.io.IOException;
public class AppendToFile {
public static void main(String[] args) {
try {
FileWriter writer = new FileWriter("output.txt", true);
writer.write("\nAppending a new line!");
writer.close();
System.out.println("Data appended successfully.");
} catch (IOException e) {
System.out.println("Error appending to file: " + e.getMessage());
}
}
}
📌 Second argument (true) enables append mode.
8. Deleting a File
To delete a file, use delete() from the File class.
54
🔹 Example: Deleting a File
import java.io.File;
public class DeleteFileExample {
public static void main(String[] args) {
File file = new File("output.txt");
if (file.delete()) {
System.out.println("File deleted successfully.");
} else {
System.out.println("Failed to delete the file.");
}
}
}
📌 Ensure the file is closed before deleting.
9. Comparison of File Handling Classes
Class Used For Best Feature
File File operations (existence, size, delete) Check & delete files
FileWriter Writing characters Simple writing
FileReader Reading characters Simple reading
BufferedWriter Writing with buffering Faster writing
BufferedReader Reading line-by-line Faster reading
PrintWriter Writing with formatting printf() support
55
SRI KALISWARI COLLEGE (Autonomous), SIVAKASI
DEPARTMENT OF COMPUTER APPLICATIONS
CORE COURSE – V: JAVA PROGRAMMING (23UCAC31)
UNIT – IV
AWT Controls: The AWT Class Hierarchy – User Interface Components – Labels –
Button – Text Components – Check Box – Check Box Group – Choice – List Box – Panels –
Scroll Pane – Menu – Scroll Bar. Working with Frame Class – Colour – Fonts and Layout
Managers. Event Handling: Events – Event Sources – Event Listeners – Event Delegation
Model (EDM) – Handling Mouse and Keyboard Events – Adapter Classes – Inner Classes.
JAVA AWT
Java AWT (Abstract Window Toolkit) is an API used to create Graphical User
Interface (GUI) or Windows-based Java programs
Java AWT components are platform-dependent.
The java.awt package contains AWT API classes
The AWT Class Hierarchy
Components: AWT provides various components such as buttons, labels, text
fields, checkboxes, etc used for creating GUI elements for Java Applications.
Containers: AWT provides containers like panels, frames, and dialogues to
organize and group components in the Application.
Layout Managers: Layout Managers are responsible for arranging data in the
containers some of the layout managers are BorderLayout, FlowLayout, etc.
Event Handling: AWT allows the user to handle the events like mouse clicks, key
presses, etc. using event listeners and adapters.
Graphics and Drawing: It is the feature of AWT that helps to draw shapes,
insert images and write text in the components of a Java Application.
Types of Containers in Java AWT
There are four types of containers in Java AWT:
1. Window: Window is a top-level container that represents a graphical window or
dialog box. The Window class extends the Container class, which means it can
contain other components, such as buttons, labels, and text fields.
2. Panel: Panel is a container class in Java. It is a lightweight container that can be
used for grouping other components together within a window or a frame.
3. Frame: The Frame is the container that contains the title bar and border and can
have menu bars.
4. Dialog: A dialog box is a temporary window an application creates to retrieve
user input.
*************************
User Interface Components
1. Labels
Label is used to display the static text
Labels are passive controls that do not support any interaction with the user
Constructors to Create Label
Label( ) - Creates a blank label
Label(String str) - creates a label that contains the string specified by str. This
string is left-justified
Label(String str, int how) - creates a label that contains the string specified by
str using the alignment specified by how. The value of how must be one of these
three constants: Label.LEFT, Label.RIGHT, or Label.CENTER.
Methods of Label Control
void setText(String str)
String getText( )
void setAlignment(int how)
int getAlignment( )
Example
import java.awt.*;
import java.applet.*;
/*
<applet code="LabelDemo" width=300 height=200>
</applet>
*/
public class LabelDemo extends Applet
{
public void init()
{
Label one = new Label("One");
Label two = new Label("Two");
Label three = new Label("Three");
// add labels to applet window
add(one);
add(two);
add(three);
}
}
******************
2. Buttons
The most widely used control is the push button.
A push button is a component that contains a label and that generates an event
when it is pressed.
Push buttons are objects of type Button.
Constructors for Button Control
Button defines these two constructors:
Button( )
Button(String str)
Methods for Button Control
String getLabel()
void setLabel(String str)
void setEnabled(Boolean enable)
Void addActionListener(ActionListener l)
void removeActionListener(ActionListener l)
String getActionCommand()
void setActionCommand(String Cmd)
Example
import java.awt.*;
import java.applet.*;
/*
<applet code="ButtonDemo" width=250 height=150>
</applet>
*/
public class ButtonDemo extends Applet
{
String msg = "";
Button yes, no, maybe;
public void init()
{
yes = new Button("Yes");
no = new Button("No");
maybe = new Button(“Understand");
add(yes);
add(no);
add(maybe);
}
public void paint(Graphics g)
{
g.drawString(msg, 6, 100);
}
}
********************
3. Check Box
Control which allows the user to choose more than one option
Constructors for Check Box Control
Checkbox( )
Checkbox(String str)
Checkbox(String str, boolean on)
Checkbox(String str, boolean on, CheckboxGroup cbGroup)
Checkbox(String str, CheckboxGroup cbGroup, boolean on)
Methods for Check Box Control
boolean getState( )
void setState(boolean on)
String getLabel( )
void setLabel(String str)
void addItemListener(ItemListener l)
void removeItemListener(ItemListener l)
Example
import java.awt.*;
import java.applet.*;
/*
<applet code="CheckboxDemo" width=250 height=200>
</applet>
*/
public class CheckboxDemo extends Applet
{
String msg = "";
Checkbox Win98, winNT, solaris, mac;
public void init()
{
Win98 = new Checkbox("Windows 98/XP", null, true);
winNT = new Checkbox("Windows NT/2000");
solaris = new Checkbox("Solaris");
mac = new Checkbox("MacOS");
add(Win98);
add(winNT);
add(solaris);
add(mac);
}
public void paint(Graphics g)
{}
}
*********************
4. Checkbox Group
It is possible to create a set of mutually exclusive check boxes in which one and
only one check box in the group can be checked at any one time.
These check boxes are often called radio button.
Check box groups are objects of type CheckboxGroup.
Only the default constructor is defined, which creates an empty group.
Methods for Checkbox Group Control
Checkbox getSelectedCheckbox( )
void setSelectedCheckbox(Checkbox wh)
Example
import java.awt.*;
import java.applet.*;
/*
<applet code="CBGroup"
width=250 height=200>
</applet>
*/
public class CBGroup extends Applet
{
String msg = "";
Checkbox Win98, winNT,
solaris, mac;
CheckboxGroup cbg;
public void init()
{
cbg = new CheckboxGroup();
Win98 = new Checkbox("Windows 98/XP", cbg, true);
winNT = new Checkbox("Windows NT/2000", cbg, false);
solaris = new Checkbox("Solaris", cbg, false);
mac = new Checkbox("MacOS", cbg, false);
add(Win98); add(winNT);
add(solaris); add(mac);
}
public void paint(Graphics g)
{
msg = "Current selection: ";
msg += cbg.getSelectedCheckbox().getLabel();
g.drawString(msg, 6, 100);
}
}
5. Choice Control
The Choice class is used to create a pop-up list of items from which the user may
choose.
Thus, a Choice control is a form of menu.
Each item in the list is a string that appears as a left justified label in the order it
is added to the Choice object.
Methods for Choice Control
void add(String name)
String getSelectedItem( )
int getSelectedIndex( )
int getItemCount( )
void select(int index)
void select(String name)
String getItem(int index)
Example
import java.awt.*;
import java.applet.*;
/*
<applet code="ChoiceDemo" width=300 height=180>
</applet>
*/
public class ChoiceDemo extends Applet
{
Choice os, browser;
String msg = "";
public void init()
{
os = new Choice();
browser = new Choice();
os.add("Windows 98/XP");
os.add("Windows NT/2000");
os.add("Solaris");
os.add("MacOS");
browser.add("Netscape 3.x");
browser.add("Netscape 4.x");
browser.add("Netscape 5.x");
browser.add("Netscape 6.x");
browser.add("Internet Explorer 4.0");
browser.add("Internet Explorer 5.0");
browser.add("Internet Explorer 6.0");
browser.add("Lynx 2.4");
browser.select("Netscape 4.x");
add(os);
add(browser);
}
public void paint(Graphics g)
{}}
**************************
6. List Control
The List class provides a compact, multiple-choice, scrolling selection list.
Unlike the Choice object, which shows only the single selected item in the menu,
a List object can be constructed to show any number of choices in the visible
Window.
It can also be created to allow multiple selections.
Constructors for List Control
List( ) - creates a List control that allows only one item to be selected at any one
time
List(int numRows) - the value of numRows specifies the number of entries in
the list that will always be visible
List(int numRows, boolean multipleSelect) - if multipleSelect is true, then the
user may select two or more items at a time
Methods for List Control
void add(String name)
void add(String name, int index)
String getSelectedItem( )
int getSelectedIndex( )
String[ ] getSelectedItems( )
int[ ] getSelectedIndexes( )
int getItemCount( )
void select(int index)
String getItem(int index)
***********************
7. Scroll Bar
Scroll bars are used to select continuous values between a specified minimum
and maximum.
Scroll bars may be oriented horizontally or vertically.
A scroll bar is actually a composite of several individual parts.
o slider box (or thumb) for the scroll bar.
The slider box can be dragged by the user to a new position, this action
translates into some form of page up and page down.
Constructors for Scroll Bar
Scrollbar( ) - creates a vertical scroll bar
Scrollbar(int style) - Allow us to specify style Scrollbar.VERTICAL,
Scrollbar.HORIZONTAL
Scrollbar(int style, int iValue, int tSize, int min, int max) - The initial value of
the scroll bar is passed in iValue. The number of units represented by the height
of the thumb is passed in tSize. The minimum and maximum values for the scroll
bar are specified by min and max
Methods for Scroll Bar
void setValues(int iValue, int tSize, int min, int max)
int getValue( )
void setValue(int newValue)
int getMinimum( )
int getMaximum( )
void setUnitIncrement(int newIncr)
void setBlockIncrement(int newIncr)
**************************
8. Text Component
It is used to get the input from user
There are 2 types of text component
1. Textfield
2. Textarea
1. Textfield
The TextField class implements a single-line text-entry area, called an edit
control.
Text fields allow the user to enter strings and to edit the text using the arrow
keys, cut and paste keys, and mouse selections.
TextField is a subclass of TextComponent.
Constructors for Textfield Control
TextField( )
TextField(int numChars)
TextField(String str)
TextField(String str, int numChars)
Methods for Textfield Control
String getText( )
void setText(String str)
String getSelectedText( )
void select(int startIndex, int endIndex)
boolean isEditable( )
void setEditable(boolean canEdit)
void setEchoChar(char ch)
boolean echoCharIsSet( )
char getEchoChar( )
2. Textarea
Sometimes a single line of text input is not enough for a given task. To handle
these situations, the AWT includes a simple multiline editor called TextArea.
Following are the constructors for TextArea:
TextArea( )
TextArea(int numLines, int numChars)
TextArea(String str)
TextArea(String str, int numLines, int numChars)
TextArea(String str, int numLines, int numChars, int sBars)
Methods for Textarea Control
TextArea is a subclass of TextComponent.
Therefore, it supports the getText( ), setText( ), getSelectedText( ), select( ),
isEditable( ), and setEditable( ) methods as of TextField.
TextArea adds the following methods:
void append(String str)
void insert(String str, int index)
void replaceRange(String str, int startIndex, int endIndex)
******************************
Menu Bars and Menus
A menu bar displays a list of top-level menu choices. Each choice is associated
with a dropdown menu.
This concept is implemented in Java by the following classes:
MenuBar, Menu, and MenuItem.
In general, a menu bar contains one or more Menu objects. Each Menu object
contains a list of MenuItem objects.
Each MenuItem object represents something that can be selected by the user.
MenuBar Class Defines only default constructor.
Menu Class Constructors
1. Menu( )
2. Menu(String optionName)
3. Menu(String optionName, boolean removable)
Here, optionName specifies the name of the menu selection.
Individual menu items constructors:
1. MenuItem( )
2. MenuItem(String itemName)
3. MenuItem(String itemName, MenuShortcut keyAccel)
Methods
Disable or enable a menu item by using:
1. void setEnabled(boolean enabledFlag)
2. boolean isEnabled( )
Label set and get using:
1. void setLabel(String newName)
2. String getLabel( )
Checkable menu item by using a subclass of MenuItem called
CheckboxMenuItem:
1. CheckboxMenuItem( )
2. CheckboxMenuItem(String itemName)
3. CheckboxMenuItem(String itemName, boolean on)
Status about checkable MenuItem:
1. boolean getState( )
2. void setState(boolean checked)
For add MenuItem:
1. MenuItem add(MenuItem item)
For add MenuBar
1. Menu add(Menu menu)
To get Item from Menu:
1. Object getItem( )
Example
import java.awt.*;
class MenuExample
{
MenuExample(){
Frame f= new Frame("Menu Example");
MenuBar mb=new MenuBar();
Menu menu=new Menu("Menu");
Menu submenu=new Menu("Sub Menu");
MenuItem i1=new MenuItem("Item 1");
MenuItem i2=new MenuItem("Item 2");
MenuItem i3=new MenuItem("Item 3");
MenuItem i4=new MenuItem("Item 4");
MenuItem i5=new MenuItem("Item 5");
menu.add(i1);
menu.add(i2); menu.add(i3); submenu.add(i4);
submenu.add(i5);
menu.add(submenu);
mb.add(menu);
f.setMenuBar(mb);
f.setSize(400,400);
f.setLayout(null);
f.setVisible(true);
}
public static void main(String args[]) {
new MenuExample();
} }
************************
Layout Managers
Layout means arranging the components within the container.
The task of lay outing can be done automatically by the Layout manager.
The layout manager is set by the setLayout( ) method.
If no call to setLayout( ) is made, then the default layout manager is used.
Whenever a container is resized (or sized for the first time), the layout manager
is used to position each of the components within it.
The setLayout( ) method has the following general form:
void setLayout(LayoutManager layoutObj)
Here, layoutObj is a reference to the desired layout manager.
If we wish to disable the layout manager and position components manually,
pass null for layoutObj.
There are following classes that represents the layout managers:
1. FlowLayout
2. BorderLayout
3. GridLayout
4. CardLayout
5. GridBagLayout
1. Flow Layout
FlowLayout is the default layout manager.
FlowLayout implements a simple layout style, which is similar to how words
flow in a text editor.
Components are laid out from the upper-left corner, left to right and top to
bottom.
When no more components fit on a line, the next one appears on the next line.
A small space is left between each component, above and below, as well as left
and right.
Constructors for FlowLayout
FlowLayout( ) - centers components and leaves five pixels of space between
each component.
FlowLayout(int how) - lets us specify how each line is aligned. Valid values for
how are as follows:
1. FlowLayout.LEFT
2. FlowLayout.CENTER
3. FlowLayout.RIGHT
FlowLayout(int how, int horz, int vert) - allows us to specify the horizontal
and vertical space left between components
Example
public class FlowLayoutDemo extends Applet
{
Checkbox Win98, winNT, solaris, mac;
public void init()
Win98 = new Checkbox("Windows 98/XP", null, true);
winNT = new Checkbox("Windows NT/2000");
solaris = new Checkbox("Solaris");
mac = new Checkbox("MacOS");
setLayout(new FlowLayout(FlowLayout.CENTER));
add(Win98); add(winNT);add(solaris);add(mac);
}}
2. Border Layout
The BorderLayout class implements a common layout style for top-level
windows.
It has four narrow, fixed-width components at the edges and one large area in
the center.
The four sides are referred to as
1. north,
2. south,
3. east, and
4. west.
The middle area is called the center.
BorderLayout defines the following constants that specify the regions:
1. BorderLayout.CENTER
2. BorderLayout.SOUTH
3. BorderLayout.EAST
4. BorderLayout.WEST
5. BorderLayout.NORTH
To add components, we use these constants with the following form of add( ),
which is defined by Container:
void add(Component compObj, Object region);
Here, compObj is the component to be added, and region specifies where the
component will be added.
Constructors for Border Layout
BorderLayout( ) - creates a default border layout
BorderLayout(int horz, int vert) - allows us to specify the horizontal and
vertical space left between components in horz and vert, respectively
Example
public class BorderLayoutDemo extends Applet {
public void init() {
setLayout(new BorderLayout());
add(new Button("This is across the top."), BorderLayout.NORTH);
add(new Label("The footer message."), BorderLayout.SOUTH);
add(new Button("Right"), BorderLayout.EAST);
add(new Button("Left"), BorderLayout.WEST);
String msg = "The reasonable man adapts himself to the world;\n" +
"the unreasonable one persists in trying to adapt the world to himself.\n"
+
"Therefore all progress depends on the unreasonable man.\n\n" + " -
George Bernard Shaw\n\n";
add(new TextArea(msg), BorderLayout.CENTER);
}
}
3. Grid Layout
GridLayout lays out components in a two-dimensional grid.
When we instantiate a GridLayout, we define the number of rows and columns.
Constructors for Grid Layout
GridLayout( ) - creates a single-column grid layout
GridLayout(int numRows, int numColumns ) - creates a grid layout with
specified number of rows and columns
GridLayout(int numRows, int numColumns, int horz, int vert)
Example
public class GridLayoutDemo extends Applet {
static final int n = 4;
public void init(){
setLayout(new GridLayout(n, n));
setFont(new Font("SansSerif", Font.BOLD, 24));
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
int k = i * n + j;
if(k > 0)
add(new Button("" + k));
} }}}
4. Card Layout
The CardLayout class is unique among the other layout managers in that it stores
several different layouts.
Each layout can be thought of as being on a separate index card in a deck that can
be shuffled so that any card is on top at a given time.
This can be useful for user interfaces with optional components that can be
dynamically enabled and disabled upon user input.
We can prepare the other layouts and have them hidden, ready to be activated
when needed
Constructors for Card Layout
CardLayout provides these two constructors:
CardLayout( ) - creates a default card layout
CardLayout(int horz, int vert) - allows us to specify the horizontal and vertical
space left between components
Methods
void add(Component panelObj, Object name);
Here name is a string that specifies the name of the card whose panel is specified
by panelObj. After we have created a deck, our program activates a card by
calling one of the following methods:
1. void first(Container deck)
2. void last(Container deck)
3. void next(Container deck)
4. void previous(Container deck)
5. void show(Container deck, String cardName)
deck is a reference to the container (usually a panel) that holds the cards, and
cardName is the name of a card.
Example
import java.awt.*;
import java.awt.event.*;
public class CardLayoutExample extends Frame implements ActionListener{
CardLayout card;
Button b1,b2,b3;
CardLayoutExample(){
card=new CardLayout(40,30);
setLayout(card);
b1=new Button("Apple");
b2=new Button("Boy");
b3=new Button("Cat");
b1.addActionListener(this);
b2.addActionListener(this);
b3.addActionListener(this);
add(b1,”card1”); add(b2,”card2”); add(b3,”card3”); }
public void actionPerformed(ActionEvent e) {
card.next(this);
}
public static void main(String[] args) {
CardLayoutExample cl=new CardLayoutExample();
cl.setSize(400,400);
cl.setVisible(true);
} }
5. GridBag Layout
Each GridBagLayout object maintains a dynamic rectangular grid of cells, with
each component occupying one or more cells, called its display area.
Each component managed by a grid bag layout is associated with an instance of
GridBagConstraints that specifies how the component is laid out within its
display area
For customize a GridBagConstraints object by setting one or more of its instance
variables:
gridx, gridy: Specifies the cell at the upper left of the component's display area,
where the upper-left-most cell has address gridx = 0, gridy = 0.
gridwidth, gridheight: Specifies the number of cells in a row (for gridwidth) or
column (for gridheight) in the component's display area. The default value is 1.
fill: Used when the component's display area is larger than the component's
requested size to determine whether (and how) to resize the component.
Example
import java.awt.*;
import java.util.*;
import java.applet.Applet;
public class GridBagEx1 extends Applet {
protected void makebutton(String name,
GridBagLayout gridbag,
GridBagConstraints c) {
Button button = new Button(name);
gridbag.setConstraints(button, c);
add(button);
}
public void init() {
GridBagLayout gridbag = new GridBagLayout();
GridBagConstraints c = new GridBagConstraints();
setLayout(gridbag);
c.fill = GridBagConstraints.BOTH;
c.weightx = 1.0;
makebutton("Button1", gridbag, c);
makebutton("Button2", gridbag, c);
makebutton("Button3", gridbag, c);
c.gridwidth = GridBagConstraints.REMAINDER; //end row
makebutton("Button4", gridbag, c);
c.weightx = 0.0; //reset to the default
makebutton("Button5", gridbag, c); //another row
}
public static void main(String args[]) {
Frame f = new Frame("GridBag Layout Example");
GridBagEx1 ex1 = new GridBagEx1();
ex1.init(); f.add("Center", ex1); f.pack();
f.resize(f.preferredSize());
f.show(); } }
**************************
Working with Color
Color is encapsulated by the Color class.
Color defines several constants to specify a number of common colors.
We can create our own colors, using one of the Color constructors.
Color( int red, int green, int blue)
Color( int rgbValue)
Color( float red, float green, float blue)
these values must be between 0 and 255.
eg. new Color(255, 100, 100); //light red
Color Methods
Using Hue, Saturation and Brightness
The Hue-Saturation-Brightness(HSB) color model is an alternative to Red-Green
Blue(RGB) for specifying particular colors.
Hue
is a wheel of Color
specified with a number between 0.0 and 1.0
colors approximately red, orange, yellow, green, blue, indigo and violet.
Saturation
scale ranging from 0.0 to 1.0 representing light pastels to intense hues.
Brightness
range from 0.0 to 1.0 where 1 is bright white and 0 is black.
Color supplies two methods to convert between RGB and HSB
o static int HSBtoRGB(float hue, float saturation, float brightness)
o static float[ ] RGBtoHSB(int red, int green, int blue, float values[ ])
RGBtoHSB( ) returns a float array of HSB values corresponding to RGB integers
o the array contains the hue at index 0, saturation at index 1, and brightness
at index 2.
Setting the current Graphics Color
void setColor(Color newColor)
o newColor -> specifies the new drawing color
Color getColor( )
o to obtain the current color
*********************
Working with Fonts
The AWT supports multiple type fonts.
Fonts have a family name, a logical font name and a face name.
family name -> general name of font. Eg. Courier
logical name -> category of font. Eg. Monospaced
face name -> specific font. Eg. Courier Italic
Fonts are encapsulated by the Font class.
Methods (refer book)
The Font class defines these variables
String name – name of the font
float pointSize – size of the font in points
int size – size of the font in points
int style – font style
Determining the Available Fonts
String[ ] getAvailableFontFamilyNames( )
Font[ ] getAllFonts( )
Creating and Selecting a Font
Font constructor
Font(String fontName, int fontStyle, int pointSize)
fontName
name of the desired font
Dialog, DialogInput, SansSerif, Serif and Monospaced supported by all Java
environments
default -> Dialog
fontStyle
style of the font
3 constants (Font.PLAIN, Font.BOLD, Font.ITALIC)
can be ORed together
eg. Font.BOLD | Font.ITALIC
pointSize -> size of the font in points
Obtaining Font Information
Font getFont( )
To obtain information about the currently selected font.
defined by the Graphics class
************************
SWINGS: Introduction to Swings, Hierarchy of swing components.
Containers, Top level containers - JFrame, JWindow, JDialog, JPanel,
JButton, JToggleButton, JCheckBox, JRadioButton, JLabel,JTextField,
JTextArea, JList, JComboBox, JScrollPane.APPLETS: Life cycle of an Applet,
Differences between Applets and Applications, Developing applets, simple
applet.
SWINGS
Introduction to Swings:
Java Swing is a part of Java Foundation Classes (JFC) that is used to create
window-based applications. It is built on the top of AWT (Abstract
Windowing Toolkit) API and entirely written in java.
Unlike AWT, Java Swing provides platform-independent and lightweight
components.
javax.swing package will provide complete swing components.
Swing in Java is a Graphical User Interface (GUI) toolkit that includes the
GUI components. Swing provides a rich set of widgets and packages to
make GUI components for Java applications.
What is JFC
The Java Foundation Classes (JFC) are a set of GUI components which
simplify the development of desktop applications.
Hierarchy of swing components:
A component is an independent visual control and Java Swing Framework
contains a large set of these components which provide rich functionalities
and allow high level of customization.
They all are derived from JComponent class. All these components are
lightweight components.
A container holds a group of components. It provides a space where a
component can be managed and displayed.
Container classes are classes that can have other components on it. So for
creating a Java Swing GUI, we need at least one container object.
Panel
JPanel is the simplest container. It provides space in which any other
component can be placed, including other panels.
Frame
A JFrame is a top-level window with a title and a border.
Dialog: It can be thought of like a pop-up window that pops out when a
message has to be displayed. It is not a fully functioning window like the
Frame
Window
A JWindow object is a top-level window with no borders and no menubar.
Java Swing Examples
There are two ways to create a frame:
o By creating the object of Frame class (association)
o By extending Frame class (inheritance)
1.By creating the object of Frame class (association)
o import javax.swing.*;
o public class FirstSwingExample {
o public static void main(String[] args) {
o JFrame f=new JFrame();//creating instance of JFrame
o
o JButton b=new JButton("click");//creating instance of JButton
o b.setBounds(130,100,100, 40);//x axis, y axis, width, height
o
o f.add(b);//adding button in JFrame
o
o f.setSize(400,500);//400 width and 500 height
o f.setLayout(null);//using no layout managers
o f.setVisible(true);//making the frame visible
o } }
2.By extending Frame class (inheritance)
import javax.swing.*;
public class Simple2 extends JFrame
{
//inheriting JFrame
JFrame f;
Simple2()
{
JButton b=new JButton("click");//create button
b.setBounds(130,100,100, 40);
add(b);//adding button on frame
setSize(400,500);
setLayout(null);
setVisible(true); }
public static void main(String[] args) {
new Simple2();
}}
output:
JFrame:
The javax.swing.JFrame class is a type of container which inherits the
java.awt.Frame class. JFrame works like the main window where
components like labels, buttons, textfields are added to create a GUI.
Unlike Frame, JFrame has the option to hide or close the window with the
help of setDefaultCloseOperation(int) method.
1. import java.awt.FlowLayout;
2. import javax.swing.JButton;
3. import javax.swing.JFrame;
4. import javax.swing.JLabel;
5. import javax.swing.JPanel;
6. public class JFrameExample {
7. public static void main(String s[]) {
8. JFrame frame = new JFrame("JFrame Example");
9. JPanel panel = new JPanel();
10. panel.setLayout(new FlowLayout());
11. JLabel label = new JLabel("JFrame By Example");
12. JButton button = new JButton();
13. button.setText("Button");
14. panel.add(label);
15. panel.add(button);
16. frame.add(panel);
17. frame.setSize(200, 300);
18. frame.setLocationRelativeTo(null);
19. frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
20. frame.setVisible(true);
21. } }
Output
JWindow:
JWindow is a part of Java Swing and it can appear on any part of the users
desktop. It is different from JFrame in the respect that JWindow does not
have a title bar or window management buttons like minimize, maximize,
and close. JWindow can contain several components such as buttons and
labels.
import java.awt.*;
import javax.swing.*;
public class JWindowExample {
public static void main(String[] args) {
JWindow window = new JWindow();
int width = 100;
int height = 50;
window.setBounds(100,50,100,50);
JLabel label = new JLabel("Hello");
window.add(label);
window.setVisible(true);
}}
Output:
JDialog:
The JDialog control represents a top level window with a border and a title
used to take some form of input from the user. It inherits the Dialog class.
Unlike JFrame, it doesn't have maximize and minimize buttons.
public class JDialog extends Dialog implements WindowConstants, Acces
sible, RootPaneContainer
1. import javax.swing.*;
2. import java.awt.*;
3. import java.awt.event.*;
4. public class DialogExample {
5. private static JDialog d;
6. DialogExample() {
7. JFrame f= new JFrame();
8. d = new JDialog(f , "Dialog Example", true);
9. d.setLayout( new FlowLayout() );
10. JButton b = new JButton ("OK");
11. b.addActionListener ( new ActionListener()
12. {
13. public void actionPerformed( ActionEvent e )
14. {
15. DialogExample.d.setVisible(false);
16. }
17. });
18. d.add( new JLabel ("Click button to continue."));
19. d.add(b);
20. d.setSize(300,300);
21. d.setVisible(true);
22. }
23. public static void main(String args[])
24. {
25. new DialogExample();
26. }}
Output:
JPanel:
The JPanel is a simplest container class. It provides space in which an
application can attach any other component. It inherits the JComponents
class.
public class JPanel extends JComponent implements Accessible
1. import java.awt.*;
2. import javax.swing.*;
3. public class PanelExample {
4. PanelExample()
5. {
6. JFrame f= new JFrame("Panel Example");
7. JPanel panel=new JPanel();
8. panel.setBounds(40,80,200,200);
9. panel.setBackground(Color.gray);
10. JButton b1=new JButton("Button 1");
11. b1.setBounds(50,100,80,30);
12. b1.setBackground(Color.yellow);
13. JButton b2=new JButton("Button 2");
14. b2.setBounds(100,100,80,30);
15. b2.setBackground(Color.green);
16. panel.add(b1); panel.add(b2);
17. f.add(panel);
18. f.setSize(400,400);
19. f.setLayout(null);
20. f.setVisible(true);
21. }
22. public static void main(String args[])
23. {
24. new PanelExample();
25. } }
Output:
JButton:
The JButton class is used to create a labeled button that has platform
independent implementation.
Button Class Declaration:
public class JButton extends AbstractButton implements Accessible
Example:
import javax.swing.*;
public class ButtonExample {
public static void main(String[] args) {
JFrame f=new JFrame("Button Example");
JButton b=new JButton("Click Here");
b.setBounds(50,100,95,30);
f.add(b);
f.setSize(400,400);
f.setLayout(null);
f.setVisible(true);
} }
Output:
JCheckBox:
The JCheckBox class is used to create a checkbox. It is used to turn an
option on (true) or off (false). Clicking on a CheckBox changes its state from
"on" to "off" or from "off" to "on ".It inherits JToggleButton class.
public class JCheckBox extends JToggleButton implements Accessible
1. import javax.swing.*;
2. public class CheckBoxExample
3. {
4. CheckBoxExample(){
5. JFrame f= new JFrame("CheckBox Example");
6. JCheckBox checkBox1 = new JCheckBox("C++");
7. checkBox1.setBounds(100,100, 50,50);
8. JCheckBox checkBox2 = new JCheckBox("Java", true);
9. checkBox2.setBounds(100,150, 50,50);
10. f.add(checkBox1);
11. f.add(checkBox2);
12. f.setSize(400,400);
13. f.setLayout(null);
14. f.setVisible(true);
15. }
16. public static void main(String args[])
17. {
18. new CheckBoxExample();
19. }}
Output:
JRadioButton:
The JRadioButton class is used to create a radio button. It is used to choose
one option from multiple options. It is widely used in exam systems or quiz.
It should be added in ButtonGroup to select one radio button only
public class JRadioButton extends JToggleButton implements Accessible
1. import javax.swing.*;
2. public class RadioButtonExample {
3. JFrame f;
4. RadioButtonExample(){
5. f=new JFrame();
6. JRadioButton r1=new JRadioButton("A) Male");
7. JRadioButton r2=new JRadioButton("B) Female");
8. r1.setBounds(75,50,100,30);
9. r2.setBounds(75,100,100,30);
10. ButtonGroup bg=new ButtonGroup();
11. bg.add(r1);bg.add(r2);
12. f.add(r1);f.add(r2);
13. f.setSize(300,300);
14. f.setLayout(null);
15. f.setVisible(true);
16. }
17. public static void main(String[] args) {
18. new RadioButtonExample();
19. } }
Output:
JLabel:
The object of JLabel class is a component for placing text in a container. It is
used to display a single line of read only text. The text can be changed by an
application but a user cannot edit it directly. It inherits JComponent class.
public class JLabel extends JComponent implements SwingConstants, Acc
essible
1. import javax.swing.*;
2. class LabelExample
3. {
4. public static void main(String args[])
5. {
6. JFrame f= new JFrame("Label Example");
7. JLabel l1,l2;
8. l1=new JLabel("First Label.");
9. l1.setBounds(50,50, 100,30);
10. l2=new JLabel("Second Label.");
11. l2.setBounds(50,100, 100,30);
12. f.add(l1); f.add(l2);
13. f.setSize(300,300);
14. f.setLayout(null);
15. f.setVisible(true);
16. } }
Output:
JTextField:
JTextField is used for taking input of single line of text. It is most widely
used text component.
Class declaration:
public class JTextField extends JTextComponent implements SwingConst
ant
1. import javax.swing.*;
2. class TextFieldExample
3. {
4. public static void main(String args[])
5. {
6. JFrame f= new JFrame("TextField Example");
7. JTextField t1,t2;
8. t1=new JTextField("Welcome to Javatpoint.");
9. t1.setBounds(50,100, 200,30);
10. t2=new JTextField("AWT Tutorial");
11. t2.setBounds(50,150, 200,30);
12. f.add(t1); f.add(t2);
13. f.setSize(400,400);
14. f.setLayout(null);
15. f.setVisible(true);
16. } }
Output:
JTextArea:
The object of a JTextArea class is a multi line region that displays text. It
allows the editing of multiple line text. It inherits JTextComponent class.
public class JTextArea extends JTextComponent
1. import javax.swing.*;
2. public class TextAreaExample
3. {
4. TextAreaExample(){
5. JFrame f= new JFrame();
6. JTextArea area=new JTextArea("Welcome to javatpoint");
7. area.setBounds(10,30, 200,200);
8. f.add(area);
9. f.setSize(300,300);
10. f.setLayout(null);
11. f.setVisible(true);
12. }
13. public static void main(String args[])
14. {
15. new TextAreaExample();
16. }}
Output:
JList:
The object of JList class represents a list of text items. The list of text items
can be set up so that the user can choose either one item or multiple items.
It inherits JComponent class.
public class JList extends JComponent implements Scrollable, Accessible
1. import javax.swing.*;
2. public class ListExample
3. {
4. ListExample(){
5. JFrame f= new JFrame();
6. DefaultListModel<String> l1 = new DefaultListModel<>();
7. l1.addElement("Item1");
8. l1.addElement("Item2");
9. l1.addElement("Item3");
10. l1.addElement("Item4");
11. JList<String> list = new JList<>(l1);
12. list.setBounds(100,100, 75,75);
13. f.add(list);
14. f.setSize(400,400);
15. f.setLayout(null);
16. f.setVisible(true);
17. }
18. public static void main(String args[])
19. {
20. new ListExample();
21. }}
Output:
JComboBox:
The object of Choice class is used to show popup menu of choices. Choice
selected by user is shown on the top of a menu. It
inherits JComponent class.
public class JComboBox extends JComponent implements ItemSelectable,
ListDataListener, ActionListener, Accessible
1. import javax.swing.*;
2. public class ComboBoxExample {
3. JFrame f;
4. ComboBoxExample(){
5. f=new JFrame("ComboBox Example");
6. String country[]={"India","Aus","U.S.A","England","Newzealand"};
7. JComboBox cb=new JComboBox(country);
8. cb.setBounds(50, 50,90,20);
9. f.add(cb);
10. f.setLayout(null);
11. f.setSize(400,500);
12. f.setVisible(true);
13. }
14. public static void main(String[] args) {
15. new ComboBoxExample();
16. } }
Output:
JScrollPane:
A JscrollPane is used to make scrollable view of a component. When screen
size is limited, we use a scroll pane to display a large component or a
component whose size can change dynamically.
1. import java.awt.FlowLayout;
2. import javax.swing.JFrame;
3. import javax.swing.JScrollPane;
4. import javax.swing.JtextArea;
5. public class JScrollPaneExample {
6. private static final long serialVersionUID = 1L;
7. private static void createAndShowGUI() {
8. // Create and set up the window.
9. final JFrame frame = new JFrame("Scroll Pane Example");
10. // Display the window.
11. frame.setSize(500, 500);
12. frame.setVisible(true);
13. frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
14. // set flow layout for the frame
15. frame.getContentPane().setLayout(new FlowLayout());
16. JTextArea textArea = new JTextArea(20, 20);
17. JScrollPane scrollableTextArea = new JScrollPane(textArea
);
18. scrollableTextArea.setHorizontalScrollBarPolicy(JScrollPane.H
ORIZONTAL_SCROLLBAR_ALWAYS);
19. scrollableTextArea.setVerticalScrollBarPolicy(JScrollPane.VER
TICAL_SCROLLBAR_ALWAYS);
20. frame.getContentPane().add(scrollableTextArea);
21. }
22. public static void main(String[] args) {
23. javax.swing.SwingUtilities.invokeLater(new Runnable() {
24. public void run() {
25. createAndShowGUI();
26. }
27. });
28. } }
Output:
JToggleButton:
JToggleButton is used to create toggle button, it is two-states button to
switch on or off. The two states are selected and unselected.
The JRadioButton and JCheckBox classes are subclasses of this class. When
the user presses the toggle button, it toggles between being pressed or
unpressed.
1. import java.awt.FlowLayout;
2. import java.awt.event.ItemEvent;
3. import java.awt.event.ItemListener;
4. import javax.swing.JFrame;
5. import javax.swing.JToggleButton;
6.
7.public class JToggleButtonExample extends JFrame implements Ite
mListener {
8. public static void main(String[] args) {
9. new JToggleButtonExample();
10. }
11. private JToggleButton button;
12. JToggleButtonExample() {
13. setTitle("JToggleButton with ItemListener Example");
14. setLayout(new FlowLayout());
15. setJToggleButton();
16. setAction();
17. setSize(200, 200);
18. setVisible(true);
19. setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
20. }
21. private void setJToggleButton() {
22. button = new JToggleButton("ON");
23. add(button);
24. }
25. private void setAction() {
26. button.addItemListener(this);
27. }
28. public void itemStateChanged(ItemEvent eve) {
29. if (button.isSelected())
30. button.setText("OFF");
31. else
32. button.setText("ON");
33. } }
Output: