Hi! In the last lesson, we got acquainted with exceptions in the Java language, and saw examples of how to work with them.
Today we will take a deeper look at the structure of exceptions, and learn how to write our own exceptions :)
Types of exceptions
As we said previously, there are a lot of exceptions in Java, almost 400! But they're all divided into groups, so it's fairly easy to remember them. This is how it looks: All exceptions have a common ancestor in theThrowable
class.
Two major groups are derived from it: exceptions (Exception) and errors (Error).
Error - This represents a critical run-time error related to the operation of the Java virtual machine. In most cases, Error doesn't need to be handled, since it indicates some serious flaws in the code.
The most famous of these are StackOverflowError (this occurs, for example, when a method calls itself endlessly) and OutOfMemoryError (this occurs when there isn't enough memory to create new objects).
As you can see, in these situations, usually there is absolutely nothing to handle at run time: the code is simply written incorrectly and needs to be reworked.
Exception - This represents, well, an exception: an exceptional, unplanned situation that occurs while the program is running.
They are not as serious as Error, but they do still require our attention.
All exceptions are divided into 2 types: checked and unchecked.
All checked exceptions are derived from the Exception
class.
What does "checked" mean?
We alluded to this in the last lesson:
"The Java compiler therefore knows the most common exceptions and the situations where they might occur."
For example, it knows that if the code reads data from a file, the file could easily not exist. And there are a lot of such situations (which it can infer).
Accordingly, the compiler checks our code in advance for the presence of these potential exceptions. If it finds them, it won't compile the code until we have handled them or re-thrown them.
The second type of exception is "unchecked". They are derived from the RuntimeException
class.
How are they different from checked exceptions? It seems that there are also lots of different classes derived from RuntimeException
(which describe runtime exceptions).
The difference is that the compiler doesn't anticipate these errors. It seems to be saying, "When the code was written, I didn't find anything suspicious, but something went wrong while it was running. Apparently, there are errors in the code!"
And indeed this is true. Unchecked exceptions are most often the result of programmer errors.
And the compiler obviously can't foresee every possible bad situation people might create with their own hands. :) Therefore, it doesn't check whether such exceptions are handled in our code.
You've already encountered several unchecked exceptions:
- An ArithmeticException occurs when dividing by zero
- An ArrayIndexOutOfBoundsException occurs when you try to access a position outside the array.
try-catch
block to check whether you accidentally divided by zero?
Any time you accessed an array, you would have to write a try-catch
block to check if your index was out of bounds.
Everything would be spaghetti code and would be completely unreadable.It makes sense that this idea was abandoned.
As a result, unchecked exceptions don't need to be handled in try-catch
blocks or re-thrown (although this is technically possible, as with Error).
How to throw your own exception
Of course, Java's creators can't foresee every exceptional situation that might arise in programs. There are too many programs in the world, and they are too diverse. But this isn't anything to worry about, because you can create your own exception, if necessary. This very easy to do. All you have to do is create your own class. You should be sure its name ends with "Exception". The compiler doesn't require this, but other programmers reading your code will immediately understand that it is an exception class. In addition, indicate that the class is inherited from theException
class (the compiler does require this).
For example, suppose we have a Dog
class. We can walk the dog using the walk()
method.
But before doing that, we need to check whether our pet is wearing a collar, leash, and muzzle. If any of this gear is missing, we throw our own exception: DogIsNotReadyException. Its code looks like this:
public class DogIsNotReadyException extends Exception {
public DogIsNotReadyException(String message) {
super(message);
}
}
To indicate that the class is an exception, you need to write "extends Exception" after the class name (this means "the class is derived from the Exception class").
In the constructor, we simply call the Exception
class constructor with the String message (if the exception occurs, we will show the message, a description of the error, to the user).
Here's how this looks in our class code:
public class Dog {
String name;
boolean isCollarPutOn;
boolean isLeashPutOn;
boolean isMuzzlePutOn;
public Dog(String name) {
this.name = name;
}
public static void main(String[] args) {
}
public void putCollar() {
System.out.println("The collar is on!");
this.isCollarPutOn = true;
}
public void putLeash() {
System.out.println("The leash is on!");
this.isLeashPutOn = true;
}
public void putMuzzle() {
System.out.println("The muzzle is on!");
this.isMuzzlePutOn = true;
}
public void walk() throws DogIsNotReadyException {
System.out.println("We're getting ready for a walk!");
if (isCollarPutOn && isLeashPutOn && isMuzzlePutOn) {
System.out.println("Hooray, let's go for a walk! " + name + " is very happy!");
} else {
throw new DogIsNotReadyException(name + " is not ready for a walk! Check the gear!");
}
}
}
Now our walk()
method throws a DogIsNotReadyException.
This is done with the keyword throw. As we said earlier, an exception is an object. So, when an exception occurs (the dog is missing something) in our method, we create a new DogIsNotReadyException
object and throw it using the keyword throw.
We add "throws DogIsNotReadyException" to the method declaration. In other words, now the compiler is aware that calling the walk()
method could turn into an exceptional situation.
Accordingly, this exception must be handled if we call this method somewhere in our program.
Let's try doing this in the main()
method:
public static void main(String[] args) {
Dog dog = new Dog("Buddy");
dog.putCollar();
dog.putMuzzle();
dog.walk();// Unhandled exception: DogIsNotReadyException
}
This won't compile. The exception is not handled! We wrap our code in a try-catch
block to handle the exception:
public static void main(String[] args) {
Dog dog = new Dog("Buddy");
dog.putCollar();
dog.putMuzzle();
try {
dog.walk();
} catch (DogIsNotReadyException e) {
System.out.println(e.getMessage());
System.out.println("Checking the gear! Is the collar on? " + dog.isCollarPutOn + "\r\n Is the leash on? "
+ dog.isLeashPutOn + "\r\n Is the muzzle on? " + dog.isMuzzlePutOn);
}
}
Now let's look at the console output:
The collar is on!
The muzzle is on!
We're getting ready for a walk!
Buddy is not ready for a walk! Check the gear!
Checking the gear! Is the collar on? true
Is the leash on? false
Is the muzzle on? true
Look at how much more informative the console output was!
We see every step taken in the program; we see where the error occurred, and we can also immediately see exactly what our dog is missing. :)
And that's how you create your own exceptions. As you can see, there's nothing complicated about it. And even though Java's creators didn't bother to include in the language a special exception for poorly equipped dogs, we've fixed their oversight. :)More reading: |
---|
GO TO FULL VERSION