среда, 1 августа 2012 г.

exception: mechanics

try + catch

исключение перехвачено точным перехватчиком

class ExceptionTest_TC_0 { 
    public static void main(String[] args) {
        try {
            System.out.println(0);
            throw new RuntimeException();
        } catch (RuntimeException e) {
            System.out.println(1);
        }
        System.out.println(2);
    }
}
>> 0
>> 1
>> 2

исключение перехвачено перехватчиком предка
class ExceptionTest_TC_1 {

    public static void main(String[] args) {
        try {
            System.out.println(0);
            throw new RuntimeException();
        } catch (Exception e) {
            System.out.println(1);
        }
        System.out.println(2);
    }
}
>> 0
>> 1
>> 2


исключение перехвачено точным-перехватчиком среди множества перехватчиков
class ExceptionTest_TC_2 { 
    public static void main(String[] args) {
        try {
            System.out.println(0);
            throw new RuntimeException();
        } catch (NullPointerException e) {
            System.out.println(1);
        } catch (RuntimeException e) {
            System.out.println(2);
        } catch (Exception e) {
            System.out.println(3);
        }
        System.out.println(4);
    }
}
>> 0
>> 2
>> 4

исключение перехвачено перехватчиком предка среди множества перехватчиков
class ExceptionTest_TC_3 {

    public static void main(String[] args) {
        try {
            System.out.println(0);
            throw new RuntimeException();
        } catch (NullPointerException e) {
            System.out.println(1);
        } catch (Exception e) {
            System.out.println(2);
        } catch (Error e) {
            System.out.println(3);
        }
        System.out.println(4);
    }
}
>> 0
>> 2
>> 4

исключение не перехвачено единственным перехватчиком
class ExceptionTest_TC_4 {
    public static void main(String[] args) { 
        try {
            System.out.println(0);
            throw new RuntimeException();
        } catch (NullPointerException e) {
            System.out.println(1);
        }
        System.out.println(2);
    }
}
>> 0
>> RuntimeException ...

исключение не перехвачено множеством перехватчиком
class ExceptionTest_TC_5 {
    public static void main(String[] args) {
        try {
            System.out.println(0);
            throw new RuntimeException();
        } catch (NullPointerException e) {
            System.out.println(1);
        } catch (ArithmeticException e) {
            System.out.println(2);
        }
        System.out.println(3);
    }
}
>> 0
>> RuntimeException ...



исключение перехвачено ПЕРВЫМ подходящим перехватчиком из множества подходящих
class ExceptionTest_TC_6 {
    public static void main(String[] args) { 
        try {
            System.out.println(0);
            throw new NullPointerException();
        } catch (ArithmeticException e) {
            System.out.println(1);
        } catch (RuntimeException e) {
            System.out.println(2);
        } catch (Exception e) {
            System.out.println(3);
        }
        System.out.println(4);
    }
}
>> 0
>> 2
>> 4

ошибка компиляции: перехватчик предка стоит перед перехватчиком потомка
class ExceptionTest_TC_7 {
    public static void main(String[] args) { 
        try {
            System.out.println(0);
            throw new NullPointerException();
        } catch (ArithmeticException e) {
            System.out.println(1);
        } catch (Exception e) {
            System.out.println(3);
        } catch (RuntimeException e) {
            System.out.println(2);
        }
        System.out.println(4);
    }
}

из одного catch не попадешь в другой catch -> новое исключение летит "выше"
class ExceptionTest_TC_8 {
    public static void main(String[] args) { 
        try {
            System.out.println(0);
            throw new NullPointerException();
        } catch (NullPointerException e) {
            System.out.println(1);
            throw new ArithmeticException();
        } catch (ArithmeticException e) {
            System.out.println(2);
        }
        System.out.println(5);
    }
}
>> 0
>> 1
>> ArithmeticException ...

можно повторно бросить перехваченное исключение -> повторно брошенное исключение летит "выше" (рекурсии не возникает - повторного входа в тот же самый catch)
class ExceptionTest_TC_9 {
    public static void main(String[] args) {
        try {
            System.out.println(0);
            throw new NullPointerException();
        } catch (NullPointerException e) {
            System.out.println(1);
            throw e;
        } catch (ArithmeticException e) {
            System.out.println(2);
        }
        System.out.println(5);
    }
}


