Рубріки: Теория

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

Андрій Денисенко

Что такое исключение в Java (Java Exception)?

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

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

Приведем пример кода, в котором возникает исключение.

class ExceptionTest{ 
    // Метод принимает два целых числа
    // и возвращает результат деления
    // первого на второе
    static float divide(int x, int y){
        float result = x / y;
        return result;
    }

    public static void main(String args[]){
        // Эта строка будет выполнена
        System.out.println(divide(4, 2));
        // Эта тоже
        System.out.println(divide(0, 2));
        // Эта выбросит исключение
        System.out.println(divide(4, 0));
    }
}

Если его запустить, получим следующий вывод:

2.0
0.0
Exception in thread "main" java.lang.ArithmeticException: / by zero
        at ExceptionTest.divide(ExceptionTest.java:6)
        at ExceptionTest.main(ExceptionTest.java:16)

Выводятся два результата деления и сообщение об исключении. В этом сообщении указана следующая информация:

  • тип исключения (ArithmeticException);
  • какое именно исключение возникло (деление на ноль);
  • стек выполнения: методы и строки, в которых возникло исключение.

Курсы по изучению Java от наших друзей Mate Academy и Hillel, помогут вам разобраться не только в основах языка программирования, но и в тонкостях работы с ним.

Операторы try, catch, finally, throw, throws: обработка исключений и примеры использования

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

try-catch

Для перехвата исключения используется конструкция trycatch. Код, который нужно проверить на исключение, заключается в блок try, а код, обрабатывающий исключение – в блок catch.

Добавим эти блоки в приведенный выше блок кода и дополним его парой переменных для наглядности.

class ExceptionTest{  
    // Метод принимает два целых числа
    // и возвращает результат деления
    // первого на второе
    static float divide(int x, int y){
        float result = x / y;
        return result;
    }

    public static void main(String args[]){
        int x = 4;
        int y = 2;
        try {
            // Эта строка будет выполнена
            System.out.println(divide(x, y));

            x = 0;
            // Эта тоже
            System.out.println(divide(x, y));

            x = 4;
            y = 0;
            // Эта выбросит исключение
            System.out.println(divide(x, y));
        } catch (ArithmeticException e) {
            System.out.println("Ошибка при делении " + x + " на " + y);
        }
    }
}

Получим более удобочитаемый вывод:

2.0
0.0
Ошибка при делении 4 на 0

finally

Блок finally выполняется после try-catch, независимо от того, возникло ли исключение. Это необязательный блок, но если нет блока catch, то блок finally необходим.

В этом блоке можно, например, закрыть файл, открытый в блоке try, как в приведенном ниже коде.

import java.io.FileWriter;
import java.io.IOException;

public class FinallyTest {
    public static void main(String[] args) {
        FileWriter writer = null;
        try {
            writer = new FileWriter("out.txt");
            writer.write("Writing to the file!");
            System.out.println("Файл записан успешно.");
        } catch (IOException e) {
            System.out.println("Ошибка записи в файл.");
            e.printStackTrace();
        } finally {
            if ( writer != null ){
                try{
                  writer.close();
                } catch (IOException e) {
                  System. out.println("Ошибка закрытия файла.");
                  e.printStackTrace();
                }
            }
        }
    }
}

 

throw

В некоторых случаях требуется выбросить исключение самостоятельно. Это делается при помощи ключевого слова throw.

В данном примере метод PrintMe выбрасывает исключение, если его аргумент равен null.

import java.util.LinkedList;

public class ThrowTest
{
  public static void main(String[] args) {
        LinkedList<String> fruits = new LinkedList<String>();
        fruits.add("apple");
        fruits.add("banana");
        fruits.add("orange");
        fruits.add("mango");

        // Печатает список
        ThrowTest.PrintMe(fruits);

        // Выбрасывает исключение
        ThrowTest.PrintMe(null);
  }

    public static void PrintMe(LinkedList<String> fruits){
        if (fruits == null){
            throw new NullPointerException("Аргумент не инициализирован");
        }
        System.out.println(fruits);
    }
}

throws

Ключевое слово throws используется, чтобы в сигнатуре метода указать, что он выбрасывает исключение. Его можно использовать, чтобы передавать исключения по стеку вызовов и указать, что эти исключения не обязательно должны обрабатываться в методе, в котором они объявлены.

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class ThrowsTest{
    public static void readFromFile() throws IOException {
        // Указываем несуществующий файл, чтобы проверить работу исключения
        try (BufferedReader reader = new BufferedReader(new FileReader("out.txt"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line + "\n");
            }
        }
    }

    public static void main(String[] args) {
    try {
            readFromFile();
        } catch (IOException ioe) {
            System.out.println("Файл не найден");
        }
    }
}

Иерархия исключений Java

