|
The Java Specialists' Newsletter
Issue 120 2006-02-08
Category:
Language
Java version: JDK 1.1 - 5.0 Exceptions From Constructorsby Dr. Heinz M. KabutzAbstract: What do you do when an object cannot be properly constructed? In this newsletter, we look at a few options that are used and discuss what would be best. Based on the experiences of writing the Sun Certified Programmer for Java 5 exam.
Welcome to the 120th edition of The Java(tm) Specialists' Newsletter, this time sent from a
cold but beautiful village of Hinxton in England.
This week I am presenting two Design Patterns Courses
at the European Bioinformatics Institute close to Cambridge in
the UK. We are having an absolute blast, with stimulating
discussions around design and Java.
Thanks for reading this newsletter on our website. We also have a mailing list. That is where the real action takes place (webinars, free reports, etc.). Maybe subscribe today?
Advanced Java Courses on Crete:Java Specialists Master Course 18-21 June 2013 and
Concurrency Specialists Course 6-9 August 2013.
Exceptions From Constructors
Last month I wrote the latest Java Programmer Certification
examination, version 5.0. An improvement over 1.1, even though
some of the questions were still obscure. Hardly any
parrot-style memorization was needed, but you did need an
excellent understanding of Java 5. Some tips for the Sun
Certified Programmer for the Java 2 Platform, Standard Edition
5.0:
- Read every question carefully. Then read it again.
- Read the source code carefully. They are not trying to
trick you. Sun has improved the exams to test your
understanding, not memory.
- Try to think of what the question is trying to test.
- If you find questions which have no correct answers (I found
at least one), bang your head against the desk.
I may not reveal any questions, or give hints of what may come
up. You can get that information from Sun's website.
Now onto the topic of the newsletter, throwing exceptions from
constructors.
What is the best way to deal with objects that cannot be
properly instantiated? Here are some suggestions, which I will
explore in more detail:
- Ignore the problem and cause errors when you try to use the
object later on
- Throw a checked exception
- Throw an IllegalArgumentException
- Throw a NullPointerException
- Throw an AssertionError
- Put in a Java 1.4 assertion
Let's deal with each suggestion.
Ignore the Problem
This, believe it or not, is the most common approach in
practice.
Input parameters are not adequately
checked to ensure that they are within specification.
As a result, the code fails later, rather than immediately.
You want to know about errors as soon as possible. The sooner
you see the problem, the easier it is to understand what caused
it.
With this approach, completely innocent code experiences
spurious values or runtime exceptions.
So, whilst this is the most undesirable of all approaches, it is
the most common. I suggest you look in your code to see where
it is possible to construct objects that actually should never
see the light of day.
Throw a Checked Exception
This tells the client that is constructing the object that
something bad may happen when you try to make it. Examples are
java.net.Socket and java.io.FileInputStream. In the first case,
you might try to open a socket to an invalid address, in the
second, the file might not be found.
Whilst this approach is not bad, it should only be used for
situations that are beyond the control of the client using your
objects.
It is debatable whether FileNotFoundException should be
thrown by the constructor of FileInputStream. Ideally the
client should first verify that the file exists before making an
instance of it. However, since the operating system is beyond
the control of Java, you cannot guarantee atomicity.
Throw an IllegalArgumentException
This is in my opinion usually the best approach. It expresses
to the user accurately what the problem is - he presented an
incorrect argument to the constructor.
To be fair to the user, document in your JavaDoc that you will
throw the IllegalArgumentException, together with the conditions
under which it will be thrown.
public class Person {
private final String name;
private final int age;
private static final int MAXIMUM_AGE = 150;
/**
* Person constructor representing a natural
* person. Name may not be null. Age must be
* non-negative and less than MAXIMUM_AGE.
*
* @throws IllegalArgumentException if name is
* null or if age is out of range.
*/
public Person(String name, int age) {
this.name = name;
this.age = age;
if (this.age < 0 || this.age > MAXIMUM_AGE) {
throw new IllegalArgumentException(
"age out of range: " + this.age +
" expected range 0 <= age < " +
MAXIMUM_AGE);
}
if (this.name == null) {
throw new IllegalArgumentException(
"name is null");
}
}
}
Throw a NullPointerException
NullPointerException was the first bug that I had to fix in some
"legacy" code, back in 1997. I usually equate
"NullPointerException" with bug. Not a bug in the client
code, but rather in the library that I am using. Examples of
code that throws NullPointerException deliberately includes the
Hashtable's put() method. The old Hashtable was written to not
handle null values. This was corrected in the
java.util.HashMap.
import java.util.*;
public class HashTableTest {
public static void main(String[] args) {
System.out.println("HashMap test");
HashMap hm = new HashMap();
hm.put(null, "hello");
System.out.println("Hashtable test");
Hashtable hs = new Hashtable();
hs.put(null, "hello");
}
}
If you decide to go this route, make sure to document this fact
to the user. Yes, no one reads comments, but at least you will
be covered. You can point to the javadoc and say: "Didn't you
read my comment?"
Throw an AssertionError
This is probably the worst way to signal to your user that
you could not construct the object due to the parameters he
sent you. An AssertionError should only
be thrown in places where it cannot happen. If you see this
Error, you know that something completely strange has occurred.
For example, you have managed to divide an int by zero.
Put in a Java 1.4 assertion
Another bad idea is putting Java 1.4 assertions into your code.
You can switch them on and off at runtime, but the problem I
have with that approach is that you may end up with a bad
object, or you may not.
To summarise, in my opinion, the most correct approach is to
be strict in your constructors and throw
IllegalArgumentException or
IllegalStateException if you encounter something
you do not like.
Right, off to bed to catch up on some beauty sleep. Tomorrow
we continue with the Adapter pattern and will discuss whether
the MouseAdapter is an Object Adapter or a Class Adapter.
It was quite fun today showing my class how to build dynamic
proxies.
Kind regards
Heinz
Language Articles
Related Java Course
Discuss at The Java Specialist Club
|