>> 0
>> 1
>> NullPointerException ...



    try + finally

    в finally заходим всегда, состояние летящего исключения приостанавливается но не очищается
class ExceptionTest_TF_0 { 
    public static void main(String[] args) {
        System.out.println(f());
    }

    public static int f() {
        try {
            System.out.println(0);
            throw new RuntimeException();
        } finally {
            System.out.println(1);
        }
    }
}
>> 0
>> 1
>> RuntimeException ...



в finally заходим всегда, состояние возврата return приостанавливается но не очищается
class ExceptionTest_TF_1 {
    public static void main(String[] args) {
        System.out.println(f());
    }
    public static int f() {
        try {
            System.out.println(0);
            return 42;
        } finally {
            System.out.println(1);
        }
    }
}
>> 0
>> 1
>> 42





в finally заходим всегда, return в finally переписывает return из try
class ExceptionTest_TF_2 { 
    public static void main(String[] args) {
        System.out.println(f());
    }
    public static int f() {
        try {
            System.out.println(0);
            return 42;
        } finally {
            System.out.println(1);
            return 24;
        }
    }
}
>> 0
>> 1
>> 24





в finally заходим всегда, return в finally переписывает исключение из try
class ExceptionTest_TF_3 { 
    public static void main(String[] args) {
        System.out.println(f());
    }
    public static int f() {
        try {
            System.out.println(0);
            throw new RuntimeException();
        } finally {
            System.out.println(1);
            return 24;
        }
    }
}

>> 0
>> 1
>> 24





в finally заходим всегда, исключение в finally переписывает return из try
class ExceptionTest_TF_4 { 
    public static void main(String[] args) {
        System.out.println(f());
    }
    public static int f() {
        try {
            System.out.println(0);
            return 42;
        } finally {
            System.out.println(1);            
            throw new RuntimeException();
        }
    }
}
>> 0
>> 1
>> RuntimeException ...




в finally заходим всегда, исключение в finally переписывает исключение из try
class ExceptionTest_TF_5 { 
    public static void main(String[] args) {
        System.out.println(f());
    }
    public static int f() {
        try {
            System.out.println(0);
            throw new RuntimeException();
        } finally {
            System.out.println(1);
            throw new NullPointerException();
        }
    }
}
>> 0
>> 1
>> NullPointerException ...


    try + catch + finally

    Исключение перехвачено точным перехватчиком
class ExceptionTest_TCF_1A {
    public static void main(String[] args) {
        try {
            System.out.println(0);
            if (true) {
                throw new NullPointerException();
            }
        } catch (NullPointerException e) {
            System.out.println(1);
        } finally {
            System.out.println(5);
        }
        System.out.println(6);
    }
}
>> 0
>> 1
>> 5
>> 6



    Исключение перехвачено перехватчиком предка
class ExceptionTest_TCF_1B {
    public static void main(String[] args) {
        try {
            System.out.println(0);
            if (true) {
                throw new NullPointerException();
            }
        } catch (RuntimeException e) {
            System.out.println(1);
        } finally {
            System.out.println(5);
        }
        System.out.println(6);
    }
}



>> 0
>> 1
>> 5
>> 6



    Исключение не перехвачено
class ExceptionTest_TCF_1C {
    public static void main(String[] args) {
        try {
            System.out.println(0);
            if (true) {
                throw new RuntimeException();
            }
        } catch (NullPointerException e) {
            System.out.println(1);
        } finally {
            System.out.println(5);
        }
        System.out.println(6);
    }
}

>> 0
>> 5
>> RuntimeException


    Исключение перехвачено, но в catch-блоке инициировано другое исключение
class ExceptionTest_TCF_10A {
    public static void main(String[] args) {
        try {
            System.out.println(0);
            if (true) {
                throw new NullPointerException();
            }
        } catch (NullPointerException e) {
            System.out.println(1);
            throw new IllegalArgumentException();
        } finally {
            System.out.println(5);
        }
        System.out.println(6);
    }
}


>> 0
>> 1
>> 5
>> IllegalArgumentException


    Исключение перехвачено, но finally-блок выкинул исключение
