I think you've probably experienced a situation where you run code and end up with something like a NullPointerException, ClassCastException, or worse... This is followed by a long process of debugging, analyzing, googling, and so on. Exceptions are wonderful as is: they indicate the nature of the problem and where it occurred. If you want to refresh your memory and learn just a little more, take a look at this article: Exceptions: checked, unchecked, and custom.

That said, there may be situations when you need to create your own exception. For example, suppose your code needs to request information from a remote service that is unavailable for some reason. Or suppose someone fills out an application for a bank card and provides a phone number that, whether by accident or not, is already associated with another user in the system.

Of course, the correct behavior here still depends on the customer's requirements and the architecture of the system, but let's assume that you've been tasked with checking whether the phone number is already in use and throwing an exception if it is.

Let's create an exception:


public class PhoneNumberAlreadyExistsException extends Exception {

   public PhoneNumberAlreadyExistsException(String message) {
       super(message);
   }
}
    

Next we'll use it when we perform our check:


public class PhoneNumberRegisterService {
   List<String> registeredPhoneNumbers = Arrays.asList("+1-111-111-11-11", "+1-111-111-11-12", "+1-111-111-11-13", "+1-111-111-11-14");

   public void validatePhone(String phoneNumber) throws PhoneNumberAlreadyExistsException {
       if (registeredPhoneNumbers.contains(phoneNumber)) {
           throw new PhoneNumberAlreadyExistsException("The specified phone number is already in use by another customer!");
       }
   }
}
    

To simplify our example, we'll use several hardcoded phone numbers to represent a database. And finally, let's try to use our exception:


public class CreditCardIssue {
   public static void main(String[] args) {
       PhoneNumberRegisterService service = new PhoneNumberRegisterService();
       try {
           service.validatePhone("+1-111-111-11-14");
       } catch (PhoneNumberAlreadyExistsException e) {
           // Here we can write to logs or display the call stack
		e.printStackTrace();
       }
   }
}
    

And now it's time to press Shift+F10 (if you're using IDEA), i.e. run the project. This is what you'll see in the console:

exception.CreditCardIssue
exception.PhoneNumberAlreadyExistsException: The specified phone number is already in use by another customer!
at exception.PhoneNumberRegisterService.validatePhone(PhoneNumberRegisterService.java:11)

Look at you! You created your own exception and even tested it a bit. Congratulations on this achievement! I recommend experimenting with the code a bit to better understand how it works.

Add another check — for example, check whether the phone number includes letters. As you probably know, letters are often used in the United States to make phone numbers easier to remember, e.g. 1-800-MY-APPLE. Your check could ensure that the phone number contains only numbers.

Okay, so we've created a checked exception.