JavaRush/Java блог/Архив info.javarush/Исключения и их обработка
articles
15 уровень

Исключения и их обработка

Статья из группы Архив info.javarush
участников
Исключениями или исключительными ситуациями (состояниями) называются ошибки, возникшие в программе во время её работы. Все исключения в Java являются объектами. Поэтому они могут порождаться не только автоматически при возникновении исключительной ситуации, но и создаваться самим разработчиком. Иерархия классов исключений: Исключения и их обработка - 1Исключения делятся на несколько классов, но все они имеют общего предка — класс Throwable. Его потомками являются подклассы Exception и Error. Исключения (Exceptions) являются результатом проблем в программе, которые в принципе решаемы и предсказуемы. Например, произошло деление на ноль в целых числах. Ошибки (Errors) представляют собой более серьёзные проблемы, которые, согласно спецификации Java, не следует пытаться обрабатывать в собственной программе, поскольку они связаны с проблемами уровня JVM. Например, исключения такого рода возникают, если закончилась память, доступная виртуальной машине. Программа дополнительную память всё равно не сможет обеспечить для JVM. В Java все исключения делятся на три типа: контролируемые исключения (checked) и неконтролируемые исключения (unchecked), к которым относятся ошибки (Errors) и исключения времени выполнения (RuntimeExceptions, потомок класса Exception). Контролируемые исключения представляют собой ошибки, которые можно и нужно обрабатывать в программе, к этому типу относятся все потомки класса Exception (но не RuntimeException). Обработка исключения может быть произведена с помощью операторов try…catch, либо передана внешней части программы. Например, метод может передавать возникшие в нём исключения выше по иерархии вызовов, сам его не обрабатывая. Неконтролируемые исключения не требуют обязательной обработки, однако, при желании, можно обрабатывать исключения класса RuntimeException. Откомпилируем и запустим такую программу:
class Main {
     public static void main(String[] args) {
         int a = 4;
         System.out.println(a/0);
     }
}
В момент запуска на консоль будет выведено следующее сообщение:
Exception in thread "main" java.lang.ArithmeticException: / by zero
        at Main.main(Main.java:4)
