Anda di halaman 1dari 4

Java Practices -> Checked versus unchecked exceptions

Page 1 of 4

Checked versus unchecked exceptions


Unchecked exceptions:
represent defects in the program (bugs) - often invalid arguments passed to a non-private method. To quote from
The Java Programming Language, by Gosling, Arnold, and Holmes: "Unchecked runtime exceptions represent
conditions that, generally speaking, reflect errors in your program's logic and cannot be reasonably recovered from
at run time."
are subclasses of RuntimeException, and are usually implemented using IllegalArgumentException,
NullPointerException, or IllegalStateException
a method is not obliged to establish a policy for the unchecked exceptions thrown by its implementation (and they
almost always do not do so)
Checked exceptions:
represent invalid conditions in areas outside the immediate control of the program (invalid user input, database
problems, network outages, absent files)
are subclasses of Exception
a method is obliged to establish a policy for all checked exceptions thrown by its implementation (either pass the
checked exception further up the stack, or handle it somehow)
It's somewhat confusing, but note as well that RuntimeException (unchecked) is itself a subclass of Exception
(checked).
Example 1
Model Objects are the data-centric classes used to represent items in a particular domain. Model Object constructors
need to handle both arbitrary user input, and input from underlying database ResultSets.
Model Object constructors should throw checked exceptions:
the program may have no direct control over user input. This is particularly true in web applications. It seems
safest for a Model Object to treat user input as having arbitrary, unvalidated content.
it's not safe for an application to make any assumptions about the state of the database. The database is an
independent entity, and its data may be changed by various means, outside of any particular application. For
example, data load tools are commonly used to create an initial state for a new database. Such data can easily
violate the constraints built into a calling application. Thus, the safest assumption is to treat database
ResultSets as having arbitrary, unvalidated content.
Here is an example Model Object, taken from the WEB4J example application. Its constructor throws
ModelCtorException (a checked exception) :
package hirondelle.fish.main.resto;
import
import
import
import
import
import
import
import
import

hirondelle.web4j.model.ModelCtorException;
hirondelle.web4j.model.ModelUtil;
hirondelle.web4j.model.Id;
hirondelle.web4j.security.SafeText;
hirondelle.web4j.model.Decimal;
static hirondelle.web4j.model.Decimal.ZERO;
hirondelle.web4j.model.Check;
hirondelle.web4j.model.Validator;
static hirondelle.web4j.util.Consts.FAILS;

/** Model Object for a Restaurant. */


public final class Resto {
/**
Full constructor.
@param aId underlying database internal identifier (optional) 1..50 characters
@param aName of the restaurant (required), 2..50 characters
@param aLocation street address of the restaurant (optional), 2..50 characters
@param aPrice of the fish and chips meal (optional) $0.00..$100.00
@param aComment on the restaurant in general (optional) 2..50 characters
*/
public Resto(
Id aId, SafeText aName, SafeText aLocation, Decimal aPrice, SafeText aComment
) throws ModelCtorException {
fId = aId;
fName = aName;
fLocation = aLocation;
fPrice = aPrice;
fComment = aComment;

Java Practices -> Checked versus unchecked exceptions

Page 2 of 4

validateState();
}
public
public
public
public
public

Id getId() { return fId; }


SafeText getName() { return fName; }
SafeText getLocation() { return fLocation;
Decimal getPrice() { return fPrice; }
SafeText getComment() { return fComment; }

!!!erride public String toString(){


return ModelUtil.toStringFor(this);
}
!!!erride public boolean equals(Object aThat){
Boolean result = ModelUtil.quickEquals(this, aThat);
if (result == null) {
Resto that = (Resto) aThat;
result = ModelUtil.equalsFor(
this.getSignificantFields(), that.getSignificantFields()
);
}
return result;
}
!!!erride public int hashCode(){
if (fHashCode == 0){
fHashCode = ModelUtil.hashCodeFor(getSignificantFields());
}
return fHashCode;
}
// PRIVATE
pri!ate final Id fId;
pri!ate final SafeText fName;
pri!ate final SafeText fLocation;
pri!ate final Decimal fPrice;
pri!ate final SafeText fComment;
pri!ate int fHashCode;
pri!ate static final Decimal HUNDRED = Decimal.from("100");
pri!ate !oid validateState() throws ModelCtorException {
ModelCtorException ex = new ModelCtorException();
if (FAILS == Check.optional(fId, Check.range(1,50))) {
ex.add("Id is optional, 1..50 chars.");
}
if (FAILS == Check.required(fName, Check.range(2,50))) {
ex.add("Restaurant Name is required, 2..50 chars.");
}
if (FAILS == Check.optional(fLocation, Check.range(2,50))) {
ex.add("Location is optional, 2..50 chars.");
}
Validator[] priceChecks = {Check.range(ZERO, HUNDRED), Check.numDecimalsAlways(2)};
if (FAILS == Check.optional(fPrice, priceChecks)) {
ex.add("Price is optional, 0.00 to 100.00.");
}
if (FAILS == Check.optional(fComment, Check.range(2,50))) {
ex.add("Comment is optional, 2..50 chars.");
}
if ( ! ex.isEmpty() ) throw ex;
}
pri!ate Object[] getSignificantFields(){
return new Object[] {fName, fLocation, fPrice, fComment};
}
}
Example
Args is a convenient utility class. It performs common validations on method arguments. If a validation fails, then it
throws an unchecked exception. It is suitable for checking the internal consistency of program, but not for checking
arbitrary user input.
package hirondelle.web4j.util;
import java.util.regex.*;

Java Practices -> Checked versus unchecked exceptions

Page 3 of 4

/**
Utility methods for common argument validations.
<P>Replaces <tt>if</tt> statements at the start of a method with
more compact method calls.
<P>Example use case.
<P>Instead of :
<PRE>
public void doThis(String aText){
if (!Util.textHasContent(aText)){
throw new IllegalArgumentException();
}
//..main body elided
}
</PRE>
<P>One may instead write :
<PRE>
public void doThis(String aText){
Args.checkForContent(aText);
//..main body elided
}
</PRE>
*/
public final class Args {
/**
If <code>aText</code> does not satisfy {@link Util#textHasContent}, then
throw an <code>IllegalArgumentException</code>.
<P>Most text used in an application is meaningful only if it has visible content.
*/
public static !oid checkForContent(String aText){
if( ! Util.textHasContent(aText) ){
throw new IllegalArgumentException("Text has no visible content");
}
}
/**
If {@link Util#isInRange} returns <code>false</code>, then
throw an <code>IllegalArgumentException</code>.
@param aLow is less than or equal to <code>aHigh</code>.
*/
public static !oid checkForRange(int aNumber, int aLow, int aHigh) {
if ( ! Util.isInRange(aNumber, aLow, aHigh) ) {
throw new IllegalArgumentException(aNumber + " not in range " + aLow + ".." + aHigh);
}
}
/**
If <tt>aNumber</tt> is less than <tt>1</tt>, then throw an
<tt>IllegalArgumentException</tt>.
*/
public static !oid checkForPositive(int aNumber) {
if (aNumber < 1) {
throw new IllegalArgumentException(aNumber + " is less than 1");
}
}
/**
If {@link Util#matches} returns <tt>false</tt>, then
throw an <code>IllegalArgumentException</code>.
*/
public static !oid checkForMatch(Pattern aPattern, String aText){
if (! Util.matches(aPattern, aText)){
throw new IllegalArgumentException(
"Text " + Util.quote(aText) + " does not match '" +aPattern.pattern()+ "'"
);
}
}
/**
If <code>aObject</code> is null, then throw a <code>NullPointerException</code>.
<P>Use cases :
<pre>
doSomething( Football aBall ){

Java Practices -> Checked versus unchecked exceptions

//1. call some method on the argument :


//if aBall is null, then exception is automatically thrown, so
//there is no need for an explicit check for null.
aBall.inflate();
//2. assign to a corresponding field (common in constructors):
//if aBall is null, no exception is immediately thrown, so
//an explicit check for null may be useful here
Args.checkForNull( aBall );
fBall = aBall;
//3. pass on to some other method as parameter :
//it may or may not be appropriate to have an explicit check
//for null here, according the needs of the problem
Args.checkForNull( aBall ); //??
fReferee.verify( aBall );
}
</pre>
*/
public static !oid checkForNull(Object aObject) {
if (aObject == null) {
throw new NullPointerException();
}
}
// PRIVATE
pri!ate Args(){
//empty - prevent construction
}
}

ee l
Model Objects
ld
Yes

e
No

e
Undecided

e
Vote

Page 4 of 4

Anda mungkin juga menyukai