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

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

Ошибки времени выполнения, такие как ClassNotFoundException, IOException, SQLException, RemoteException и т. д., обычно обрабатываются с помощью обработки исключений.

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

Всякий раз, когда во время выполнения возникает исключение или какая-либо ошибка, исключения связаны с объектами в Java. Исключение Java возникает во время создания объекта.

Для реализации обработки исключений в Java компилятор предоставляет один пакет, который является пакетом по умолчанию и включает класс Exception.

java.язык.Исключение.*;

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

В Java основным классом для обработки исключений является Throwable, который является родительским классом как для классов исключений, так и для классов ошибок.

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

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

  • В основном существует два типа исключений: отмеченные и неотмеченные. Здесь ошибка рассматривается как непроверенное исключение. Согласно Oracle, существует три типа исключений:
  • Проверенное исключение
  • Непроверенное исключение
  • Ошибка

проверенное исключение

  • Классы, которые напрямую наследуют класс Throwable, за исключением RuntimeException и Error, называются проверенными исключениями. Checked Exceptions проверяются на во время компиляции.
  • Пример: IOException, SQLException и т. д.

Непроверенное исключение

  • Классы, наследующие RuntimeException, называются непроверенными исключениями. Непроверенные исключения не проверяются во время компиляции. Но они проверяются во время выполнения.
  • Пример: ArrayIndexOutOfBoundsException, NullPointerException, ArithmeticExceptionи т. д.

Ошибка

  • Ошибка неисправима
  • например OutOfMemoryError, VirtualMachineError, AssertionError и т. д.

Разница между ошибкой и исключением заключается в следующем:

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

Исключения в Java в основном делятся на две категории:

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

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

  • Арифметическое исключение
  • Класснотфаундексцептион
  • IOException
  • ArrayIndexOutOfBoundsException
  • FileNotFoundException
  • Исключение нулевого указателя
  • носачфиелдексцептион
  • NoSuchMethodException
  • StringIndexOutOfBoundsException
  • Исключение времени выполнения
  • NumberFormatException
  • InterruptedException и т.д.

Код без обработки исключений (встроенное исключение)

class Exc0 {
  public static void main(String args[]) {
    int d = 0;
    int a = 42/d;
   }
}

java.lang.ArithmeticException: / на ноль в Exc0.main(Exc0.java:4)

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

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

  • Это типы исключений, которые можно перехватывать с помощью некоторых настраиваемых исключений, созданных пользователем, и пользователь должен иметь возможность обрабатывать эти исключения. Эти исключения также можно назвать проверенными исключениями или исключениями времени компиляции.
// File Name InsufficientFundsException.

import java.io.*;
public class InsufficientFundsException extends Exception { private double amount;
public InsufficientFunds Exception (double amount) { this.amount = amount;
}
public double getAmount() { return amount;
}
}

Здесь InsufficientFundsException — определяемый пользователем класс исключений.

Основной синтаксис исключительной обработки:

try{
// block of code to monitor for errors
}

catch (Exception Type1 exOb) {
// exception handler for Exception Typel
} 

catch (Exception Type2 exOb) { 
// exception handler for Exception Type2
}

// ...
finally {
// block of code to be executed after try block ends
}

Обработка исключений:

Для обработки исключений в Java используются пять ключевых слов:

  1. пытаться
  2. ловить
  3. окончательно
  4. бросать
  5. бросает

1. попробуйте:

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

2. поймать:

Оператор catch позволяет определить блок кода, который будет выполняться, если в блоке try произойдет ошибка.

// Syntax 

try {
  //  Block of code to try
}
catch(Exception e) {                     // e - object
  //  Block of code to handle errors
}

Примечание. Ключевые слова try и catch идут парами, и есть один блок «try» и «finally» и несколько блоков catch.

Рассмотрим следующий пример:

public class Main {
  public static void main(String[ ] args) {
    int[] myNumbers = {1, 2, 3};
    System.out.println(myNumbers[10]); // error!
  }
}

// This will generate an error, because myNumbers[10] does not exist.

Вывод будет примерно таким:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 10
at Main.main(Main.java:4)

Если возникает ошибка, мы можем использовать try...catch, чтобы поймать ошибку и выполнить некоторый код для ее обработки:

