Java All Notes
Java All Notes
Introduction of Java:
1. Java is a versatile, object-oriented programming language
developed by Sun Microsystems in 1995.
2. Known for its platform independence, Java uses the "Write
Once, Run Anywhere" (WORA) principle, allowing programs to
run on any device with a Java Virtual Machine (JVM).
3. Its syntax is derived from C and C++, fostering familiarity for
developers.
4. Key features include automatic memory management through
garbage collection, strong type-checking, and a rich set of
libraries.
5. Java's portability, security features, and widespread use in web
development, mobile apps (Android), and enterprise systems
contribute to its enduring popularity in the software
development landscape.
History of Java:
The following points are explain the history of java :
1. Inception (1991):
Java's origins trace back to 1991 when James Gosling, Mike
Sheridan, and Patrick Naughton initiated the "Green Project" at
Sun Microsystems.
The team aimed to develop a new programming language for
consumer electronics.
2. Oak Language (1992):
Initially named "Oak," the language was designed for handheld
devices and set-top boxes.
It incorporated features like strong typing and garbage
collection.
3. Evolution to Java (1995):
1
In 1995, Oak was rebranded as Java to avoid trademark
conflicts with another company using the name "Oak."
The official release of Java took place, accompanied by the
slogan "Write Once, Run Anywhere."
4. Java 1.0 (1996):
The first official version, Java 1.0, was released, featuring
applets for web browsers and the HotJava browser.
Java quickly gained attention for its portability and platform
independence.
5. Introduction of JDK (1997):
The Java Development Kit (JDK) was introduced, providing tools
for Java development.
This marked a significant step in establishing Java as a
comprehensive development platform.
6. Java 2 Platform (1998):
The release of Java 2 (J2SE) introduced new features like the
Swing GUI toolkit and the Collections Framework.
This version laid the foundation for Java's growth in enterprise
development.
7. Enterprise Edition (J2EE) and Micro Edition (J2ME) (1999):
J2EE and J2ME were introduced, focusing on enterprise-level
and mobile application development, respectively.
These editions expanded Java's capabilities into diverse
computing environments.
8. Open Sourcing (2006):
Sun Microsystems open-sourced Java, making the source code
available to the public under the GNU General Public License
(GPL).
This move aimed to foster community involvement and
innovation.
9. Oracle's Acquisition (2010):
Oracle Corporation acquired Sun Microsystems, becoming the
steward of Java.
Java continued to evolve under Oracle's management, with
regular updates and improvements.
2
10. Java 8 and Beyond (2014 Onward):
Java 8 brought significant enhancements, including lambda
expressions and the Streams API.
Subsequent versions, like Java 9, 10, and beyond, introduced
modularization and ongoing language and platform
improvements.
Java and C++ are both powerful programming languages, but they
differ in several key aspects:
1. Platform Independence:
Java: Java follows the "Write Once, Run Anywhere" principle.
Java code is compiled into bytecode, which can run on any
device with a Java Virtual Machine (JVM), making it platform-
independent.
C++: C++ code is compiled into machine-specific binaries, which
may not be portable across different platforms without
recompilation.
2. Memory Management:
Java: Java uses automatic memory management through
garbage collection, which helps in handling memory allocation
and deallocation without explicit programmer intervention.
C++: C++ allows manual memory management using features
like new and delete, providing more control but also requiring
careful handling to prevent memory leaks or errors.
3. Object-Oriented Features:
Java: Java is purely object-oriented, and everything in Java is an
object. It enforces the use of classes and objects for program
structure.
C++: C++ supports both procedural and object-oriented
programming. While it has classes and objects, it allows for
procedural-style coding as well.
3
4. Pointers:
Java: Java does not have explicit pointers and does not support
pointer arithmetic, contributing to a more secure environment
with reduced risks of memory-related errors.
C++: C++ supports pointers and allows for direct manipulation
of memory addresses, providing more flexibility but also
increasing the potential for bugs and security vulnerabilities.
5. Multiple Inheritance:
Java: Java supports multiple inheritance through interfaces,
allowing a class to implement multiple interfaces. However, it
avoids the complications associated with multiple inheritance
in C++.
C++: C++ supports direct multiple inheritance, allowing a class
to inherit from more than one class. While powerful, this can
lead to the "diamond problem" and increased complexity.
6. Exception Handling:
Java: Java has a robust and consistent exception handling
mechanism, making it mandatory for developers to catch or
declare exceptions.
C++: C++ supports exception handling but does not enforce its
usage, providing developers with more flexibility but potentially
leading to less consistent error-handling practices.
JDK Tools:
The Java Development Kit (JDK) provides a set of tools that aid in
Java development. Some key JDK tools include:
4
1. javac (Java Compiler):
Compiles Java source code (.java files) into bytecode (.class
files) that can be executed by the Java Virtual Machine (JVM).
2. java (Java Interpreter):
Executes Java bytecode on the JVM. It takes the name of a class
as a parameter to run the main method of that class.
3. jar (Java Archive):
Creates and manages Java Archive (JAR) files, which are used to
package multiple Java class files, resources, and metadata into
a single compressed file.
4. javadoc (Java Documentation Generator):
Generates API documentation from Java source code
comments. It produces HTML pages documenting classes,
methods, and fields.
5. jdb (Java Debugger):
A command-line debugger for Java applications. Developers use
it to find and fix bugs by stepping through code, setting
breakpoints, and inspecting variables.
6. jconsole (Java Monitoring and Management Console):
A graphical tool for monitoring and managing Java applications.
It provides information about memory usage, thread activity,
and performance metrics.
7. jvisualvm (Java VisualVM):
A visual tool that integrates several JDK monitoring,
troubleshooting, and profiling utilities. It allows developers to
analyze the performance of Java applications.
8. jps (Java Process Status Tool):
Lists the instrumented HotSpot Java Virtual Machines on the
target system. It provides information about the Java processes
running, including their process IDs.
9. javap (Java Class File Disassembler):
Disassembles Java class files, providing a human-readable
representation of the bytecode instructions.
10. keytool (Key and Certificate Management Tool):
5
Manages keystores and certificates for secure communication
in Java applications. It is used to generate key pairs, create
certificates, and manage cryptographic keys.
11. javah (Java Header and Stub File Generator):
Generates C header files and C source files from Java class files,
facilitating the integration of Java code with native code.
Class File:
A class file in Java is a binary file that contains bytecode, which is the
intermediate representation of a Java source code file.
When you compile a Java source code file (with a .java extension)
using the Java compiler (javac), it produces a class file (with a .class
extension).
1. Bytecode:
The class file contains bytecode, a set of instructions
understood by the JVM. It is a low-level, platform-independent
representation of the Java source code.
2. Compilation Process:
After writing Java source code, you use the Java compiler
(javac) to compile it. This results in the creation of one or more
class files, each corresponding to a class defined in the source
code.
3. Platform Independence:
6
The Java programming language follows the "Write Once, Run
Anywhere" principle. Since class files contain bytecode, they
can be executed on any device with a compatible JVM,
regardless of the underlying hardware or operating system.
4. Execution by JVM:
When you run a Java program, the JVM loads the class files,
interprets the bytecode, and executes the instructions. This
process ensures that Java applications are portable across
different environments.
5. Structure:
Class files have a specific structure defined by the Java Virtual
Machine Specification. They include constant pools, method
information, field information, access flags, and more.
6. Debugging and Disassembly:
Tools like javap can be used to disassemble class files, providing
a human-readable representation of the bytecode instructions.
This can aid in understanding the structure and behavior of
Java programs.
7. Packaging in JAR Files:
Class files are often bundled together into Java Archive (JAR)
files for distribution. JAR files simplify the deployment of Java
applications by packaging multiple class files along with
resources and metadata.
Java Bytecode:
Java bytecode is an intermediate representation of a Java program
that is generated during the compilation process. It serves as an
abstraction layer between the Java source code and the native
machine code of the underlying hardware.
7
Here are key points about Java bytecode:
1. Generated by Compilation:
After writing Java source code (.java files), you use the Java
compiler (javac) to compile it. The result is a set of class files
containing Java bytecode.
2. Platform-Independent:
Java bytecode is designed to be platform-independent,
adhering to the "Write Once, Run Anywhere" (WORA) principle.
This means that the same bytecode can run on any device with
a Java Virtual Machine (JVM) without modification.
3. Intermediary Representation:
Bytecode is neither high-level source code nor machine-specific
native code. It is an intermediary representation that retains
the structure and logic of the original Java source code while
being independent of the underlying hardware.
4. Java Virtual Machine (JVM):
The JVM is responsible for executing Java bytecode. It
interprets the bytecode at runtime or, in some cases,
dynamically compiles it into native machine code for improved
performance.
5. Security:
The use of bytecode adds a layer of security to Java
applications. Before executing, the JVM can perform bytecode
verification to ensure that the code adheres to Java's safety and
security requirements.
6. Portability:
Since bytecode is platform-independent, Java applications can
be distributed in a single format and executed on various
devices and operating systems with a compatible JVM.
7. Debugging and Profiling:
Java bytecode can be inspected using tools like javap or
decompiled for debugging and profiling purposes. This allows
developers to understand the behavior of their Java programs
at a lower level.
8
8. Optimizations:
Just-in-time (JIT) compilers within the JVM can dynamically
translate bytecode into native machine code for improved
execution speed. This process allows the JVM to adapt to the
specific characteristics of the host system.
9. Structure:
Bytecode instructions are typically low-level operations,
representing actions such as method invocation, variable
manipulation, and control flow. The Java Virtual Machine
Specification defines the detailed structure and semantics of
bytecode.
JVM:
The Java Virtual Machine (JVM) is a key component of the Java
Runtime Environment (JRE) and Java Development Kit (JDK).
1. Execution Environment:
The JVM provides a runtime environment for Java applications
to run. It abstracts the underlying hardware and operating
system, allowing Java programs to be platform-independent.
2. Platform Independence:
One of the primary features of the JVM is its ability to execute
Java bytecode on any device that has a JVM installed. This
follows the "Write Once, Run Anywhere" (WORA) principle.
3. Interpretation and Just-in-Time Compilation:
9
The JVM can interpret Java bytecode on-the-fly, executing the
instructions one by one. Additionally, modern JVMs often
employ Just-in-Time (JIT) compilation, translating bytecode into
native machine code for improved performance during
runtime.
4. Memory Management:
The JVM handles memory allocation and garbage collection,
automatically managing the allocation and deallocation of
memory, reducing the risk of memory-related errors.
5. Security:
The JVM includes a security manager that enforces security
policies to protect against malicious activities. Bytecode
verification is performed before execution to ensure it adheres
to Java's safety requirements.
6. Class Loader:
The Class Loader is responsible for loading classes into the JVM.
It loads classes from the local file system or network, allowing
Java applications to dynamically load classes at runtime.
7. Execution of Bytecode:
The JVM executes Java bytecode, which is the compiled form of
Java source code. Bytecode is a set of instructions that the JVM
interprets or compiles into native machine code.
8. Java Native Interface (JNI):
The JVM supports the Java Native Interface, allowing Java code
to interact with applications and libraries written in other
languages, such as C and C++.
9. Monitoring and Management:
The JVM provides tools for monitoring and managing Java
applications. Tools like JConsole and VisualVM offer insights
into memory usage, thread activity, and overall performance.
10. HotSpot JVM:
The HotSpot JVM, developed by Oracle, is a widely used and
optimized JVM implementation that incorporates features like
adaptive optimization and garbage collection.
10
In summary, the JVM serves as a virtualized execution environment
for Java applications, ensuring platform independence, memory
management, security, and adaptability. It is a fundamental
component that enables the widespread use of Java across diverse
computing environments.
Identifiers:
Identifiers in programming are names given to various program
elements such as variables, methods, classes, packages, and more.
Here are key points about identifiers:
1. Definition:
An identifier is a sequence of characters in a program that is
used to name entities like variables, functions, classes, etc.
2. Rules for Naming:
Identifiers must begin with a letter (A-Z or a-z), underscore (_),
or a dollar sign ($).
After the first character, identifiers can also contain digits (0-9).
Uppercase and lowercase letters are distinct in most
programming languages, meaning "example" and "Example"
would be different identifiers.
3. Examples:
Valid identifiers: variable, _count, totalAmount,
calculateSum123.
Invalid identifiers: 123total, @special, class, as they violate
naming rules.
4. Case Sensitivity:
Most programming languages are case-sensitive, meaning
example and Example are considered different identifiers.
5. Reserved Words:
Certain words are reserved by programming languages and
cannot be used as identifiers. Examples include keywords like if,
while, and class.
6. Descriptive Naming:
11
Choosing meaningful and descriptive names for identifiers
enhances code readability and understanding.
7. CamelCase and SnakeCase:
CamelCase and SnakeCase are conventions for naming
identifiers. CamelCase capitalizes the first letter of each word
except the first, while SnakeCase separates words with
underscores.
8. Consistency:
Maintaining consistent naming conventions across a codebase
improves code clarity and makes it easier for developers to
collaborate.
9. Namespace:
Identifiers within different namespaces (like classes or
packages) can share the same name without conflict.
10. Scope:
The scope of an identifier refers to the region in the code
where it is valid and can be accessed. For example, local
variables have a limited scope within a specific block of code.
Data types:
Java provides a variety of data types to represent different kinds of
values. Here are the main data types in Java:
Floating-Point Types:
Character Type:
12
Boolean Type:
boolean: Represents true or false values.
Array Types:
13
long myLong = 9223372036854775807L; // Note the 'L' suffix
for long literals
// Floating-Point Types
float myFloat = 3.14f; // Note the 'f' suffix for float literals
double myDouble = 2.71828;
// Character Type
char myChar = 'A';
// Boolean Type
boolean myBoolean = true;
Operators in Java:
14
Java provides various operators for performing operations on
variables and values. Here are some commonly used operators in
Java with examples:
1. Arithmetic Operators:
Used for basic mathematical operations.
For ex:
int a = 10;
int b = 5;
int sum = a + b; // Addition
int difference = a - b; // Subtraction
int product = a * b; // Multiplication
int quotient = a / b; // Division
int remainder = a % b; // Modulus
2. Comparison Operators:
Used to compare values and produce a boolean result.
int x = 10;
int y = 5;
boolean isEqual = (x == y); // Equal to
boolean isNotEqual = (x != y); // Not equal to
boolean greaterThan = (x > y); // Greater than
boolean lessThan = (x < y); // Less than
boolean greaterOrEqual = (x >= y); // Greater than or equal to
boolean lessOrEqual = (x <= y); // Less than or equal to
3. Logical Operators:
Used for combining boolean expressions.
boolean condition1 = true;
15
boolean condition2 = false;
boolean logicalAnd = condition1 && condition2; // Logical AND
boolean logicalOr = condition1 || condition2; // Logical OR
boolean logicalNot = !condition1; // Logical NOT
4. Assignment Operators:
Used to assign values to variables.
int age = 20; String result = (age >= 18) ? "Adult" : "Minor";
7. Bitwise Operators:
Used to perform bit-level operations on integers.
8. Instanceof Operator:
Used to test whether an object is an instance of a particular
class or interface.
Object obj = "Hello"; boolean isString = (obj instanceof String);
Control Statements:
16
Control statements in Java are used to control the flow of execution
in a program.
1. if Statement:
Used for decision-making. Executes a block of code if a given
condition is true.
Class If{
Public Static Void Main(string[ ]args) {
int x = 10;
if (x > 5) {
System.out.println("x is greater than 5");
}
}
}
2. if-else Statement:
Provides an alternative block of code to be executed if the
condition in the if statement is false.
Class IfElse{
Public Static Void Main(string[ ]args) {
int y = 3;
if (y % 2 == 0) {
System.out.println("y is even");
17
} else {
System.out.println("y is odd");
}
}
}
3. if-else if-else Statement:
Allows checking multiple conditions in sequence and executing
the block associated with the first true condition.
Class simple{
Public Static Void Main(string[ ]args) {
int grade = 75;
if (grade >= 90) {
System.out.println("A");
} else if (grade >= 80) {
System.out.println("B");
} else {
System.out.println("C");
}
}
}
4. Switch Statement:
Evaluates a variable or expression against a list of possible
values and executes the corresponding block of code.
Class simple{
Public Static Void Main(string[ ]args) {
int day = 3;
18
switch (day) {
case 1:
System.out.println("Monday");
break;
case 2:
System.out.println("Tuesday");
break;
// ... other cases ...
default:
System.out.println("Invalid day");
}
}
}
5. while Loop:
Repeats a block of code as long as a specified condition is true.
Class simple{
Public Static Void Main(string[ ]args) {
int i = 0;
while (i < 5) {
System.out.println(i);
i++;
}
}
}
19
6. do-while Loop:
Similar to the while loop, but guarantees that the block of code
is executed at least once before checking the condition.
Class simple{
Public Static Void Main(string[ ]args) {
int j = 0;
do {
System.out.println(j);
j++;
} while (j < 5);
}
}
7. for Loop:
Executes a block of code a specified number of times, using an
initialization, condition, and increment expression.
Class simple{
Public Static Void Main(string[ ]args) {
20
Used to alter the flow of control in loops. break terminates the
loop, and continue skips the rest of the loop and proceeds to
the next iteration.
Class simple{
Public Static Void Main(string[ ]args) {
for (int m = 0; m < 10; m++) {
if (m == 5) {
break; // Terminate the loop when m is 5
}
if (m % 2 == 0) {
continue; // Skip even numbers
}
System.out.println(m);
}
}
}
loop in Java:
1. while Loop:
The while loop repeatedly executes a block of code as long as
the specified condition is true.
Class simple{
Public Static Void Main(string[ ]args) {
21
int i = 0;
while (i < 5) {
System.out.println(i); i++;
}
}
}
2. do-while Loop:
The do-while loop is similar to the while loop, but it guarantees
that the block of code is executed at least once before checking
the condition.
Class simple{
Public Static Void Main(string[ ]args) {
int j = 0;
do {
System.out.println(j);
j++;
}
while (j < 5);
}
}
3. for Loop:
The for loop is used when you know the number of iterations in
advance. It has an initialization, condition, and
increment/decrement expression.
Class simple{
22
Public Static Void Main(string[ ]args) {
for (int k = 0; k < 5; k++) {
System.out.println(k);
}
}
}
5. Nested Loops:
You can use loops within other loops, creating nested loops for
more complex iteration patterns.
Class simple{
Public Static Void Main(string[ ]args) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
23
System.out.println("i: " + i + ", j: " + j);
}
}
}
}
6. break Statement:
The break statement is used to terminate a loop prematurely. It
is often used in combination with a conditional statement.
Class simple{
Public Static Void Main(string[ ]args) {
for (int m = 0; m < 10; m++) {
if (m == 5) {
break; // Terminate the loop when m is 5
}
System.out.println(m);
}
}
}
7. continue Statement:
The continue statement is used to skip the rest of the loop's
code and proceed to the next iteration.
Class simple{
Public Static Void Main(string[ ]args) {
for (int n = 0; n < 10; n++) {
24
if (n % 2 == 0) {
continue; // Skip even numbers
}
System.out.println(n);
}
}
}
Loops are essential for repetitive tasks and allow for more efficient
and concise code in Java. The choice of loop depends on the specific
requirements of the program and the nature of the iteration.
Arrays in Java:
In Java, an array is a data structure that stores a fixed-size, ordered
collection of elements of the same type.
// Declaration
dataType[] arrayName;
26
// Declaration of a string array
String[] names;
In this example:
Inheritance in Java:
// Parent class
class Vehicle {
String brand;
int year;
28
void start() {
void stop() {
int numberOfDoors;
void accelerate() {
29
// Creating an instance of the child class (Car)
myCar.brand = "Toyota";
myCar.year = 2022;
myCar.numberOfDoors = 4;
myCar.start();
myCar.stop();
myCar.accelerate();
In this example:
Vehicle is the parent class with attributes brand and year, as well as
methods start() and stop().
Car is the child class that extends Vehicle. It inherits attributes and
methods from Vehicle and introduces its own attribute
numberOfDoors and method accelerate().
In the main method, an instance of Car is created, and both parent
and child class methods are accessed.
Key Concepts:
30
1. Superclass (Parent Class): The class whose properties and behaviors
are inherited.
2. Subclass (Child Class): The class that inherits from another class.
Benefits of Inheritance:
Multilevel hierarchy:
32
}
In this example:
Output:
33
}
}
34
myDog.makeSound(); // Calls the overridden method in Dog
class
Explanation:
Output:
Bark, bark!
Bark, bark!
Dog is fetching.
35
Abstract classes in Java:
Abstract classes in Java are classes that cannot be instantiated on
their own and may contain abstract methods, which are methods
without a body.
// Abstract class
// Concrete method
void display() {
System.out.println("This is a shape.");
// Concrete subclass 1
36
double radius;
// Constructor
Circle(double radius) {
this.radius = radius;
@Override
double calculateArea() {
// Concrete subclass 2
double length;
double width;
// Constructor
37
Rectangle(double length, double width) {
this.length = length;
this.width = width;
@Override
double calculateArea() {
myCircle.display();
38
System.out.println("Area of the circle: " +
myCircle.calculateArea());
myRectangle.display();
Explanation:
Output:
This is a shape.
This is a shape.
39
Once a class is declared as final, it cannot be extended or inherited
by any other class.
// Final class
// Final method
40
// Calling the final method
finalObj.display();
Explanation:
Output:
41
A package in Java is a way to organize related classes and interfaces.
It helps in avoiding naming conflicts and provides a modular
structure to the code.
2. Exceptions in Java:
geometry
|-- Shape.java
|-- Circle.java
|-- Rectangle.java
|-- MainApp.java
package geometry;
42
public abstract class Shape {
abstract double calculateArea();
}
Circle.java:
package geometry;
@Override
double calculateArea() {
return Math.PI * radius * radius;
}
}
Rectangle.java:
package geometry;
43
public Rectangle(double length, double width) {
this.length = length;
this.width = width;
}
@Override
double calculateArea() {
return length * width;
}
}
MainApp.java:
import geometry.Circle;
import geometry.Rectangle;
44
}
}
3. Compileand Run:
Compile the classes using the following commands:
4. Output:
Area of the Circle: 78.53981633974483
Area of the Rectangle: 24.0
This structure illustrates the organization and encapsulation
provided by packages in Java. Each class is part of the geometry
package, and their functionality is encapsulated within this
namespace.
geometry
|-- Shape.java
|-- Circle.java
45
|-- Rectangle.java
|-- MainApp.java
app
|-- MainClass.java
2.Define Classes in the Packages:
geometry/Shape.java:
package geometry;
@Override
double calculateArea() {
46
return Math.PI * radius * radius;
}
}
geometry/Rectangle.java:
package geometry;
@Override
double calculateArea() {
return length * width;
}
}
geometry/MainApp.java:
package geometry;
47
public static void main(String[] args) {
Circle myCircle = new Circle(5.0);
Rectangle myRectangle = new Rectangle(4.0, 6.0);
app/MainClass.java:
package app;
import geometry.Circle;
import geometry.Rectangle;
48
System.out.println("Area of the Rectangle: " +
myRectangle.calculateArea());
}
}
3. Compile
and Run:
Compile the classes using the following commands:
java app.MainClass
4. Output:
Area of the Circle: 28.274333882308138
Area of the Rectangle: 35.0
In this example, the MainClass in the app package imports the Circle
and Rectangle classes from the geometry package using the import
statement. This allows it to create instances of these classes and use
their functionality.
49
import java.util.ArrayList;
51
System.out.println("Square Root: " + advCalc.squareRoot(25));
}
}
Compile and Run:
javac math/*.java MathApp.java
java MathApp
Output:
Addition: 8
Square Root: 5.0
52
} catch (ArithmeticException e) {
// Handling the exception
System.out.println("Error: Division by zero is not allowed.");
} finally {
// Code that will be executed regardless of whether an
exception occurs or not
System.out.println("This block will be executed regardless of
exceptions.");
}
53
Output: Error: Division by zero is not allowed.
This block will be executed regardless of exceptions.
Program continues after exception handling.
Explanation:
The ‘ try’ block contains the code that might throw an exception (in
this case, dividing by zero).
The ‘catch’ block catches the specific type of exception
(‘ArithmeticException’) that may occur and provides a way to handle
it.
The ‘finally’ block contains code that will be executed regardless of
whether an exception occurs or not.
The ‘divide’ method throws an ‘ArithmeticException’ if the
denominator is zero.
After exception handling, the program continues with the rest of the
code.
Uncaught Exceptions:
Uncaught exceptions in Java are exceptions that are not caught and
handled within the code using a try-catch block.
54
public class UncaughtExceptionExample {
public static void main(String[] args) {
// Calling a method that throws an uncaught exception
uncaughtExceptionMethod();
Output:
at
UncaughtExceptionExample.uncaughtExceptionMethod(UncaughtEx
ceptionExample.java:12)
55
at
UncaughtExceptionExample.main(UncaughtExceptionExample.java:
6)
Multiple catch:
In Java, you can use multiple ‘catch’ blocks to handle different types
of exceptions that may occur within a ‘try’ block.
This allows you to provide specific handling for different types of
exceptions.
The ‘catch’ blocks are evaluated in order, and the first matching
block is executed.
Here's an example illustrating multiple catch blocks:
public class MultipleCatchExample {
public static void main(String[] args) {
try {
// Code that might cause exceptions
int[] numbers = {1, 2, 3};
int result = divideByZero(numbers);
System.out.println("Result: " + result); // This line won't be
reached if an exception occurs
} catch (ArithmeticException e) {
56
// Handling ArithmeticException
System.out.println("Error: Division by zero is not allowed.");
} catch (ArrayIndexOutOfBoundsException e) {
// Handling ArrayIndexOutOfBoundsException
System.out.println("Error: Array index out of bounds.");
} catch (Exception e) {
// Generic exception handler (catches any other type of
exception)
System.out.println("An unexpected error occurred: " +
e.getMessage());
} finally {
// Code that will be executed regardless of whether an
exception occurs or not
System.out.println("This block will be executed regardless of
exceptions.");
}
}
// Causing an ArrayIndexOutOfBoundsException
int value = numbers[10];
return result;
}
}
Output:
57
Error: Array index out of bounds.
This block will be executed regardless of exceptions.
In this example, an attempt to divide by zero and access an array
element with an invalid index causes exceptions. The specific ‘catch’
blocks handle each type of exception separately, and the generic
‘Exception’ block catches any other unexpected exceptions. The
‘finally’ block ensures that its code is executed regardless of the
exception type.
1. ArithmeticException:
Thrown when an exceptional arithmetic condition has
occurred, such as dividing by zero
2. NullPointerException:
Thrown when trying to access or invoke a method on an object
reference that is null.
3. ArrayIndexOutOfBoundsException:
Thrown when attempting to access an array element at an
index that is outside the bounds of the array.
58
int value = numbers[5]; // ArrayIndexOutOfBoundsException
4. NumberFormatException:
Thrown when attempting to convert a string to a numeric
format, but the string does not have the appropriate format.
5. FileNotFoundException:
Thrown when attempting to access a file that cannot be found.
6. IOException:
A general exception for I/O operations.
fileInputStream.read(); // IOException
7. nterruptedException:
Thrown when a thread is waiting, sleeping, or otherwise
occupied and the thread is interrupted.
8. ClassNotFoundException:
59
Thrown when an application tries to load a class through its
string name using methods like Class.forName, but the
specified class cannot be found.
try { Class.forName("com.example.NonExistentClass"); //
ClassNotFoundException } catch (ClassNotFoundException e) {
e.printStackTrace(); }
It has the same name as the class and is invoked when an object of
the class is created.
Example:
String model;
int year;
// Default constructor
public Car() {
model = "Unknown";
60
year = 2022;
// Parameterized constructor
model = modelName;
year = releaseYear;
61
defaultCar.displayDetails();
customCar.displayDetails();
Output:
Model: Unknown
Year: 2022
Model: Toyota
Year: 2020
1. Default Constructor:
62
Automatically provided by Java if no constructors are explicitly
defined in a class.
Syntax:
2. Parameterized Constructor:
Syntax:
String model;
int year;
// Parameterized constructor
model = modelName;
year = releaseYear;
3. Copy Constructor:
63
A constructor that creates an object by copying the values of another
object.
Helps in creating a new object with the same values as an existing
object.
Syntax:
String name;
int age;
// Copy constructor
name = otherStudent.name;
age = otherStudent.age;
4. Constructor Overloading:
String title;
String author;
64
// Constructor with one parameter
title = bookTitle;
author = "Unknown";
title = bookTitle;
author = bookAuthor;
5. Private Constructor:
// Private constructor
private Singleton() {
65
// Initialization code
if (instance == null) {
return instance;
class Vehicle {
String type;
66
public Vehicle(String vehicleType) {
type = vehicleType;
int numDoors;
numDoors = doors;
67
// Creating an object of the subclass Car
Output:
Number of Doors: 4
Explanation:
68
When creating an object of Car (myCar), both the constructor of
Vehicle and Car are invoked, and the output shows the sequence of
constructor calls.
1. Byte: java.lang.Byte
2. Short: java.lang.Short
3. Integer: java.lang.Integer
4. Long: java.lang.Long
5. Float: java.lang.Float
6. Double: java.lang.Double
7. Character: java.lang.Character
8. Boolean: java.lang.Boolean
Example:
69
public static void main(String[] args) {
// Primitive data types
int primitiveInt = 42;
double primitiveDouble = 3.14;
// Wrapper classes
Integer wrappedInt = Integer.valueOf(primitiveInt);
Double wrappedDouble = Double.valueOf(primitiveDouble);
70
Original primitive int: 42
Wrapped Integer: 42
Unwrapped int: 42
1. Concatenation:
71
Hello World
2. Length:
72
}
Output:
World
5. Replacing Characters:
73
}
Output:
I like Python
6. Converting Case:
Output:
7. Comparing Strings:
Output:
Immutability:
In Java, strings are immutable, which means their values cannot be
changed after they are created.
Any operation that appears to modify a string actually creates a new
string.
This immutability has several benefits, such as thread safety,
simplicity, and ease of use.
Here's an example illustrating string immutability:
public class StringImmutabilityExample {
public static void main(String[] args) {
// Original string
String originalString = "Hello";
75
System.out.println("Original String: " + originalString);
System.out.println("Concatenated String: " +
concatenatedString);
// Demonstrating immutability
System.out.println("Original String after operations: " +
originalString);
}
}
Output:
Original String: Hello, Java!
Concatenated String: Hello World
Original String after operations: Hello, Java!
76
public class StringExample {
public static void main(String[] args) {
// Using string literal
String str1 = "Hello, World!";
// Using constructor
String str2 = new String("Java Programming");
// Using concatenation
String str4 = "Hello" + ", " + "Java!";
// Displaying strings
System.out.println(str1);
System.out.println(str2);
System.out.println(str3);
System.out.println(str4);
77
System.out.println(str5);
}
}
Output:
Hello, World!
Java Programming
Hello
Hello, Java!
42
78
// Using reverse method
StringBuffer buffer4 = new StringBuffer("olleH");
In the examples:
For the String class, various ways to create and initialize strings are
demonstrated, including using literals, constructors, char arrays,
concatenation, and the valueOf method.
For the StringBuffer class, initialization is shown through
constructors, appending, inserting, and reversing operations.
79
mutable StringBuffer class, depending on the requirements of your
application.
80
}
In this example:
@Override
81
public void myMethod() {
System.out.println("Implementation of myMethod");
@Override
return x + y;
@Override
System.out.println("Custom implementation of
defaultMethod");
82
In Java interfaces, abstract methods are methods that are declared
without a body. Any class implementing the interface must provide a
concrete implementation for these abstract methods. Abstract methods
in interfaces are implicitly public and abstract, and they do not have a
method body.
@Override
public int calculate(int x, int y) {
83
return x + y;
}
}
Implementing Interface:
Implementing interfaces in Java involves providing concrete
implementations for all the abstract methods declared in the
interface.
Here's an example:
// Interface with abstract methods
interface Shape {
double calculateArea();
void display();
}
// Constructor
84
public Circle(double radius) {
this.radius = radius;
}
@Override
public void display() {
System.out.println("Circle Area: " + calculateArea());
}
}
// Constructor
public Rectangle(double length, double width) {
this.length = length;
85
this.width = width;
}
@Override
public void display() {
System.out.println("Rectangle Area: " + calculateArea());
}
}
86
}
}
Output:
Circle Area: 78.53981633974483
Rectangle Area: 24.0
In this example:
Extending Interfaces:
In Java, interfaces can extend other interfaces, allowing the creation
of hierarchies of interfaces.
87
A class implementing an interface that extends another interface must
provide concrete implementations for all the abstract methods in the
entire hierarchy.
// Parent interface
interface Shape {
double calculateArea();
// Constructor
this.radius = radius;
88
this.color = color;
@Override
@Override
return color;
89
System.out.println("Circle Area: " +
coloredCircle.calculateArea());
Output:
In conclusion :-
Extending interfaces helps in building a more organized and modular
design, allowing for the creation of specific interfaces with additional
functionality while maintaining a connection to a common set of
methods. Classes implementing these interfaces can then provide
specialized implementations.
Interface References:
// Interface
interface Shape {
double calculateArea();
90
}
this.radius = radius;
@Override
91
this.length = length;
this.width = width;
@Override
92
Shape[] shapes = {new Circle(3), new Rectangle(2, 4)};
Output:
Circle Area: 78.53981633974483
Rectangle Area: 24.0
Shape Area: 28.274333882308138
Shape Area: 8.0
93
interface Greeting {
// Abstract method
void greet();
System.out.println("Default Greeting");
@Override
System.out.println("Hello");
94
public class DefaultMethodExample {
// Invoking methods
Output:
Hello
Default Greeting
95
interface MathOperation {
// Abstract method
@Override
return a + b;
96
// Implementation of abstract method
@Override
return a - b;
MathOperation.description();
97
System.out.println("Difference: " + difference);
Output:
Sum: 8
Difference: 4
Constants in Interfaces:
Here's an example:
98
interface Constants {
// Constant fields (implicitly public, static, and final)
int MAX_VALUE = 100;
String DEFAULT_NAME = "Default";
}
// Displaying constants
myObject.displayConstants();
}
}
Output:
99
Max Value: 100
Default Name: Default
100
}
101
class MyThread extends Thread {
try {
} catch (InterruptedException e) {
e.printStackTrace();
myThread.start();
102
// Code in the main thread
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
OPutput:
Main: 1
Thread: 1
Thread: 2
Main: 2
Thread: 3
Main: 3
Thread: 4
Main: 4
Thread: 5
103
Main: 5
104
// Creating a thread using the runnable
Thread thread = new Thread(myRunnable);
105
Thread: 4
Main: 4
Thread: 5
Main: 5
multi-threaded programming:
Multi-threaded programming in Java allows multiple threads to run
concurrently, enabling parallel execution of tasks.
Below is an example of a simple multi-threaded program where
two threads run concurrently:
class MyRunnable implements Runnable {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println(Thread.currentThread().getId() + " - Count:
" + i);
try {
Thread.sleep(500); // Simulating some work
} catch (InterruptedException e) {
e.printStackTrace();
}
106
}
}
}
107
e.printStackTrace();
}
}
}
}
Output:
11 - Count: 1
12 - Count: 1
Main Thread - Count: 1
12 - Count: 2
11 - Count: 2
Main Thread - Count: 2
12 - Count: 3
11 - Count: 3
Main Thread - Count: 3
11 - Count: 4
12 - Count: 4
Main Thread - Count: 4
11 - Count: 5
12 - Count: 5
Main Thread - Count: 5
In this example:
108
The MyRunnable class implements the Runnable interface and
defines the behavior of the threads in the run method.
Two instances of MyRunnable are created, and two threads (thread1
and thread2) are created using these instances.
The start method is called on each thread to begin their execution
concurrently.
The main thread also performs its own tasks concurrently with the
other threads.
109
public void run() {
System.out.println(Thread.currentThread().getName() + "
Count: " + i);
thread1.setPriority(Thread.MIN_PRIORITY); // Priority 1
thread2.setPriority(Thread.NORM_PRIORITY); // Priority 5
(default)
thread3.setPriority(Thread.MAX_PRIORITY); // Priority 10
110
thread1.start();
thread2.start();
thread3.start();
111
thread priorities and consider other synchronization mechanisms if
precise control over execution order is required.
synchronization of thread:
In Java, synchronization is a mechanism used to control the access of multiple
threads to shared resources. This ensures that only one thread at a
time can execute a critical section of code, preventing data corruption
or race conditions. The synchronized keyword is used to achieve
synchronization.
// Synchronized method
counter++;
System.out.println(Thread.currentThread().getName() + "
Counter: " + counter);
try {
} catch (InterruptedException e) {
e.printStackTrace();
112
}
this.sharedResource = sharedResource;
sharedResource.increment();
113
// Creating an instance of the shared resource
thread1.start();
thread2.start();
The output will demonstrate that only one thread at a time can
execute the increment method, preventing interleaved access
and ensuring the integrity of the shared resource:
Thread-0 Counter: 1
Thread-0 Counter: 2
Thread-0 Counter: 3
Thread-0 Counter: 4
Thread-0 Counter: 5
Thread-1 Counter: 6
114
Thread-1 Counter: 7
Thread-1 Counter: 8
Thread-1 Counter: 9
Thread-1 Counter: 10
115
public void run() {
System.out.println(Thread.currentThread().getName() + "
started");
try {
// Simulating some work
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "
finished");
latch.countDown(); // Decrements the latch count
}
}
thread1.start();
thread2.start();
116
// Main thread waits for both threads to finish
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
In this example:
Thread-0 started
Thread-1 started
Thread-0 finished
Thread-1 finished
117
Keep in mind that direct suspend() and resume() methods are
deprecated due to the issues they can cause, such as potential
deadlocks.
Using modern concurrency utilities like CountDownLatch or
other mechanisms provided by java.util.concurrent is
recommended for synchronization and coordination between
threads.
118