Часть заголовка метода throws
То обстоятельство, что метод не обрабатывает возникающее в нем исключение, а выбрасывает (throws) его, следует отмечать в заголовке метода служебным словом throws и указанием класса исключения:
private static void f(int n) throws ArithmeticException{
System.out.println(" 10 / n = " + (10 / n)) ;
}
Почему же мы не сделали это в листинге 16.3? Дело в том, что спецификация JLS делит все исключения на проверяемые (checked), те, которые проверяет компилятор, и непроверяемые (unchecked). При проверке компилятор замечает необработанные в методах и конструкторах исключения и считает ошибкой отсутствие в заголовке таких методов и конструкторов пометки throws. Именно для предотвращения подобных ошибок мы в предыдущих главах вставляли в листинги блоки обработки исключений.
Так вот, исключения класса RuntimeException и его подклассов, одним из которых является ArithmeticException, непроверяемые, для них пометка throws необязательна. Еще одно большое семейство непроверяемых исключений составляет класс Error и его расширения.
Почему компилятор не проверяет эти типы исключений? Причина в том, что исключения класса RuntimeException свидетельствуют об ошибках в программе, и единственно разумный метод их обработки — исправить исходный текст программы и перекомпилировать ее. Что касается класса Error, то эти исключения очень трудно локализовать и на стадии компиляции невозможно определить место их появления.
Напротив, возникновение проверяемого исключения показывает, что программа недостаточно продумана, не все возможные ситуации описаны. Такая программа должна быть доработана, о чем и напоминает компилятор.
Если метод или конструктор выбрасывает несколько исключений, то их надо перечислить через запятую после слова throws. Заголовок метода main ()
листинга 16.1, если бы исключения, которые он выбрасывает, не были бы объектами подклассов класса RuntimeException, следовало бы написать так:
public static void main(String[] args)
throws ArithmeticException, ArrayIndexOutOfBoundsException{
// Содержимое метода
}
Перенесем теперь обработку деления на нуль в метод f о и добавим трассировочную печать, как это сделано в листинге 16.4. Результат — на рис. 16.3.
Листинг 16.4. Обработка исключения в методе
class SimpleExt3{
private static void f(int n){ // throws ArithmeticException{
try{
System.out.println(" 10 / n = " + (10 / n) ) ;
System.out.printlnt"From f() after results output");
}catch(ArithmeticException ae)(
System.out.printlnf"From f() catch: " + ae) ;
// throw ae;
}finally{
System.out.println("From f() finally");
}
}
public static void main(String[] args){
try{
inf n = Integer.parselnt(args[0]);
System.out.printlnt"After parselnt());
f (n);
System.out.println("After results output"); (
catch(ArithmeticException ae){
System.out.println("From Arithm.Exc. catch: "+ае);
}catch(ArraylndexOutOfBoundsException arre)(
System.out.println("From Array.Exc. catch: "+arre);
}finally{
System.out.println("From finally");
}
System.out.println("After all actions");
}
}
Внимательно проследите за передачей управления и заметьте, что исключение класса ArithmeticException уже не выбрасывается в метод main ().
Оператор try {}catch о {} в методе f о можно рассматривать как вложенный в оператор обработки исключений в методе main ().
При необходимости исключение можно выбросить оператором throw ae. В листинге 16.4 этот оператор показан как комментарий. Уберите символы комментария //, перекомпилируйте программу и посмотрите, как изменится ее вывод.
Рис. 16.3. Обработка исключения в методе