public class Main {
  public static void main(String[ ] args) {
    try {
      int[] myNumbers = {1, 2, 3};
      System.out.println(myNumbers[10]);
    } catch (Exception e) {
      System.out.println("Something went wrong.");
    }
  }
}

Вывод будет:

Something went wrong.

3. Наконец:

Оператор finally позволяет выполнять код после try...catch независимо от результата:

public class Main {
  public static void main(String[] args) {
    try {
      int[] myNumbers = {1, 2, 3};
      System.out.println(myNumbers[10]);
    } catch (Exception e) {
      System.out.println("Something went wrong.");
    } finally {
      System.out.println("The 'try catch' is finished.");
    }
  }
}

Вывод будет:

Something went wrong.
The 'try catch' is finished.

4. Ключевое слово throw:

Оператор throw позволяет создать пользовательскую ошибку.

Оператор throw используется вместе с типом исключения. В Java доступно множество типов исключений: ArithmeticException, FileNotFoundException, ArrayIndexOutOfBoundsException, SecurityException и т. д.:

Пример

Генерировать исключение, если возраст меньше 18 лет (выведите «Доступ запрещен»). Если возраст 18 лет и старше, напечатайте «Доступ предоставлен»:

public class Main {
  static void checkAge(int age) {
    if (age < 18) {
      throw new ArithmeticException("Access denied - You must be at least 18 years old.");
    }
    else {
      System.out.println("Access granted - You are old enough!");
    }
  }

  public static void main(String[] args) {
    checkAge(15); // Set age to 15 (which is below 18...)
  }
}

Вывод будет:

Exception in thread "main" java.lang.ArithmeticException: Access denied - You must be at least 18 years old.
at Main.checkAge(Main.java:4)
at Main.main(Main.java:12)

Если бы age было равно 20, вы не получили бы исключение:

Пример

checkAge(20);

Вывод будет:

Access granted - You are old enough!

5. бросает:

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

В Java доступно множество типов исключений: ArithmeticException, ClassNotFoundException, ArrayIndexOutOfBoundsException, SecurityException и т. д.

Различия между throw и throws:

Примеры: Наиболее распространенные исключения Java

1. Исключение ClassNotFoundException

Если какой-либо класс определен неправильно, это приведет к ClassNotFoundException.

package com.journaldev.exceptions;

public class DataTest {

  public static void main(String[] args) {
    try {
      Class.forName("com.journaldev.MyInvisibleClass");

      ClassLoader.getSystemClassLoader().loadClass("com.journaldev.MyInvisibleClass");

      ClassLoader.getPlatformClassLoader().loadClass("com.journaldev.MyInvisibleClass");
    } catch (ClassNotFoundException e) {
      e.printStackTrace();
    }
  }
}

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

java.lang.ClassNotFoundException: com.journaldev.MyInvisibleClass
 at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:582)
 at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:185)
 at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:496)
 at java.base/java.lang.Class.forName0(Native Method)
 at java.base/java.lang.Class.forName(Class.java:292)
 at com.journaldev.exceptions.DataTest.main(DataTest.java:7)

В приведенном выше примере все три оператора будут выдавать java.lang.ClassNotFoundException.

Исправить ClassNotFoundException очень легко, поскольку трассировка стека исключений четко указывает, что класс не найден. Просто проверьте настройки пути к классу и убедитесь, что класс присутствует во время выполнения.

2. Исключение ArrayIndexOutOfBoundsException

Всякий раз, когда осуществляется доступ к какому-либо неправильному индексу, а диапазон индекса недоступен и недоступен, возникает ArrayIndexOutOfBoundsException.

public class ArrayIndexOutOfBoundsExceptionExample {
    public static void main(String[] args) {
        String[] arr = new String[10]; 
        System.out.println(arr[11]);
    }
}

В этом примере создается массив String длины 10. Затем делается попытка получить доступ к элементу с индексом 10, который выходит за пределы диапазона массива, выдавая ArrayIndexOutOfBoundsException:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 10 out of bounds for length 10
    at ArrayIndexOutOfBoundsExceptionExample.main(ArrayIndexOutOfBoundsExceptionExample.java:4)

