CHAPTER 2 ■ JAVA SYNTAX
interfaces, that means a class that implements the interface must implement the methods defined in the
interface (as we already learned, but now you know why that's the case). Consequently, interfaces never
implement anything. Also, interfaces, and the methods they contain, are always static. Consequently,
each interface (and its methods) exists exactly once in the system.
Interfaces generally contain only method definitions. They can also contain fields, but those fields
are always constants.
Consider the getAverage() method from the Average interface listed earlier in the chapter. As you
can see, the method has no body, not even braces. That's a method definition (also called a method
signature), as opposed to a method. Any class that implements the interface must implement that
method, including its modifiers and arguments. In this example, a class that implements Average must
contain a method with the same modifiers. That is, the class must contain a public float getAverage()
method with a body that does whatever needs to be done and returns a float value. (We cover data types
in the next chapter.)
Interfaces offer a handy way to ensure that similar classes implement similar (but not necessarily
the same) behavior. Consider a set of classes that model the animal kingdom. Such a model might have a
Predator interface with a hunt() method. Both cats and dogs hunt, but they do it differently (cats tend to
pounce, and dogs tend to chase). By leaving the details to the classes, the Predator interface lets us know
that predators hunt but leaves room for each kind of predator to hunt in their own way.
Exceptions
When something bad happens, Java raises an error through a process known as “throwing an
exception.” Exception is a class with many (and many levels of) descendants. The AverageImpl class
throws an IllegalArgumentException if someone tries to use an empty array, because the getAverage
method divides by the length of the array and it's illegal to divide by 0. (In fact, trying to divide by zero
creates an ArithmeticException, but AverageImpl doesn't let things get that far.)
When you can anticipate that someone might try something that will cause a problem, you should
test for that problem and throw an appropriate exception. Let's look at one of the places where
AverageImpl throws an exception in more detail in Listing 2-13:
Listing 2-13. Throwing an exception
public AverageImpl(int[] ints) throws IllegalArgumentException {
if (ints.length == 0){
throw new IllegalArgumentException(EXCEPTION_MESSAGE);
}
this.ints = ints;
}
As you can see, the method declaration includes the throws keyword and then the name of the
exception that the method throws. A method can throw any number of exceptions (and many do). When
a method can throw more than one kind of exception, use a comma to separate them.
Within the method, you can see the test for a problem we want to catch, namely an empty array as
the value of ints. Once we detect the problem, we use the throw keyword to throw a new instance of the
appropriate exception.
When a method throws an exception, any object that uses that method must handle that exception.
You can see that happen in the AverageTest class, in Listing 2-14: