The Java Specialists' Newsletter [Issue 120]
Author: Dr. Heinz M. Kabutz
JDK version: JDK 1.1 - 5.0Category: Language
If you are reading this, and have not subscribed, please consider doing it
now by going to our subscribe page [http://www.javaspecialists.co.za/archive/subscribe.jsp].
You can subscribe either via email or RSS.
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 [http://www.javaspecialists.co.za/courses/dpc.jsp]
at the European Bioinformatics Institute close to Cambridge in the UK. We are
having an absolute blast, with stimulating discussions around design and Java.
In-house Courses [http://www.javaspecialists.co.za/courses/inhouse.jsp]
: This is the best value-for-money Java training you will find. Heinz flies
over to your country and trains your developers on Java. Presented in English or
German. One week of high quality Java training for only EUR 975 per developer!
Please ask for a detailed quotation.
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 knowledge, 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
Copyright 2000-2005 Maximum Solutions, South Africa
Reprint Rights. Copyright subsists in all the material included
in this email, but you may freely share the entire email with anyone you feel
may be interested, and you may reprint excerpts both online and offline provided
that you acknowledge the source as follows: This material from The Java(tm)
Specialists' Newsletter by Maximum Solutions (South Africa). Please contact
Maximum Solutions [http://www.javaspecialists.co.za] for more
information.
Java and Sun are trademarks or registered trademarks of Sun Microsystems,
Inc. in the United States and other countries. Maximum Solutions is independent
of Sun Microsystems, Inc.
7861 bytes more | comments? | | Score: 0
|