Узнайте, как работать с исключениями в Java

Исключение в Java:

  1. Что такое исключение?
  2. Типы исключений.
  3. Как обрабатывать исключения?
  4. Как сбросить исключение?
  5. Пользовательские исключения.

Что такое исключение?

Исключение — это механизм в Java для обработки непредвиденных ситуаций. В большинстве случаев неожиданная ситуация является неожиданным входом.

Например, чтобы преобразовать число строки в число int, мы можем использовать метод Integer.parseInt(str). Он принимает строку в качестве аргумента и ожидает, что мы передадим число как строку, чтобы получить его как целое число. Но никто не может помешать нам передать любую строку. Если мы передадим строку «10hello», что должна делать программа? Да, сгенерируйте исключение и сообщите, что ввод был неправильным.

На приведенном выше рисунке показан пример исключения, сгенерированного нашей программой.

Давайте рассмотрим еще один пример.

В приведенном выше примере мы будем ArrayIndexOutOfBoundsException. Мы создали массив размером 3 и пытаемся получить доступ к 4-му элементу. Четвертого элемента нет, в нашем массиве всего 3 элемента. Таким образом, java выдаст исключение, которое имеет смысл.

Когда возникнет исключение, вы увидите стек исключений в консоли. Стек исключений — это набор классов, задействованных в конкретной проблеме. Мы знаем, что один класс может использовать другой класс, а этот класс — другой и так далее, поэтому стек исключений покажет вам эту цепочку классов. Он идет сверху вниз. Первая строка стека является наиболее подробной и содержит основное сообщение и причину исключения. Мы всегда читаем стек исключений сверху вниз.

Типы исключений

Исключения в java представлены набором классов. Существует два типа исключений — исключение времени выполнения (непроверенное) и проверенное исключение. У нас также есть ошибка в java. Ошибки не являются исключениями, и мы никогда не должны обрабатывать и выдавать ошибки внутри нашей программы. По поведению ошибки аналогичны исключениям времени выполнения.

Исключения во время выполнения

На приведенном выше рисунке показана диаграмма структуры исключений (включая не все классы исключений). Обратите внимание, что класс Throwable имеет два прямых дочерних класса Error и Exception. Мы не должны бросать или обрабатывать Throwable (это возможно). Каждый класс, который расширяет Error, в основном является ошибкой, и каждый класс, который расширяет Exception, является исключением.

Теперь исключения времени выполнения выделены на картинке.

  1. Исключения времени выполнения — это исключения, которые расширяют класс RuntimeException.
  2. Они необязательны для обработки. Ниже мы обсудим, как обрабатывать исключения.

Проверенные исключения

  1. Класс Exception и его подклассы, за исключением RuntimeException, являются проверенными исключениями.
  2. Java требует, чтобы код обрабатывал проверенные исключения, иначе он просто не скомпилируется.

Ошибка

  1. Ошибки выдаются JVM и не должны их обрабатывать. Ошибки учитываются при возникновении серьезных системных сбоев (таких как переполнение памяти). Поэтому нет смысла обрабатывать это на уровне приложения.
  2. Мы никогда не выдаем ошибку.
  3. Ошибки бывают редко.

Как обработать исключение?

Для обработки исключений мы можем использовать оператор try-catch.

Код, который потенциально генерирует исключение, мы можем поместить в тело оператора try. Если возникнет исключение, оно будет обработано оператором catch, и его тело будет выполнено. В операторе catch мы можем указать, какое исключение обрабатывать. В приведенном выше примере мы обрабатываем исключение NumberFormatException. Поэтому, когда возникнет исключение и если мы перехватим это исключение, будет выполнено тело оператора catch. Вот как мы справляемся с этим. Вы можете просто распечатать что-то, как мы сделали в нашем примере, или вы можете делать все, что хотите, это действительно зависит от ваших требований и спецификаций программы.

У нас может быть несколько операторов catch в нашем операторе try-catch. Это позволяет нам по-разному обрабатывать разные исключения. Есть одно правило — меньшее (или можно сказать исключение подкласса) исключение всегда должно быть сверху. В нашем примере NullPointerException является подклассом (не прямым) Exception, поэтому мы ставим его первым.

Если мы сначала поместим большее (родительское) исключение, оно не скомпилируется, потому что родительское исключение может перехватить все его дочерние исключения.

Приведенный выше пример работает нормально. Даже если программа выдаст NullPointerException, Exception его перехватит. Как мы уже обсуждали выше, Exception может его перехватить, потому что это родительский класс для NullPointerException. Вывод этой программы будет

Exception hanled

Обратите внимание, что в выводе нет Hello, World! трижды. Из строки, где генерируется исключение, оно будет напрямую переходить к телу оператора catch, если мы обрабатываем правильный тип исключения. В противном случае он выкинет его на консоль.

