Tasks studies - laboratory
An exception is a special class in Java. It is specific because it inherits from the java.lang.Throwable
class. Instances that have this class in their inheritance chain can be “thrown,” interrupting the standard program execution.
The Throwable
class is the base class in the hierarchy and is divided into Error
and Exception
.
Error - Represents irreversible conditions, e.g., out-of-memory errors, memory leaks, stack overflow errors, library mismatches, infinite recursion, etc.
Exception - These can be caught and handled by the program. When an exception occurs in a method, an object is created, which is referred to as an exception object. It contains information about the exception, such as its name, description, and the program state where the exception occurred.
An example might be validating method arguments. Suppose our method takes the number of hours as an argument and returns the number of seconds corresponding to the provided argument. We can assume that only positive or 0 arguments are acceptable. In other words, if the method is called with a negative argument, we can consider this an invalid invocation and signal this situation by throwing an exception.
package PO_UR.Lab08;
public class ExceptionExample01 {
public int getNumberOfSeconds(int hour) {
if (hour < 0) {
throw new IllegalArgumentException("Hour must be >= 0: " + hour);
}
return hour * 60 * 60;
}
}
In the above example, a standard Java library exception java.lang.IllegalArgumentException
is used. To throw an exception, the throw
keyword is used.
Let’s analyze the following example:
package PO_UR.Lab08;
public class StackTraceExample {
public static void main(String[] args) {
StackTraceExample example = new StackTraceExample();
example.method1();
}
public void method1() {
method2();
}
public void method2() {
method3();
}
public void method3() {
throw new RuntimeException("BUM! BUM! BUM!");
}
}
In the main
method, we create an instance of the StackTraceExample
class and call the method1
method on it. This method calls method2
, which in turn calls method3
. method3
throws a java.lang.RuntimeException
(another standard library exception). This chain of method calls is referred to as the call stack. In our case, the stack looks like this:
When this program is executed, the exception is thrown, and the programmer will see a stack trace of the methods, as shown below:
Exception in thread "main" java.lang.RuntimeException: BUM! BUM! BUM!
at PO_UR.Lab08.StackTraceExample.method3(StackTraceExample.java:19)
at PO_UR.Lab08.StackTraceExample.method2(StackTraceExample.java:15)
at PO_UR.Lab08.StackTraceExample.method1(StackTraceExample.java:11)
at PO_UR.Lab08.StackTraceExample.main(StackTraceExample.java:7)
In programming, the ability to read this type of message is very important. The stack trace is nothing more than a reversed call stack, from the program’s start to the point where the exception was thrown.
An exception is handled when we respond to its occurrence and attempt to “fix” the program during its execution. Handling exceptions is done using the try/catch
block. Refer to the example below:
try {
// code
} catch (Exception e) {
// code
}
package PO_UR.Lab08;
public class ExceptionExample02 {
public static void main(String[] args) {
try {
// code that generates exception
int divideByZero = 5 / 0;
System.out.println("Rest of code in try block");
} catch (ArithmeticException e) {
System.out.println("ArithmeticException => " + e.getMessage());
}
}
}
In the above example, we try to divide a number by 0. To handle the exception, the division code is placed inside a try
block. If an exception occurs, the remaining part of the try
block is skipped. The catch
block catches the exception and executes the instructions within it. If no instructions in the try
block generate an exception, the catch
block is skipped.
finally
BlockIn Java, the finally
block is always executed, regardless of whether an exception occurs or not. It is optional, and for every try
block, there can only be one finally
block. Basic syntax:
try {
// code
} catch (ExceptionType1 e1) {
// catch block
} finally {
// finally block always executes
}
package PO_UR.Lab08;
public class ExceptionExample02 {
public static void main(String[] args) {
try {
// code that generates exception
int divideByZero = 5 / 0;
System.out.println("Rest of code in try block");
} catch (ArithmeticException e) {
System.out.println("ArithmeticException => " + e.getMessage());
} finally {
System.out.println("This is the finally block");
}
}
}
In the above example, we divide a number by 0 inside the try
block. This code generates an ArithmeticException
, which is caught by the catch
block. Then, the finally
block is executed.
Write a program that takes a number from the user and displays its square root. Use the existing method java.lang.Math.sqrt()
to calculate the square root. If the user enters a negative number, throw an IllegalArgumentException
. Handle cases where the user inputs a string that is not a number.
Write a method that returns the factorial of the number provided as an argument. The method should throw a Checked
exception defined by you, InvalidFactorialValueException
, if the argument is negative. Use this method in the main
method, handling any potential exceptions.
Write a program with a Address
class that includes the following fields set in the constructor. The constructor should validate all provided values and throw a Checked
exception InvalidAddressException
if any values are invalid.
Note: The exception message should include information about all invalid values passed to the constructor. For example, if both the street and city are null
, the exception message should be: “Street cannot be null. City cannot be null.”
Class fields:
String street
– invalid value: null
int houseNumber
– invalid value: number <= 0
String postalCode
– invalid value: null
String city
– invalid value: null