Чтобы избежать ArrayIndexOutOfBoundsException, следует помнить следующее:

  • Границы массива должны быть проверены перед доступом к его элементам.
  • Массив в Java начинается с индекса 0 и заканчивается индексом length - 1, поэтому доступ к элементам, выходящим за пределы этого диапазона, вызовет ошибку ArrayIndexOutOfBoundsException.
  • Пустой массив не имеет элементов, поэтому попытка доступа к элементу вызовет исключение.
  • При использовании циклов для перебора элементов массива следует обращать внимание на начальные и конечные условия цикла.

3. Исключение NullPointerException

Ошибка NullPointerException возникает из-за ситуации в коде приложения, когда предпринимается попытка доступа или изменения неинициализированного объекта. По сути, это означает, что ссылка на объект никуда не указывает и имеет нулевое значение.

Некоторые из наиболее распространенных сценариев для NullPointerException:

  • Вызов методов для нулевого объекта
  • Доступ к свойствам нулевого объекта
  • Доступ к элементу индекса (например, в массиве) нулевого объекта
  • Передача нулевых параметров в метод
  • Неправильная конфигурация для фреймворков внедрения зависимостей, таких как Spring.
  • Использование synchronized для нулевого объекта
  • Выброс null из метода, который выдает исключение.
public class NullPointerExceptionExample {
    private static void printLength(String str) {
        System.out.println(str.length());
    }

    public static void main(String args[]) {
        String myString = null;
        printLength(myString);
    }
}


/* Exception in thread "main" java.lang.NullPointerException
        at NullPointerExceptionExample.printLength(NullPointerExceptionExample.java:3)
        at NullPointerExceptionExample.main(NullPointerExceptionExample.java:8)      */

В этом примере метод printLength() вызывает метод length() строки, не выполняя проверку нуля перед вызовом метода. Поскольку значение строки, переданной из метода main(), равно null, выполнение приведенного выше кода вызывает ошибку NullPointerException..

Чтобы исправить NullPointerException в приведенном выше примере, строку следует проверить на нулевые или пустые значения, прежде чем она будет использоваться дальше:

import org.apache.commons.lang3.StringUtils;

public class NullPointerExceptionExample {
    private static void printLength(String str) {
        if (StringUtils.isNotEmpty(str)) {
            System.out.println(str.length());
        } else {
            System.out.println("Empty string");
        }
    }

    public static void main(String args[]) {
        String myString = null;
        printLength(myString);
    }
}

Код обновляется с проверкой в ​​методе printLength(), которая гарантирует, что строка не пуста, используя метод StringUtils.isNotEmpty() apache commons. Только если строка не пуста, вызывается метод length() строки, иначе он выводит сообщение Empty string на консоль.

4. Исключение ClassCastException

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

Например, объект String не может быть приведен к объекту Integer, и попытка сделать это приведет к ошибке ClassCastException. Поскольку ClassCastException является непроверяемым исключением, его не нужно объявлять в предложении throws метода или конструктора.

Некоторые из наиболее распространенных источников ClassCastException в Java:

  • Использование таких коллекций, как HashMap, ArrayList и HashTable, которые не используют Java Generics.
  • Использование методов, которые были написаны для интерфейсов до Java 5, использующих полиморфизм.
  • Не использовать безопасность типов при приведении объектов в Java.

Пример выдачи ClassCastException при попытке привести строку к целому числу:

public class NullPointerExceptionExample {
    private static void printLength(String str) {
        System.out.println(str.length());
    }

    public static void main(String args[]) {
        String myString = null;
        printLength(myString);
    }
}

/*  Exception in thread "main" java.lang.ClassCastException: class java.lang.String cannot be cast to class java.lang.Integer
    at ClassCastExceptionExample.main(ClassCastExceptionExample.java:4)      */

Здесь строка obj пытается быть приведена к целому числу. Поскольку это не экземпляр класса Integer, эта операция выдает ошибку ClassCastException..

Чтобы исправить ClassCastException в приведенном выше примере, необходимо проверить тип объекта перед выполнением операции приведения:

public class ClassCastExceptionExample {
    public static void main(String[] args) {
        Object obj = new String("Hello");
 
        if (obj instanceof Integer) {
            System.out.println((Integer) obj);
        } else {
            System.out.println(obj);
        }
    }
}

// Output: Hello

Код обновляется с проверкой, которая гарантирует, что obj является экземпляром класса Integer, прежде чем он будет приведен к Integer. Операция приведения выполняется только в том случае, если проверка проходит успешно. Приведенный выше код успешно выполняется без выдачи ClassCastException.