Теперь давайте обсудим, как объявить исключение, и мы поговорим о проверенных исключениях.

Наш приведенный выше пример должен печатать Good Day! 10 раз и ждать 1 секунду после каждой печати. Для ожидания мы используем Thread.sleep(1000) . Причина, по которой он не компилируется, заключается в том, что наш метод сна throws проверил исключение. И мы должны обрабатывать или объявлять проверенные исключения.

Теперь он работает нормально и будет печатать Good Day! 10 раз с ожиданием по одной секунде после каждого. Мы справились с этим с помощью оператора try-catch. В этом коде нет ничего плохого, и исключений не возникнет. И тогда зачем нам с этим справляться? Потому что так это работает в Java. В большинстве случаев методы, которые throws проверяли исключения, могут генерировать реальное исключение, поэтому он заставляет клиентский код обрабатывать его, даже если он может не генерировать никаких исключений. В нашем примере Thread.sleep(1000);method приостанавливает поток, а потоки управляются ОС. Я думаю, что этот метод не может дать стопроцентную гарантию приостановки потока, поэтому он throws проверяет исключение и заставляет клиентский код его обработать.

Мы можем использовать экземпляр исключения e (в нашем случае), чтобы получить информацию об этом исключении.

Приведенный выше пример также отлично работает без ошибок компиляции. Обратите внимание, что мы удалили try-catch и добавили throws InterruptedException в объявление основного метода. Именно так мы объявляем исключения. Исключения могут быть объявлены только на уровне метода в объявлении метода. Объявление исключения означает, что мы сообщаем, что наш метод потенциально throws является исключением. Если вы объявили проверенное исключение в своем методе, код, который будет использовать ваш метод, должен обработать или объявить его.

public static native void sleep(long millis) throws InterruptedException;

Вот так выглядит объявление метода Thread.sleep. Вы видите, что он объявляет InterruptedException в объявлении своего метода. Когда мы использовали, мы должны были обработать или объявить это.

Мы создали отдельный метод для печати наших сообщений с помощью Thread.sleep. Мы объявляем throws InterruptedException в нашем методе и там все хорошо. Но посмотрите, когда мы используем наш метод, он выдает ошибку компилятора необработанного исключения. Итак, строка 12 в нашем методе выдает проверенное исключение, и мы должны его обработать. Мы обрабатываем это, объявляя его в нашем методе. На самом деле мы говорим следующее: «Я знаю, что мой код генерирует проверенное исключение, но я не хочу его обрабатывать, и код, который будет использовать этот метод, должен его обрабатывать». Вот почему строка 6 выдает ошибку компилятора.

Вы можете объявить родительское исключение, и оно будет обрабатывать все дочерние исключения. Кроме того, вы можете объявить несколько исключений.

Как сбросить исключение?

Мы можем генерировать собственное исключение.

public void setAge(int age) {
    if (age < 0) {
        throw new IllegalArgumentException("Age cannot be negative");
    }

    this.age = age;
}

Здесь мы выбрасываем собственное исключение. Мы используем ключевое слово throw и создаем экземпляр исключения, которое нам нужно сгенерировать. В нашем случае мы генерируем исключение, если age указано как отрицательное.

Пользовательские исключения

Мы можем создать собственный тип исключения, расширив существующие исключения. Если мы хотим создать проверенное исключение, мы можем расширить класс Exception, а если мы хотим создать исключение во время выполнения, мы можем расширить класс RuntimeException.

Это все, что у меня есть для исключений в Java. Спасибо!

This article is part of the series of articles to learn Java programming language from Tech Lead Academy:
1. Introduction to programming 
2. OS, File, and File System
3. Working with terminal 
4. Welcome to Java Programming Language
5. Variables and Primitives in Java
6. Methods with Java
7. Java Math Operators and special operators
8. Conditional branching in Java
9. Switch statement in Java
10. Ternary operator in Java
11. Enum in Java
12. String class and its methods in Java
13. Loops in Java
14. Access modifiers in Java
15. Static keyword in Java
16. The final keyword in Java
17. Class and Object in Java
18. Object Oriented Programming in Java
19. OOP: Encapsulation in Java
20. Inheritance in Java
21. Abstraction in Java
22. Polymorphism in Java
23. Overriding vs Overloading in Java
24. OOP Design Principles in Java
25. Array in Java
26. Data Structures with Java
27. Collection framework in Java
28. ArrayList in Java
29. Set in Java
30. Map in Java
31. LocalDate in Java
32. Exception in Java
33. IO in Java
34. Design Patterns
35. Generics in Java
36. Multithreading in java
37. JUnit
38. Big O Notation for coding interviews
39. Top 17 Java coding interview questions for SDET