Creating
your own exceptions
You’re
not stuck using the Java exceptions.
This is important because you’ll often need to create your own exceptions
to denote a special error that your library is capable of creating, but which
was not foreseen when the Java hierarchy was created.
To
create your own exception class, you’re forced to inherit from an
existing type of exception, preferably one that is close in meaning to your new
exception. Inheriting an exception is quite simple:
//: Inheriting.java
// Inheriting your own exceptions
class MyException extends Exception {
public MyException() {}
public MyException(String msg) {
super(msg);
}
}
public class Inheriting {
public static void f() throws MyException {
System.out.println(
"Throwing MyException from f()");
throw new MyException();
}
public static void g() throws MyException {
System.out.println(
"Throwing MyException from g()");
throw new MyException("Originated in g()");
}
public static void main(String[] args) {
try {
f();
} catch(MyException e) {
e.printStackTrace();
}
try {
g();
} catch(MyException e) {
e.printStackTrace();
}
}
} ///:~
The
inheritance occurs in the creation of the new class:
class MyException extends Exception {
public MyException() {}
public MyException(String msg) {
super(msg);
}
}
The
key phrase here is
extends
Exception
,
which says “it’s everything an
Exception
is and more.” The added code is small – the addition of two
constructors that define the way
MyException
is created. Remember that the compiler automatically calls the base-class
default constructor if you don’t explicitly call a base-class
constructor, as in the
MyException( )
default constructor. In the second constructor, the base-class constructor with
a
String
argument is explicitly invoked by using the
super
keyword.
The
output of the program is:
Throwing MyException from f()
MyException
at Inheriting.f(Inheriting.java:16)
at Inheriting.main(Inheriting.java:24)
Throwing MyException from g()
MyException: Originated in g()
at Inheriting.g(Inheriting.java:20)
at Inheriting.main(Inheriting.java:29)
You
can see the absence of the detail message in the
MyException
thrown from
f( ). The
process of creating your own exceptions can be taken further. You can add extra
constructors and members:
//: Inheriting2.java
// Inheriting your own exceptions
class MyException2 extends Exception {
public MyException2() {}
public MyException2(String msg) {
super(msg);
}
public MyException2(String msg, int x) {
super(msg);
i = x;
}
public int val() { return i; }
private int i;
}
public class Inheriting2 {
public static void f() throws MyException2 {
System.out.println(
"Throwing MyException2 from f()");
throw new MyException2();
}
public static void g() throws MyException2 {
System.out.println(
"Throwing MyException2 from g()");
throw new MyException2("Originated in g()");
}
public static void h() throws MyException2 {
System.out.println(
"Throwing MyException2 from h()");
throw new MyException2(
"Originated in h()", 47);
}
public static void main(String[] args) {
try {
f();
} catch(MyException2 e) {
e.printStackTrace();
}
try {
g();
} catch(MyException2 e) {
e.printStackTrace();
}
try {
h();
} catch(MyException2 e) {
e.printStackTrace();
System.out.println("e.val() = " + e.val());
}
}
} ///:~
A
data member
i
has been added, along with a method that reads that value and an additional
constructor that sets it. The output is:
Throwing MyException2 from f()
MyException2
at Inheriting2.f(Inheriting2.java:22)
at Inheriting2.main(Inheriting2.java:34)
Throwing MyException2 from g()
MyException2: Originated in g()
at Inheriting2.g(Inheriting2.java:26)
at Inheriting2.main(Inheriting2.java:39)
Throwing MyException2 from h()
MyException2: Originated in h()
at Inheriting2.h(Inheriting2.java:30)
at Inheriting2.main(Inheriting2.java:44)
e.val() = 47
Since
an exception is just another kind of object, you can continue this process of
embellishing the power of your exception classes. Keep in mind, however, that
all this dressing up might be lost on the client programmers using your
packages, since they might simply look for the exception to be thrown and
nothing more. (That’s the way most of the Java library exceptions are
used.) If this is the case, it’s
possible to create a new exception type with almost no code at all:
//: SimpleException.java
class SimpleException extends Exception {
} ///:~
This
relies on the compiler to create the default constructor (which automatically
calls the base-class default constructor). Of course, in this case you
don’t get a
SimpleException(String)
constructor, but in practice that isn’t used much.