Исключения в Java делятся на две основные категории: встроенные и пользовательские.

Встроенные исключения

Встроенные исключения – это исключения, которые заранее определены в Java.

Когда возникает встроенное исключение, виртуальная машина Java (JVM) создает объект, принадлежащий классу встроенного исключения. Все исключения происходят от класса java.lang.Throwable, но они определены в нескольких пакетах.

Класс Throwable происходит непосредственно об класса Object и является корневым классом дерева классов исключений. От него происходят два подкласса: Error и Exception. Ошибки и исключения, которые встречаются в программах на Java, являются объектами этих классов.

С использованием класса Throwable можно создавать собственные исключения.

Класс Error является надклассом для всех классов ошибок времени выполнения. Он завершает выполнение программы, если происходит ошибка, связанная с системой или ресурсами (JVM).

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

Примеры ошибок: AssertionError, LinkageError, OutOfMmeoryError, StackOverFlowError, VirtualMachineError.

Класс Exception представляет ошибки, вызванные программой или внешними факторами. Это надкласс для все классов исключений.

Для этого класса существует два конструктора:

  • public Exception() (по умолчанию)
  • public Exception(String message) (принимает строковое сообщение как аргумент)

Эти конструкторы наследуются всеми подклассами исключений. Сам по себе класс Exception не предоставляет собственных методов. Он наследует методы класса Throwable.

Встроенные исключения делятся на две группы: проверяемые (checked) и непроверяемые (unchecked).

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

Проверяемые исключения проверяются компилятором Java во время компиляции и не являются подклассами RuntimeException (исключения времени выполнения).

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

Проверяемые исключения обрабатываются либо в блоке try-catch, либо в объявлении метода с ключевым словом throws. Если исключение не обработано, происходит ошибка компиляции.

Проверяемыми исключениями являются все исключения, кроме RuntimeException, Error и их подклассов.

Примеры проверяемых исключений: ClassNotFoundException, IOException, SQLException, IllegalAccessException, FileNotFoundException.

Непроверяемые исключения (исключения времени выполнения) в Java

Непроверяемые исключения в Java – это исключения, которые проверяются JVM, а не компилятором Java. Они возникают во время выполнения программы.

Все подклассы RuntimeException называются непроверяемыми исключениями или исключениями времени выполнения в Java.

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

Компилятор Java не проверяет исключения времени выполнения во время компиляции, независимо от того, обрабатывает ли их программа.

Если в методе возникает исключение времени выполнения, а программист не обрабатывает его, JVM прекращает выполнение программы, не выполняя остаток кода.

Примеры непроверяемых исключений: ArithmeticException, ArrayIndexOutOfBoundsException, ClassCastException, NegativeArraySizeException, NullPointerException.

В Java определено множество встроенных исключений. Ниже приведены описания некоторых из них.

Исключение Описание
ArithmeticException Выбрасывается, когда возникает исключительная арифметическая ситуация.
ArrayIndexOutOfBoundsException Выбрасывается при попытке обратиться к массиву по недействительному индексу.
ArrayStoreException Выбрасывается при попытке сохранить объект несоответствующего типа в массиве объектов.
ClassCastException Выбрасывается, когда код совершает попытку привести тип объекта к подклассу, экземпляром которого он не является.
ClassNotFoundException Выбрасывается, когда приложение совершает попытку загрузить класс по его имени в строковом представлении с использованием метода forName в классе Class.
CloneNotSupportedException Выбрасывается, когда для клонирования объекта определенного класса вызван метод clone, но класс этого объекта не реализует интерфейс Cloneable.
EnumConstantNotPresentException Выбрасывается, когда приложение производит попытку обратиться к константе из перечисления по имени, но тип этого перечисления не содержит константу с указанным именем.
Exception Класс Exception и его подклассы являются подклассами Throwable и указывают на ситуации, которые могут быть перехвачены приложением.
IllegalAccessException Выбрасывается, когда приложение совершает попытку применить рефлексию, чтобы создать экземпляр (отличный от массива), присвоить полю значение или получить значение поля, вызвать метод, но текущий выполняемый метод не имеет доступа к определению указанного класса, поля, метода или конструктора.
IllegalArgumentException Выбрасывается, когда методу передан недопустимый или неприемлемый аргумент.
IllegalMonitorStateException Выбрасывается, когда нить пытается ожидать монитор объекта или отправить оповещение другим нитям, ожидающим монитор объекта, но указанный монитор не принадлежит ей.
IllegalStateException Выбрасывается, когда метод вызван в недопустимое или неприемлемое время.
IllegalThreadStateException Выбрасывается, когда нить находится в неприемлемом состоянии для выполнения запрошенной операции.
IndexOutOfBoundsException Выбрасывается, когда индекс определенного типа (например, для массива, строки или вектора) находится вне допустимого диапазона.
InstantiationException Выбрасывается, когда приложение совершает попытку создать экземпляр класса с использованием метода newInstance класса Class, но создать экземпляр указанного класса невозможно.
InterruptedException Выбрасывается, когда нить находится в состоянии ожидания, сна или занята каким-либо другим образом, но ее работа прервана либо перед выполнением действия, либо после его выполнения.
NegativeArraySizeException Выбрасывается, когда приложение совершает попытку создать массив отрицательного размера.
NoSuchFieldException Выбрасывается, когда в классе отсутствует поле с указанным именем.
NoSuchMethodException Выбрасывается, когда невозможно найти указанный метод.
NullPointerException Выбрасывается, когда приложение совершает попытку использовать значение null, но требуется указать объект.
NumberFormatException Выбрасывается, когда приложение совершает попытку преобразовать строку в один из числовых типов, но строка имеет недопустимый формат.
RuntimeException Это родительский класс для тех исключений, которые могут быть выброшены при нормальной работе виртуальной машины Java.
SecurityException Выбрасывается менеджером безопасности при нарушении безопасности.
StringIndexOutOfBoundsException Выбрасывается методами класса String при попытке использовать отрицательный индекс или индекс, превышающий размер строки.
TypeNotPresentException Выбрасывается, когда приложение совершает попытку доступа к типу с указанием его имени в виде строки, но не удается найти определение типа с указанным именем.
UnsupportedOperationException Выбрасывается, когда запрошенная операция не поддерживается.

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