class ExceptionTest_TCF_10B {
    public static void main(String[] args) {
        try {
            System.out.println(0);
            if (true) {
                throw new NullPointerException();
            }
        } catch (NullPointerException e) {
            System.out.println(1);
        } finally {
            System.out.println(5);
            if (true) {
                throw new IllegalArgumentException();
            }
        }
        System.out.println(6);
    }
}



>> 0
>> 1
>> 5
>> IllegalArgumentException



?
?
>> ?


?
?
>> ?


    Из одного catch-блока не попадаем во второй
class ExceptionTest_TCF_20 {
    public static void main(String[] args) {
        try {
            System.out.println(0);
            throw new NullPointerException();
        } catch (NullPointerException e) {
            System.out.println(1);
            throw new IllegalArgumentException();
        } catch (IllegalArgumentException e) {
            System.out.println(2);
        } finally {
            System.out.println(5);
        }
        System.out.println(6);
    }
}
>> 0
>> 1
>> 5
>> IllegalArgumentException

Далее следует хорошо различать две ситуации

- этого нельзя/можно сделать (вопросы синтаксиса)
- этого не рекомендуется делать (вопросы семантики)

Примеры



public class DeepDiveException {    
    public static void main(String[] args) {
        f();
    }
    public static void f() {
        try {
            f();
        } catch (StackOverflowError e) {
            f();
        } finally {
            f();
        }
    }
}

1) Что произойдет при запуске этого кода?
2) Если вы для трассировки вставите System.out.println(..) - это повлияет на работу примера. Как?
Факты
1. В Java 5 ключевых слов для работы с исключениями: try, catch, finally, throw, throws.
2. Исключение - способ узнать имя метода и номер строки (так делают Log4j).
3. В секцию finally попадаем всегда. За исключением 
- System.exit(...) 
- Runtime.getRuntime().halt(...);
Runtime.getRuntime().exit(...);
4. любому методу в сигнатуру можно добавить throws AnyException, хоть чек/унчек вне зависимости от тела.
5. чек/унчек влияет только на компиляцию, перехватываются все одинаково можно 
6. я могу напрямую наследоваться от Throwable, хотя так и не принято
7. У исключений могут быть поля и методы
8. у исключения может быть message + clause
9. исключение это способ вернуть Разные резльтаты из одной сигнатуры
10. в java 7 добавилось
    - Multi-catch exceptions, which we cover here
    - try-with-resources
11. throw и new - независимые инструкции (в какой момент наполняется стектрейс?).

- в каком случае я МОГУ добавить в сигнатуру throws RE?

- в каком случае я НЕ МОГУ добавить в сигнатуру throws RE?
- в каком случае я ОБЯЗАН добавить в сигнатуру throws RE?

- в каком случае я МОГУ добавить в сигнатуру throws Ex?
- в каком случае я НЕ МОГУ добавить в сигнатуру throws Ex?
- в каком случае я  ОБЯЗАН добавить в сигнатуру throws Ex?
- я не зайду в finally если
    - не было исключения
    - return;
    - throw new - не перехваченный catch
    - throw new - перехваченный catch
    - throw new - перехваченный catch и catch кинул новое
    - System.exit
    - Runtime.exit
    - Runtime.halt
- я могу наследоваться исключительно от нефинальных Ex и RuEx или их потомков.
    - да, Er и Th - нельзя наследоваться
    - могу еще и от Er
    - могу еще и от Th
    - могу еще и от Er и от Th
- мы не можем обернуть чекед в анчекед (да, нет)
- последовательность catch
    - er, ex, re, остальные
    - er, er-насл, ex, ex-насл, re, re-насл
    - нельзя ставить предка выше потомка, в остальном произвольно
- Throwable можно перехватывать (да, нет, можно но не рекомендуется)
- Error можно перехватывать (да, нет, можно но не рекомендуется)
- Exception можно перехватывать (да, нет, можно но не рекомендуется)
- RuntimeException можно перехватывать (да, нет, можно но не рекомендуется)
- неперехваченное исключение 
    - убивает поток
    - убивает приложение
    - попадает в DefaultExceptionHandler

    Лабораторные
    ex.mech.Simple
    ex.mech.MultiCatch
    ex.mech.InfOrNotInf
    Задания лабораторных можно прочитать на этой странице.