How to Create a Custom Exception in Java - Quiz

Total: 5 questions

1. 

How do you create a custom exception in Java?

A custom (user-defined) exception is a class that extends Exception (checked) or RuntimeException (unchecked). To create one:

  1. Declare a class whose name ends with Exception, for example InvalidAgeException.
  2. Choose the parent class: Exception or RuntimeException.
  3. Add constructors that pass the message (and, if needed, the cause) to super(...).
public class InvalidAgeException extends Exception {
    public InvalidAgeException(String message) {
        super(message);
    }
}

You do not have to implement any methods: getMessage(), getCause(), printStackTrace() and toString() are inherited from Throwable (Exception itself declares only constructors). You throw such an exception with throw new InvalidAgeException("Invalid age: " + age); a method must declare a checked exception in its throws clause.

2. 

Should a custom exception extend Exception or RuntimeException?

The parent class decides whether the exception is checked:

  • extends Exception — checked. The compiler requires throws or try-catch, otherwise you get unreported exception ... must be caught or declared to be thrown. Choose it when the situation is expected and the caller can react meaningfully: a payment is declined, a file is not found, a password is wrong.
  • extends RuntimeException — unchecked. throws and try-catch are optional. Choose it for programming errors and broken method contracts: an invalid argument, an illegal object state.

Rule of thumb: if the code that catches the exception can do something useful (retry, show a message, take another path), make it checked; if the only fix is to change the code, use RuntimeException. Spring and Hibernate make almost all their exceptions unchecked.

Do not extend Error or Throwable: Error is reserved for JVM failures (OutOfMemoryError, StackOverflowError), and a direct subclass of Throwable is not caught by the usual catch (Exception e).

3. 

Which constructors does a custom exception need, and why pass the cause to it?

Constructors are not inherited, so every variant you need must be declared in your class and passed on to super(...). Two are usually enough:

public class OrderProcessingException extends Exception {
    public OrderProcessingException(String message) {
        super(message);
    }

    public OrderProcessingException(String message, Throwable cause) {
        super(message, cause);
    }
}

The constructor with cause enables exception chaining: a low-level exception is wrapped in your own, and the original cause stays available through getCause() and appears in the stack trace as Caused by: ...:

catch (NumberFormatException e) {
    throw new OrderProcessingException("Invalid item quantity: " + input, e);
}

Without passing e, getCause() returns null and the Caused by block disappears from the log.

In total, Exception (and RuntimeException) has five constructors: (), (String message), (String message, Throwable cause), (Throwable cause) and the protected (String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) added in Java 7 — for example, super(message, null, false, false) creates an exception without a stack trace.

4. 

When should you create a custom exception, and when is it better to reuse a standard JDK exception?

A custom exception is justified when:

  • the error has a meaning in your business domain: OrderNotFoundException, WrongPasswordException;
  • you need to pass extra data (an error code, the invalid value) in fields with getters;
  • the calling code must catch exactly this error separately from others;
  • at the boundary between application layers: the data access layer catches SQLException and throws its own DataAccessException with the cause, so the business logic does not depend on JDBC.

For typical contract violations, standard exceptions are better — every Java developer knows what they mean:

  • invalid argument — IllegalArgumentException;
  • null argument — NullPointerException via Objects.requireNonNull(arg, "...");
  • wrong object state — IllegalStateException;
  • index out of range — IndexOutOfBoundsException via Objects.checkIndex(index, length);
  • unsupported operation — UnsupportedOperationException.

If you have many custom exceptions, give them a common parent (for example, ShopException and its subclasses) so the whole group can be caught with one catch.

5. 

What are the most common mistakes when creating a custom exception class?

Most problems are not about syntax but about lost information:

  • A message field of your own instead of super(message) — getMessage() and the stack trace show null.
  • A lost cause — throw new MyException("Database error") inside catch (SQLException e) discards the original exception; write throw new MyException("Database error", e).
  • Extending Throwable or Error — the first is not caught by catch (Exception e), the second is misleading: Error means a JVM failure.
  • A name without the Exception suffix — technically allowed, but it breaks the naming convention.
  • The serialVersionUID warning — Throwable implements Serializable; it is not an error and goes away with private static final long serialVersionUID = 1L;.

Also, an exception cannot be a generic class: class MyException<T> extends Exception fails with a generic class may not extend java.lang.Throwable (because of type erasure, catch could not tell the type arguments apart). A record does not work either — it implicitly extends java.lang.Record. A static nested exception class (UserService.NotFoundException), on the other hand, is common practice.

Page 1 of 1