While working on a course (as in, school courses) database system for a school project, I stumbled upon an issue of debate.
I have a class called Course. Here is a constructor (the other one is a blank constructor that assigns default values) for the class:
public Course(String name, String code, char level, int academicYear)
{
serialNumber = nextSerialNumber++;
if (name == null)
{
throw new NullPointerException("Name can not be null.");
}
else
{
this.name = name;
}
if (code == null)
{
throw new NullPointerException("Code can not be null.");
}
else
{
this.code = code;
}
if (indexOf(level, VALID_LEVEL) == -1)
{
throw new InvalidLevelException("Level must be one of "
+ "characters defined in the public array in Course.");
}
else
{
this.level = level;
}
if (String.valueOf(academicYear).length() != NUMBER_OF_DIGITS_IN_YEAR)
{
throw new InvalidYearException("Year must be a four digit number!");
}
else
{
this.academicYear = academicYear;
}
}
Where
InvalidLevelException
and
InvalidYearException
are custom exceptions that are subclasses of
RuntimeException
I throw exceptions from that constructor to indicate if anything has gone wrong. For example, if, while reading from the data file, I encounter bad data, I can reject it and write it to a log (as the project mandates), simply by putting that constructor in a try-catch block and then catching those exceptions, and inside that catch block, log the bad data.
After showing this code to my teacher, he said it is inappropriate to throw exceptions from the constructor. However, I have read numerous Stackoverflow posts in which this practice is encouraged.
My question is: Is it okay to throw exceptions from the above constructor?
Reputable sources (for example, official documents or authoritative books) attached with an answer would be greatly appreciated.
Thanks very much in advance.
The short answer to the question “can a constructor throw an exception in Java” is yes! Of course, properly implementing exceptions in your constructors is essential to getting the best results and optimizing your code.
A constructor should throw an exception when it is unable to complete the construction of said object.
If your construction fails and throws an exception, ~Mutex() will not be called and mutex_ will not be cleaned up. Don't throw exceptions in constructors.
You should always be as precise as possible when defining contracts. Saying throws Exception is therefore a bad idea. It's bad for the same reason it is bad practice to say a method returns an Object when it is guaranteed to return a String .
I don't see anything wrong from throw an exception in the constructor. It means that the object can't be created in a valid state.
Personally you throw the right exception, but don't use custom exceptions if you can use Java exceptions InvalidLevelException
and InvalidYearException
should be replaced with IllegalArgumentException
while NullPointerException
is the right exception if an argument is null.
Another thing i would change is the style: Check your arguments then do everything else.
public Course(String name, String code, char level, int academicYear)
{
if (name == null) {
throw new NullPointerException("Name can not be null.");
}
if (code == null) {
throw new NullPointerException("Code can not be null.");
}
if (indexOf(level, VALID_LEVEL) == -1) {
throw new InvalidLevelException("Level must be one of "
+ "characters defined in the public array in Course.");
}
if (String.valueOf(academicYear).length() != NUMBER_OF_DIGITS_IN_YEAR) {
throw new InvalidYearException("Year must be a four digit number!");
}
serialNumber = nextSerialNumber++;
this.code = code;
this.academicYear = academicYear;
this.level = level;
this.name = name;
}
(p.s if the object can't be created, why increment serial number?)
It's very elegant right? -- Another thing is to make the messages more specific.
Anyway, i think the best source is the entire JDK platform since it's a common pattern to thrown an exception in the constructor.
As Luiggi Mendoza said in comments, it's HashMap
constructor if you need a prof for your teacher
187 public More ...HashMap(int initialCapacity, float loadFactor) {
188 if (initialCapacity < 0)
189 throw new IllegalArgumentException("Illegal initial capacity: " +
190 initialCapacity);
191 if (initialCapacity > MAXIMUM_CAPACITY)
192 initialCapacity = MAXIMUM_CAPACITY;
193 if (loadFactor <= 0 || Float.isNaN(loadFactor))
194 throw new IllegalArgumentException("Illegal load factor: " +
195 loadFactor);
196
197 // Find a power of 2 >= initialCapacity
198 int capacity = 1;
199 while (capacity < initialCapacity)
200 capacity <<= 1;
201
202 this.loadFactor = loadFactor;
203 threshold = (int)(capacity * loadFactor);
204 table = new Entry[capacity];
205 init();
206 }
Is it okay to throw exceptions from the above constructor?
Your question touches on one aspect of Exception
handling. The other aspect is accurately describing the problem. I'll go through both briefly.
Is the exception thrown where the code fails?
The reasoning for this is simple. You want the user to know exactly where the problem occurred, and if you're propagating your exception all over the place, then you're going to make it more difficult for a user of your code to decipher where the issue is. If the issue is in the constructor of an object, you know the issue occurred during that object's creation.
That provides the user with an important clue, which is all you can do. You don't know how the user will mis use your code, so you need to make it as easy as possible for them to decipher the source of their issue.
Does the exception message describe the problem?
Using the appropriate type of Exception
is important. If they've provided an invalid parameter, throw an IllegalArgumentException
. If they have provided a null value, throw a NullPointerException
. The Exception
should be as effective as possible at describing the problem.
The second part of this is the message you attach. The amount of times I've seen:
Exception: Exception Occurred
is frustratingly high. It doesn't help in the slightest, and is an extremely lazy way of handling your code. You need to make it clear:
NullPointerException: Parameter X was null
Instantly, the user knows that the value they're passing for X
is null
. Simply put, make sure that the message specifically describes the issue that caused it.
Extra Reading
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With