User Professor Hans Noodles
Professor Hans Noodles
Level 41

Exceptions: checked, unchecked, and custom

Published in the Java Developer group
Hi! In the last lesson, we got acquainted with exceptions in the Java language, and saw examples of how to work with them.
Exceptions: checked, unchecked, and custom - 1
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: Exceptions: checked, unchecked, and custom - 2 All exceptions have a common ancestor in the Throwable 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. Exceptions: checked, unchecked, and custom - 3 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.
Of course, you can imagine that Java's creators could have introduced mandatory exception handling, but in this case the code would be too complicated. For any division operation, would you have to write a 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 the Exception 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. :)
Comments (25)
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION
Andy Lee Level 10
20 March 2021
good article
Chandan Thapa Level 22, Dubai, United Arab Emirates
1 November 2020
this was very informative!
Christophe Level 22, Lausanne, Switzerland
16 April 2020
Is that right/correct to say : - unchecked purely comes from the inside of the java program (for RuntimeException's derivatives) : so I should be able to avoid them by adopting best practices and defensive coding style. The great conceptor was magnanimous and give us it trust to act ourself as an adult and doesnt enforce try-catch everywhere - checked : comes because the outer world is clearly unpredictable (not made of pure & beautiful java ) and resources like files, network, service, etc.. are in a separate (memory) space that we can't trust. So the great conceptor lead us by enforcing us to implement error (...or I'm too lazy so I pushed the problem to the caller, but I'm half shamed then...)
jawad Level 10, Lahore, Pakistan
24 March 2020
why the leash method showing "false" while the assigned value is true.
Attila Level 25
4 March 2020
very clear, thank you for this explanation.
Thomas Sixberry Level 16, Rochester Hills, United States
3 February 2020
Very cool! You'll hear me in the office.. //screw your exceptions! As I am working through their programs.. oh the joy. LOL
Manish Sinha Level 26, london, United Kingdom
9 January 2020
Thank you for lovely article. Comments always help in clearing all the stuffs do not understand or did not click to mind. Thanks all for commenting useful information related to article. It always helped me.
Turner Level 11, Pittsburgh, United States
16 September 2019
It is a subtle but important point made by the Article. Unchecked exceptions show Programmer Error. Therefore, you as a Developer must use try-catch judiciously. Too many tend to hide bastion of bad code simply because they are handled. Letting the program "fail" allows a redesign and a reevaluation of the requirements. Example: If a divide by zero occurs, if checked the Exception might simply be logged (and often overlooked :)). If left unchecked however then the developer has the opportunity to ask the question why is the programming allowing a zero in the denominator to occur?
Ash Ka Level 13, Calgary, Canada
29 August 2019
This article is as clear as it can be.. Wonderful!
Binesh Level 16, India
29 August 2019
Moving on...