Из сообщения виден класс случившегося исключения — ArithmeticException. Это исключение можно обработать:
class Main {
     public static void main(String[] args) {
         int a = 4;
         try {
              System.out.println(a/0);
         } catch (ArithmeticException e) {
              System.out.println("Произошла недопустимая арифметическая операция");
         }
     }
}
Теперь вместо стандартного сообщения об ошибке будет выполняться блок catch, параметром которого является объект e соответствующего исключению класса (самому объекту можно давать любое имя, оно потребуется в том случае, если мы пожелаем снова принудительно выбросить это исключение, например, для того, чтобы оно было проверено каким-то ещё обработчиком). В блок try при этом помещается тот фрагмент программы, где потенциально может возникнуть исключение. Одному try может соответствовать сразу несколько блоков catch с разными классами исключений.
import java.util.Scanner;
class Main {
    public static void main(String[] args) {
     int[] m = {-1,0,1};
        Scanner sc = new Scanner(System.in);
        try {
            int a = sc.nextInt();
            m[a] = 4/a;
            System.out.println(m[a]);
        } catch (ArithmeticException e) {
            System.out.println("Произошла недопустимая арифметическая операция");
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("Обращение по недопустимому индексу массива");
        }
    }
}
Если запустив представленную программу, пользователь введётся с клавиатуры 1 или 2, то программа отработает без создания каких-либо исключений. Если пользователь введёт 0, то возникнет исключение класса ArithmeticException, и оно будет обработано первым блоком catch. Если пользователь введёт 3, то возникнет исключение класса ArrayIndexOutOfBoundsException (выход за приделы массива), и оно будет обработано вторым блоком catch. Если пользователь введёт нецелое число, например, 3.14, то возникнет исключение класса InputMismatchException (несоответствие типа вводимого значение), и оно будет выброшено в формате стандартной ошибки, поскольку его мы никак не обрабатывали. Можно, однако, добавить обработчик для класса Exception, поскольку этот класс родительский для всех остальных контролируемых исключений, то он будет перехватывать любые из них (в том числе, и InputMismatchException).
import java.util.Scanner;
class Main {
    public static void main(String[] args) {
        int[] m = {-1,0,1};
        int a = 1;
        Scanner sc = new Scanner(System.in);
        try {
            a = sc.nextInt();
            m[a-1] = 4/a;
            System.out.println(m[a]);
        } catch (ArithmeticException e) {
            System.out.println("Произошла недопустимая арифметическая операция");
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("Обращение по недопустимому индексу массива");
        } catch (Exception e) {
            System.out.println("Произошло ещё какое-то исключение");
        }
    }
}
Поскольку исключения построены на иерархии классов и подклассов, то сначала надо пытаться обработать более частные исключения и лишь затем более общие. То есть поставив первым (а не третьим) блок с обработкой исключения класса Exception, мы бы никогда не увидели никаких сообщений об ошибке, кроме «Произошло ещё какое-то исключение» (все исключения перехватились бы сразу этим блоком и не доходили бы до остальных). Необязательным добавлением к блокам try…catch может быть блок finally. Помещенные в него команды будут выполняться в любом случае, вне зависимости от того, произошло ли исключение или нет. При том, что при возникновении необработанного исключения оставшаяся после генерации этого исключения часть программы — не выполняется. Например, если исключение возникло в процессе каких-то длительных вычислений, в блоке finally можно показать или сохранить промежуточные результаты. Ссылка на первоисточник: Исключения и их обработка
Комментарии (18)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Oleg Zaytsev
Уровень 24
2 марта 2019, 23:03
Очень крутая статья
MaxST1994
Уровень 12
23 марта 2016, 19:31
Не понимаю смысл деления uncheke/cheked если некоторые uncheked в большинстве случаев крайне рекомендованы к обработке, к примеру IndexOutOfBOunds, ну или NullPointerException…
kasper1987
Уровень 20
26 марта 2016, 23:25
Смысл такой. Смотри если у тебя вылетает OutOfMemoryError который говорит о том что JVM не хватает памяти, ты же не сможешь это «починить» на лету, это же не исправить память закончилась ее нету!!! Тогда вопрос, зачем это обрабатывать если и так понятно что памяти нету! Тоже самое касается всех АНЧЕКЕД исключениями. А класс РунТайм из родителя Эгзкепшн как раз с той же самой изюминкой. Нет смысла обрабатывать. А такие ошибки как деление на ноль НУЖНО!
MaxST1994
Уровень 12
27 марта 2016, 01:32
Ну окей, а что если я проверяю есть ли пробел перед символом if (true) //some logic
но может оказаться так, что символ первый в строке и тогда проверка (chars[i-1] == ' ') приведет к ошибке ArrayIndexOutOfBoundsException — и тут то я уже предугадываю, что такое возможно, и обрабатываю исключение. То есть это не случайная ошибка и надо внимательно писать код или что то там еще а нет. это заведомо checked ситуация
kasper1987
Уровень 20
27 марта 2016, 07:57
Вы говорите очевидные вещи. Когда речь идёт о простом коде, то такие вещи можно и повнимательней писать. А когда ситуации, в которых код пишет 10000 сотрудников? Это очевидно, что такую ситуацию можно «починить», или исправить «на лету». А если мы мы читаем флешку и её кто то выдернул то тут невозможно «на лету» что-то сделать или исправить, не так ли? Тем более такие ситуации редкие. А вот чтобы, как в вашем примере не плодить код всяким ветвлением. Пример, Вы написали код в котором проверяете массив в виде //code [i+3] //code, допустим массив равен длине = 4, то на 3-й итарации цикла for вылетит ошибка ArrayIndexOutOfBoundsException. Верно? Зачем нам валить программу. Можно исправить это. Добавив исключение. Мы его добавляем. И вуаля, мы проверили массив и не положили программу. На выходе получил код 0. Чего нн скажешь о флешке которой нету, и когда её выдернули, она программе нужна сейчас а её нету. На тебе ошибку. И смысл её обрабатывать, все равно программа слетит! Главное уловить смысл!!!
noxior
Уровень 30
7 февраля 2016, 03:37
на сайте oracle, runtimeexception является unchecked исключением, а в лекции написано противоположное…
Adelaida
Уровень 34
7 февраля 2016, 21:30
дайте пожалуйста цитату в лекции где так написано
b_rhyme
Уровень 17
20 января 2016, 15:09
ArrayIndexOutOfBoundsException (выход за приделы массива)… Можно это как-то исправить?)
mrANDERSON
Уровень 26
21 января 2016, 16:32
Что значит исправить? Исправляется написанием корректного когда, когда индекс не выходит за прЕделы массива…
b_rhyme
Уровень 17
21 января 2016, 20:34
Именно это я и хотел обозначить. Ошибку в слове. И было бы здорово, подкорректировать ее)
mrANDERSON
Уровень 26
22 января 2016, 11:04
Понял) Поддерживаю!
don_bunny
Уровень 26
6 января 2016, 23:57
Читаем по тексту:

