Исключения Java

Защита от дурака — стандартная конструкция для любого приложения. Рассмотрим, как организовать её в Java.
15 сентября 2017326451Илья Бубнов1590417

Одно из стандартных требований ТЗ на разработку ПО – отсутствие ошибок и конфликтов, препятствующих нормальной работе. Путей реализации два – ограничить функциональность и возможности пользователя или создать код, который будет учитывать возможные неприятности.

В java исключением называется любая ошибка, которая возникает в ходе выполнения программы. Это может быть несоответствие типов данных, деление на ноль, обрыв связи с сервером и многое другое. Операции по их поиску и предотвращению называются обработкой исключений.

Иерархия

Прежде чем мы перейдём к практике, давайте познакомимся с видами исключений Джава и их иерархией. В основе всего лежит класс Throwable. Все возможные конфликты кода с машиной и пользователем описаны здесь. Для удобства обработки и чтения класс Throwable имеет подклассы Error и Exception. Error – критические ошибки, которые не обязательно происходят по вине пользователя, обработать их невозможно. Exception – собственно конфликты нашей программы, которые необходимо отлавливать.

Взгляните на упрощённую схему иерархии исключений java:

Как видно, блоки делятся на «два лагеря» по цветам  — проверяемые и непроверяемые java исключения. Данная классификация показывает, как их воспринимает компилятор: проверяемые – учитывает, непроверяемые – игнорирует. К первому относится Exception в полном составе, кроме RuntimeException. Все остальные классы исключений – непроверяемые компилятором.

Иерархия классов исключений важна и для правильной организации кода. Допустим, у вас есть несколько блоков обработки. Тогда в начале необходимо указать низшие уровни, а в конце – высшие. В противном случае, будет запущен только первый блок, а остальные – проигнорированы.

Создание обработчика

Для обработки исключений java используются следующие операторы: try, catch, finally, throw, throws. Первые три — стандартная структура вашего блока. По шагам:

  1. Оператор или часть кода, в которой вам надо отыскать ошибку, помещается в блок try.
  2. Далее в блоке catch вы указываете, что за исключение надо ловить и как его обрабатывать.
  3. В блоке finally набор обязательных действий при возникновении ошибки. Обычно это запись данных, закрытие ресурсов и пр. Блок исполняется всегда, вне зависимости от срабатывания catch.

Рассмотрим структуру на примере Джава исключения:

try {
// код, где мы хотим отследить ошибку
}
catch (тип_исключения объект_исключения) {
// код обработки
}
finally {
// что нужно выполнить после завершения блока try
}

Если вы хотите обработать несколько исключений – просто создайте ещё один блок catch.

try {
// код, где мы хотим отследить ошибку
}
catch (тип_исключения_1 объект_исключения_1) {
// код обработки
}
catch (тип_исключения_2 объект_исключения_2) {
// код обработки
}
finally {
// что нужно выполнить после завершения блока try
}

С помощью оператора throw вы можете создавать исключения:

throw экземпляр_Throwable

На практике это выглядит так:

Student stud1;
public void onClick(View view) {
  if(stud1 == null){
    throw new NullPointerException("Студента не существует");
  }
}

Включим оператор throw в наш стандартный пример с try-catch:

public void onClick(View view) {
  if (stud1 == null) {
    try {
      throw new NullPointerException("Студента не существует");
    } catch (NullPointerException e) {
      Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
    }
  }
}

Как только обработка дойдёт до оператора throw, дальнейшее выполнение кода будет прекращено. Обработчик рассмотрит ближайший блок try-catch на требуемое исключение, потом следующий и так до конца кода. В случае, если вызвать ява исключение неоткуда – обработчик остановит программу.

Оператор throws используется для методов, которые содержат исключения, но их не обрабатывают.

тип имя_метода(список_параметров) throws список_исключений {
// код метода
}

Несколько исключений в списке необходимо перечислить через запятую. Воспользовавшись такой конструкцией, вы сообщите всем вызывающим методам о необходимости учитывать исключения. 

Операторы try можно вкладывать друг в друга. При этом если вложенный обработчик не имеет своего блока catch, он осуществляет его поиск в родительском операторе. Если и там нет – блок обрабатывается системой.

Готовые и новые исключения

Далее приведём список java исключений, которые вам потребуются в работе чаще других:

  • ArithmeticException - ошибки вычислений.
  • NullPointerException - ссылка на пустое место.
  • NegativeArraySizeException - массив отрицательной размерности.
  • ArrayStoreException - присвоение элементу массива неправильного типа.
  • NumberFormatException - невозможно преобразовать строку в число.
  • IllegalArgumentException - неправильный аргумент при вызове метода.
  • UnsupportedOperationException - указанной операции не существует.
  • TypeNotPresentException - указанного типа не существует.

Все указанные типы java исключений содержатся в классе RuntimeException, а значит, их не надо указывать в блоке throws.

Естественно, система не может содержать всевозможные исключения. Некоторые придётся создавать самостоятельно. Для того, чтобы создать собственное java исключение, вам необходимо унаследовать собственный класс от Exception и переопределить требуемые методы класса Throwable. Или унаследоваться от наиболее близкого по смыслу типа. Рассмотрим на примере программы под android создание java исключения:

package geekbrains.exception;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
}

public void testMethod() throws StudentException {
  System.out.println("Возбуждаем StudentException из метода testMethod()");
  throw new StudentException(); // конструктор по умолчанию
}

public void testMethod2() throws StudentException {
  System.out.println("Возбуждаем StudentException из метода testMethod2()");
  throw new StudentException("Создано во втором методе");
}

public void onClick(View view) {
  try {
    testMethod();
  } catch (StudentException e) {
    e.printStackTrace();
    System.out.println("Исключение перехвачено");
  }

  try {
    testMethod2();
  } catch (StudentException e) {
    e.printStackTrace();
  }
}

class StudentException extends Exception {
  StudentException() {
}

StudentException(String msg) {
  super(msg);
}
}
}

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

Новые комментарии