Packages in Java can be classified as:
Some commonly user predefined packages in Java include:
Note: When using the "import java.awt.*" statement, it will include only the classes from the specified package, not its subpackages. To include classes from a subpackage, you must import it explicitly. For example: to include classes from the "java.awt.event" subpackage, you should use the statement "import java.awt.event.
That's why java.* won't include everything because there are no classes directly inside the java package; instead, it contains subpackages. In Java, packages are used to organize and structure code. The java package serves as the root package for many core Java libraries, and it houses various subpackages, each responsible for specific functionalities or components.
Syntax ↓
import static java.lang.System.*;
Example ↓
import static java.lang.System.*;
// Incorrect usage:
// import static java.util.*; // This is not allowed
class Test {
public static void main(String[] args) {
out.println("Hello World"); // No need to use the keyword 'System' every time
out.println("How are you???");
}
}
Explanation:
class Shape {
void color() {
System.out.println("Coloring the shape");
}
void cal_area() {
System.out.println("Calculating area.");
}
void cal_square() {
System.out.println("Calculating square");
}
}
// Shape.java file
package group;
public class Shape {
public void color() {
System.out.println("Coloring the shape");
}
public void cal_area() {
System.out.println("Calculating area.");
}
public void cal_square() {
System.out.println("Calculating square");
}
}
Now that we have created our package file, let's use it:
javac -d . filename.java
// Test.java file where we will import our package and use the methods
import group.Shape.*;
class Test
{
public static void main(String[] args)
{
// To avoid path errors, use the following
group.Shape obj = new group.Shape();
// Shape obj = new Shape(); // This might result in an error
obj.color();
obj.cal_area();
obj.cal_square();
}
}
In Java, exceptions are events that occur during the execution of a program that disrupt the normal flow
of instructions. Exceptions can occur for various reasons, such as division by zero, trying to access an
array element that doesn't exist, or attempting to open a file that doesn't exist.
In Java, exceptions are a vital concept used to manage and handle runtime errors gracefully. They play a
crucial role in achieving the goal of a robust programming language. Let's delve deeper into the world
of exceptions:
Exception handling is a fundamental aspect of Java programming that empowers developers to deal with runtime errors systematically. Java provides built-in support for exception handling, making it easier to write robust and reliable code. Here's a closer look at exception handling in Java:
int x = 10;
int ans = x / 0; // Automatically handled by Java
String s1 = null; // also an exception
In Java, exceptions are organized into a hierarchy of classes through inheritance. The java.lang.Throwable class serves as the root of this hierarchy.
The Throwable class is the root class of the exception hierarchy in Java. It has two main subclasses:
Error represents serious, unrecoverable system-level errors, often caused by the JVM or underlying hardware. Developers usually don't handle these exceptions, and they typically lead to program termination.
Exception represents exceptions that can be caught and handled by application code.
In Java, exceptions are classified into two main categories: checked exceptions and unchecked
exceptions.
These distinctions help developers handle and manage exceptions effectively in their code.
Understanding the difference between checked and unchecked exceptions is crucial for effective exception handling in Java. Checked exceptions help ensure that developers handle potential issues that may arise when interacting with external resources, while unchecked exceptions primarily address programming errors and invalid operations.
The Throwable class, along with its subclasses Error and Exception, forms the foundation of Java's exception handling system. Developers can create their custom exceptions by extending the Exception class or one of its subclasses.
When handling exceptions in Java, it's essential to catch specific exceptions based on the situation, which allows for more precise error handling and recovery.
Exception handling in Java involves several essential keywords, including try, catch, finally, throw, and throws. Let's dive into the details of how these keywords play a crucial role in managing exceptions:
Example ↓
import java.util.Scanner;
class Exp {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int v1, v2, ans;
System.out.println("Enter two numbers: ");
v1 = sc.nextInt();
v2 = sc.nextInt();
ans = v1 / v2;
System.out.println(ans);
}
}
import java.util.Scanner;
class Exp {
public static void main(String[] args) {
try {
Scanner sc = new Scanner(System.in);
int v1, v2, ans;
System.out.println("Enter two numbers: ");
v1 = sc.nextInt();
v2 = sc.nextInt();
ans = v1 / v2;
System.out.println(ans);
} catch (Exception e) {
System.out.println("Error: " + e);
}
}
}
catch (Exception e) {
System.out.println("Error occurred at line: " + e.getStackTrace()[0].getLineNumber());
System.out.println("Error message: " + e.getMessage());
}
// This provides full details about the error.
import java.util.Scanner;
class Exp {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int v1, v2, ans;
System.out.println("Enter two numbers: ");
v1 = sc.nextInt();
v2 = sc.nextInt();
try {
ans = v1 / v2;
System.out.println(ans);
}
catch (InputMismatchException e1) {
System.out.println("Exception due to wrong input datatype");
}
catch (ArithmeticException e2) {
System.out.println("Exception due to dividing by zero");
}
catch (Exception e) { // Default, if we don't exactly know what can be the exception.
System.out.println("Error: " + e);
}
}
}
Exception handling in Java is a critical aspect of ensuring that your programs can gracefully handle unexpected situations. Java provides several mechanisms for handling exceptions, including:
When dealing with exceptions, try and catch blocks serve two main objectives:
There is no strict limitation on the number of try and catch blocks you can use in your code. However, it's essential to consider code complexity as it may increase with a higher number of exception-handling blocks.
Both the input and calculation sections have a higher chance of encountering exceptions, so it's beneficial to place separate try and catch blocks for each group.
import java.util.*;
class ExceptionHandlingExample {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int v1 = 0, v2 = 0, ans = 0, sub = 0;
System.out.println("Enter two numbers: ");
try { // input
v1 = sc.nextInt();
v2 = sc.nextInt();
} catch (InputMismatchException e1) {
System.out.println("Error due to wrong input");
}
try { // calculation
ans = v1 / v2;
System.out.println("Division Result: " + ans);
} catch (ArithmeticException e2) {
System.out.println("Error due to division by zero");
}
try { // independent calculation
sub = v1 - v2;
System.out.println("Subtraction Result: " + sub);
} catch (ArithmeticException e3) {
System.out.println("Error due to subtraction");
}
}
}
In Java, when dealing with complex situations that involve multiple layers of exception handling, nested `try` and `catch` blocks can be employed. These blocks allow for a finer level of detail in handling exceptions at different levels of your code.
Nested `try` and `catch` blocks involve placing one or more `try` blocks inside another. This approach is useful when certain operations within a `try` block can themselves trigger exceptions that need to be handled separately.
try {
// Outer try block
// Perform some operations
try {
// Inner try block
// Perform more specific operations
} catch (SpecificException e) {
// Handle the specific exception from the inner block
}
// Continue with operations
} catch (GeneralException e) {
// Handle a more general exception from the outer block
}
In the example above, the outer `try` block handles more general exceptions, while the inner `try` block handles exceptions specific to its operations. This way, you can provide specialized error-handling for different parts of your code.
The key benefit of nested `try` and `catch` blocks is the ability to address specific exceptions without affecting the entire code block. It allows you to provide more specific error-handling strategies at different levels of your code.
While nesting can be powerful for precise error handling, it can also make your code more complex. It's essential to strike a balance between specificity and code readability. Avoid excessive nesting, which can lead to code that's challenging to maintain.
import java.util.Scanner;
public class NestedTryCatchExample {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int v1, v2, ans, sub;
try {
System.out.println("Enter two numbers: ");
v1 = sc.nextInt();
v2 = sc.nextInt();
try {
ans = v1 / v2;
System.out.println("Division Result: " + ans);
} catch (ArithmeticException e2) {
System.out.println("Error: Division by zero is not allowed.");
}
try {
sub = v1 - v2;
System.out.println("Subtraction Result: " + sub);
} catch (ArithmeticException e3) {
System.out.println("Error: Subtraction operation resulted in an error.");
}
} catch (java.util.InputMismatchException e1) {
System.out.println("Error: Invalid input. Please enter valid numbers.");
}
}
}
Syntax:
try {
// Code that may throw exceptions
}
catch (Exception e) {
// Exception handling code
}
finally {
// Code that always executes, whether or not an exception was thrown
}
import java.util.*;
class Test
{
public static void main(String[] args)
{
int ans = 0;
int v1 = 10;
int v2 = 0;
if(v2 == 0)
{
throw new ArithmeticException("Division by zero is not allowed.");
// Alternatively, you can create an ArithmeticException object and then throw it:
// ArithmeticException obj = new ArithmeticException("Division by zero is not allowed.");
// throw obj;
}
else
{
ans = v1 / v2;
}
System.out.println(ans);
}
}
In the example above, we used the concept of anonymous objects.
class A
{
public void sum(int v1)
{
System.out.println(v1 + 10);
}
}
public static void main(String[] args)
{
(new A()).sum(5);
// This is similar to the following:
// A obj = new A();
// obj.sum(5);
}
// Step 1: Inheriting from RuntimeException class to create our custom exception class
class YoungerAgeException extends RuntimeException {
// Step 2: Creating a constructor that takes a custom error message
YoungerAgeException(String msg) {
super(msg);
}
}
class Test {
public static void main(String[] args) {
int age = 16;
if (age < 18) {
throw new YoungerAgeException("You are not eligible to vote");
} else {
System.out.println("Please vote");
}
System.out.println("Hello"); // This message won't print if the exception is generated, which means the program will terminate abnormally.
}
}
class YoungerAgeException extends RuntimeException {
YoungerAgeException(String msg) {
super(msg);
}
}
class Test {
public static void main(String[] args) {
int age = 16;
try {
if (age < 18) {
throw new YoungerAgeException("You are not eligible to vote");
} else {
System.out.println("Please vote");
}
} catch (YoungerAgeException e) {
System.out.println(e);
}
System.out.println("Hello"); // Now this will run
}
}
Another Example: If a number is even, throw a custom exception.
class MyException extends Exception { // We could also extend RuntimeException here
MyException(String str) {
super(str);
}
}
class Test {
public static void main(String[] args) {
int n1 = 10;
try {
if (n1 % 2 == 0) {
throw new MyException("Number is even.");
} else {
System.out.println("Nothing is wrong");
}
} catch (MyException e) {
System.out.println(e);
}
}
}
Definition of the 'super' Keyword:
In Java, the 'super' keyword is a special word used to refer to the superclass or the parent class of the current class. It helps you access members (like variables or methods) from the superclass, especially when there are similarly named members in both the superclass and the subclass. The 'super' keyword is primarily used to handle conflicts and interact with superclass members in an inheritance hierarchy.
Simple Example for Beginners:
Let's illustrate the 'super' keyword with a straightforward example involving two classes: a superclass called Animal and a subclass called Dog. We'll show how 'super' can be used to access the constructor and method of the superclass.
<!-- Superclass -->
class Animal {
String name;
Animal(String name) {
this.name = name;
}
void sound() {
System.out.println("Animal makes a sound");
}
}
<!-- Subclass -->
class Dog extends Animal {
String breed;
Dog(String name, String breed) {
<!-- Using 'super' to call the superclass constructor -->
super(name);
this.breed = breed;
}
void sound() {
<!-- Using 'super' to call the superclass method -->
super.sound();
System.out.println("Dog barks");
}
}
<!-- Main Program -->
public class Main {
public static void main(String[] args) {
Dog myDog = new Dog("Buddy", "Labrador");
System.out.println("Name: " + myDog.name);
System.out.println("Breed: " + myDog.breed);
myDog.sound();
}
}
In this example, 'super' is used within the Dog constructor to call the constructor of the Animal superclass, passing the name parameter. It's also used within the sound method of the Dog class to call the sound method of the Animal class before adding specific behavior for the Dog class.
When you run this program, it demonstrates how 'super' allows you to use and extend functionality from the superclass when creating subclasses, promoting code reusability and organization in object-oriented programming.
Thread.sleep(1000);
might throw 'IOException'. If we use this, we will get an error
because Java gives warnings before many classes and suggests good exception handling practices. So,
only those who are familiar with exception handling should use these classes.
Syntax:
public void myMethod() throws ExceptionType1, ExceptionType2
{
// Method body
}
public void myMethod() throws Exception // Parent class; mentioning this may consume more memory.
{
// Method implementation
}
The Thread.sleep method is used to intentionally introduce a pause or delay in the execution of a Java program. When this method is called, the program suspends its execution for the specified duration in milliseconds. Importantly, during this pause, the program does not perform any tasks and does not continue from where it left off immediately. This behavior necessitates proper exception handling because Thread.sleep can throw an InterruptedException when interrupted during the sleep period. Exception handling is essential to ensure the program's stability and graceful response to interruptions.
class Test {
public static void main(String[] args) {
System.out.println("Welcome to the use of Throws statement");
int n = 10;
System.out.println(n);
Thread.sleep(5000); // this will throw InterruptedException
int j = 20;
System.out.println(j);
}
}
class Test {
public static void main(String[] args) {
System.out.println("Welcome to the use of Throws statement");
int n = 10;
System.out.println(n);
try {
Thread.sleep(5000); // this will throw InterruptedException
} catch (InterruptedException e) {
System.out.println(e);
}
int j = 20;
System.out.println(j);
}
}
class Test {
public static void main(String[] args) throws InterruptedException {
System.out.println("Welcome to the use of Throws statement");
int n = 10;
System.out.println(n);
Thread.sleep(5000); // this will throw InterruptedException
int j = 20;
System.out.println(j);
}
}
In summary, using the throws keyword in the method signature can make your code cleaner and more concise when dealing with Thread.sleep. It simplifies exception handling and is especially beneficial when you have multiple Thread.sleep calls in your code.
class MyException extends Exception {
public MyException(String message) {
super(message);
}
}
class Test {
// This method declares that it may throw a custom exception.
public void divide(int numerator, int denominator) throws MyException {
if (denominator == 0) {
// Simulate a custom exception (for demonstration purposes).
throw new MyException("Division by zero is not allowed.");
}
int result = numerator / denominator;
System.out.println("Result: " + result);
}
public static void main(String[] args) {
Test myObj = new Test();
try {
myObj.divide(10, 0);
} catch (MyException e) {
System.out.println("Caught an exception: " + e.getMessage());
}
}
}
void m1() {
throw new ArithmeticException();
}
In this example, we throw an 'ArithmeticException' explicitly, signaling that an
arithmetic
error has occurred.
void m1() throws ArithmeticException {
// Method code
}
Here, 'throws' indicates that this method may throw an 'ArithmeticException,' and it's
the
caller's responsibility to handle it if necessary.
throw new ArithmeticException();
This line throws an 'ArithmeticException.'
void m1() throws ArithmeticException, ArrayIndexOutOfBoundsException {
// Method code
}
Here, the 'throws' keyword declares that 'm1' may throw either an 'ArithmeticException'
or an
'ArrayIndexOutOfBoundsException.'
import java.util.InputMismatchException;
import java.util.Scanner;
class Test {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int num1 = 0;
int num2 = 0;
try {
System.out.println("Enter first number: ");
num1 = sc.nextInt();
System.out.println("Enter second number: ");
num2 = sc.nextInt();
} catch (InputMismatchException e) {
System.out.println("InputMismatchException: " + e.getMessage());
// Clear the invalid input
sc.next();
}
try {
String str = "123Human";
int num3 = Integer.parseInt(str);
} catch (NumberFormatException e) {
System.out.println("NumberFormatException: " + e.getMessage());
}
// Rest of your code
int sum = num1 + num2;
System.out.println("Sum: " + sum);
}
}
+---------------------+
| Interface: Test |
|---------------------|
| Area(int l, int b) |
+---------------------+
+---------------------+
| Class: Rectangle |
|---------------------|
| Area(int l, int b) |
+---------------------+