Пользовательские исключения создаются пользователями или программистами в соответствии с их собственными потребностями. Они создаются путем расширения класса Exception.

Примером пользовательского исключения может служить исключение, выбрасываемое, если пользователь пытается открыть банковский счет, но не достиг возраста 18 лет. В таком случае может быть выдано сообщение о том, что требуется открыть счет с кем-то из родителей. 

Чтобы использовать пользовательское исключение, нужно выполнить следующие действия.

  • Определить класс, расширяющий класс Exception.
  • Определить конструктор. Если не требуется хранить сведения об исключении, определяется конструктор по умолчанию. Если требуется сохранить сведения об исключении в виде строки, определяется конструктор с параметром.
  • Создать объект пользовательского исключения и выбросить его с помощью ключевого слова throw.

Пример исключения с конструктором по умолчанию:

class MyException extends Exception{
    // Конструктор по умолчанию
    MyException(){}
}

class Main{
    public static void main(String[] args){
        try{
            MyException e = new MyException();
            throw e;
        }
        catch(MyException ex){
             System.out.println("Перехвачено пользовательское исключение"); 
        }
    }
}

Этот код выведет следующий текст: “Перехвачено пользовательское исключение”.

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

class MyException extends Exception{
    MyException(String msg){
        super(msg);
    }
}

class Main{
    public static void main(String[] args){
        try{
            MyException e = new MyException("Перехвачено пользовательское исключение с информацией");
            throw e;
        }
        catch(MyException ex){
             System.out.println(ex.getMessage()); 
        }
    }
}

Вывод будет таким:   “Перехвачено пользовательское исключение с информацией”

Заключение

Исключения в Java позволяют указать пути обхода проблем и исправления их последствий. С их помощью можно поместить логику обработки исключительных ситуаций в отдельные блоки кода (catch), оставив основную логику в блоке try, а логику завершающих действий по обработке исключения – в блоке finally. Исключения могут быть обработаны в методах, где они возникают, или переданы далее с помощью ключевых throw и throws.

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

Останні статті

Обучение Power BI – какие онлайн курсы аналитики выбрать

Сегодня мы поговорим о том, как выбрать лучшие курсы Power BI в Украине, особенно для…

13.01.2024

Work.ua назвал самые конкурентные вакансии в IТ за 2023 год

В 2023 году во всех крупнейших регионах конкуренция за вакансию выросла на 5–12%. Не исключением…

08.12.2023

Украинская IT-рекрутерка создала бесплатный трекер поиска работы

Unicorn Hunter/Talent Manager Лина Калиш создала бесплатный трекер поиска работы в Notion, систематизирующий все этапы…

07.12.2023

Mate academy отправит работников в 10-дневный оплачиваемый отпуск

Edtech-стартап Mate academy принял решение отправить своих работников в десятидневный отпуск – с 25 декабря…

07.12.2023

Переписки, фото, история браузера: киевский программист зарабатывал на шпионаже

Служба безопасности Украины задержала в Киеве 46-летнего программиста, который за деньги устанавливал шпионские программы и…

07.12.2023

Как вырасти до сеньйора? Девелопер создал популярную подборку на Github

IT-специалист Джордан Катлер создал и выложил на Github подборку разнообразных ресурсов, которые помогут достичь уровня…

07.12.2023