1. Контролируемые исключения (checked)
2. Неконтролируемые исключения (unchecked), к которым относятся ошибки (Errors)
3. Исключения времени выполнения (RuntimeExceptions, потомок класса Exception).
remain4life
Уровень 41
8 января 2016, 11:36
На ДВА типа. RuntimeExceptions также относится к uchecked.
P.S. Да и если «читать по тексту», то тогда в тексте «В Java все исключения делятся на три типа: контролируемые исключения (checked) и неконтролируемые исключения (unchecked), к которым относятся ошибки (Errors) и исключения времени выполнения (RuntimeExceptions, потомок класса Exception).» перед второй «и» должна быть запятая по смыслу (+ первая «и» ни к чему тогда).
don_bunny
Уровень 26
8 января 2016, 23:18
Если делать акцент именно на checked и unchecked — то согласен, на два. Но исключений, всё-таки, три — 2 unchecked (с разными предками: один предок Throwable, другой — Exception) и 1 checked.
Стоит обратить внимание на схему иерархии классов — наглядная демонстрация.

Ссылаюсь на материал. По ссылке достаточно подробно описана ситуация.

1. Errors (unchecked) (extends Throwable);
2. Exception (checked) (extends Throwable);
3. RunTimeExceprions (unchecked) (extends Exceprion);

Насчёт знаков препинания претензий не имею. Текст читается легко:
аки
Груши и Яблоки, которые бывают антоновка и белый налив.
контролируемые исключения (checked) и неконтролируемые исключения (unchecked), к которым относятся ошибки (Errors) и исключения времени выполнения (RuntimeExceptions, потомок класса Exception).
remain4life
Уровень 41
9 января 2016, 12:31
Акцент и делается на checked и unchecked, а далее идет просто раскрытие unchecked. Если же говорить об исключениях в плане наследования, то список тогда действительно должен быть таким, как указано в вашем сообщении (но не таким, как в предыдущем).
Насчет знаков препинания — пример конфликтует с вашим утверждением, т.к. в вашем примере ДВА синонима, а к последнему идет расшифровка. В тексте было сказано, что типов ТРИ. После двоеточия идет перечисление. И если дело обстоит так, как вы сказали (что третий тип — RuntimeExceptions), тогда оборот "к которым относятся ошибки (Errors)" должен обособляться запятыми + "и" идет второй раз в перечислении. Если же типов ДВА — тогда с грамматикой все правильно.
mrANDERSON
Уровень 26
21 января 2016, 16:31
Как раз Головач и говорил про 2 типа. RunTimeExceptions это unchecked, т.е. один из двух типов.
Вы говорите ТРИ типа checked, unchecked и unchecked ничего не смущает? :)
mrserfr
Уровень 33
21 декабря 2015, 19:33
В Java все исключения делятся на три типа

на ДВА типа?
mrANDERSON
Уровень 26
29 декабря 2015, 21:31
Наверное таки на ДВА ))