English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
В этом уроке вы изучите, как использовать Java для обработки исключений. Чтобы обработать исключения, мы будем использовать блок try ... catch ... finally.
В предыдущем уроке мы изучили исключения. Исключения - это внезапные события, которые происходят в процессе выполнения программы.
В Java мы используем компоненты обработки исключений try, catch и finally, чтобы обрабатывать исключения.
Чтобы捕获 и обработать исключения, мы размещаем блок кода try...catch...finally вокруг кода, который может генерировать исключения. Блок finally является опциональным.
Синтаксис try...catch...finally:
try { // код catch (ExceptionType e) { // блок улавливания } // блок finally }
Код, который может генерировать исключения, должен быть размещен в блоке try.
За каждым блоком try должен следовать блок catch или finally. При возникновении исключения он будет捕获 блок, который следует за catch.
Блок catch не может использоваться в отдельности, он должен следовать сразу за блоком try.
class Main { public static void main(String[] args) { try { int divideByZero = 5 / 0; System.out.println("остальной код в блоке try"); } System.out.println("ArithmeticException => " + e.getMessage()); } } }
Результат вывода
ArithmeticException => деление на ноль
В данном примере
Мы делим число на ноль в блоке try. Это вызывает исключение ArithmeticException.
При возникновении исключения программа пропускает оставшийся код в блоке try.
В данном случае мы создали блок catch для обработки исключения ArithmeticException. Поэтому выполняются инструкции в блоке catch.
Если все инструкции в блоке try не генерируют исключений, пропускается блок catch.
Для каждого блока try может быть ноль или несколько блоков catch.
Тип параметра каждого блока catch указывает на тип исключений, которые он может обрабатывать. Множественные блоки catch позволяют обрабатывать каждую исключительную ситуацию по-разному.
class ListOfNumbers { public int[] arrayOfNumbers = new int[10]; public void writeList() { try { arrayOfNumbers[10] = 11; } System.out.println("NumberFormatException => " + e1.getMessage()); } System.out.println("IndexOutOfBoundsException => " + e2.getMessage()); } } } class Main { public static void main(String[] args) { ListOfNumbers list = new ListOfNumbers(); list.writeList(); } }
Результат вывода
IndexOutOfBoundsException => Index 10 out of bounds for length 10
В данном примере мы объявили целочисленный массив arrayOfNumbers размером 10.
Мы знаем, что индексы массива всегда начинаются с 0. Поэтому, когда мы пытаемся присвоить значение индексу 10, возникает исключение IndexOutOfBoundsException, так как граница массива arrayOfNumbers составляет 0 до 9.
Когда в блоке try возникает исключение:
Исключение передается первому блоку catch. Первый блок catch не обрабатывает исключение IndexOutOfBoundsException, поэтому оно передается следующему блоку catch.
Второй блок catch в данном примере является подходящим обработчиком исключений, так как он обрабатывает исключение IndexOutOfBoundsException. Поэтому он выполняется.
Для каждого блока try может быть только один блок finally.
Блок finally является опционным. Но если он определен, он всегда выполняется (даже если не происходит исключения).
Если происходит исключение, то выполняется после блока try...catch. Если не происходит исключений, то выполняется после блока try.
Основная грамматика блока finally:
try { //код } //блок catch } //блок catch } //Блок finally всегда выполняется }
class Main { public static void main(String[] args) { try { int divideByZero = 5 / 0; } System.out.println("ArithmeticException => " + e.getMessage()); } System.out.println("Блок finally всегда выполняется"); } } }
Результат вывода
ArithmeticException => деление на ноль Блок finally всегда выполняется
В этом примере мы делим числа на ноль. Это вызывает ArithmeticException, которыйcatch-блок улавливает, блок finally всегда выполняется.
Использование блока finally считается хорошей практикой. Это потому, что он содержит важные коды очистки, такие как
Может быть пропущен код, неожиданно прерванный операторами return, continue или break
Закрытие файлов или соединений
Мы уже упоминали, что finally всегда выполняется, обычно это такое. Но в некоторых случаях блок finally не выполняется:
Использование метода System.exit()
В блоке finally произошел исключение
Тред был остановлен
Давайте рассмотрим пример, в котором мы пытаемся создать новый файл с помощью FileWriter и записать данные с помощью PrintWriter.
import java.io.*; class ListOfNumbers { private int[] list = new int[10]; public ListOfNumbers() { //В списке массива хранятся целочисленные значения for (int i = 0; i < 10; i++) { list[i] = i; } } } public void writeList() { PrintWriter out = null; try { System.out.println("Вход в блок try"); //Создать новый файл OutputFile.txt out = new PrintWriter(new FileWriter("OutputFile.txt")); //Записать значения из массива списка в новый созданный файл for (int i = 0; i < 10; i++) { out.println("Значение в: " + i + " = " + list[i]); } } System.out.println("IndexOutOfBoundsException => " + e1.getMessage()); } System.out.println("IOException => " + e2.getMessage()); } //Проверить, открыт ли PrintWriter if (out != null) { System.out.println("Закрыть PrintWriter"); out.close(); } else { System.out.println("PrintWriter не может быть открыт"); } } } } class Main { public static void main(String[] args) { ListOfNumbers list = new ListOfNumbers(); list.writeList(); } }
При запуске этой программы могут произойти две возможности:
Произошло исключение в блоке try
Блок try был выполнен normally
Может произойти исключение при создании нового FileWriter. Если не удалось создать или записать指定的 файл, будет выброшено IOException.
Если произошло исключение, мы получим следующий вывод.
Войти в блок try IOException => OutputFile.txt PrintWriter не может быть открыт
Если не произошло исключение и блок try был выполнен normalmente, мы получим следующий вывод.
Войти в блок try Закрыть PrintWriter
Будет создан файл OutputFile.txt, содержащий следующее
Значение в: 0 = 0 Значение в: 1 = 1 Значение в: 2 = 2 Значение в: 3 = 3 Значение в: 4 = 4 Значение в: 5 = 5 Значение в: 6 = 6 Значение в: 7 = 7 Значение в: 8 = 8 Значение в: 9 = 9
Давайте постараемся подробнее понять процесс обработки исключений с помощью примера.
Upper diagram describes the program execution flow when an exception occurs while creating a new FileWriter.
Чтобы найти метод, вызываемый исключением, метод main вызывает метод writeList(), который затем вызывает метод FileWriter() для создания нового файла OutputFile.txt.
При возникновении исключения runtime-система пропускает оставшийся код в блоке try.
Он начинает искать в обратном порядке в呼叫ном стеке, чтобы найти подходящий обработчик исключений.
Здесь у FileWriter нет обработчика исключений, поэтому при выполнении системы проверяется следующий метод в呼叫ном стеке, то есть writeList.
Метод writeList имеет два обработчика исключений: один обрабатывает IndexOutOfBoundsException, а другой обрабатывает IOException.
Затем система последовательно обрабатывает эти обработчики.
В этом примере первый обработчик обрабатывает IndexOutOfBoundsException. Это не соответствует IOException, вызванному блоком try.
Таким образом, проверяется,哪个 обработчик IOException следующий. Если он соответствует типу возникшего исключения, то выполняется код в соответствующем блоке catch.
После выполнения программы обработки исключений выполняется блок finally.
В этом сценарии, поскольку в FileWriter произошел исключение, объект PrintWriter out никогда не открывался, поэтому его не нужно закрывать.
Теперь предположим, что при выполнении программы исключение не произошло, и блок try был выполнен normalmente. В этом случае будет создан и записан файл OutputFile.txt.
Известно, что выполнение блока finally не зависит от обработки исключений. Поскольку исключение не произошло, PrintWriter был открыт и требует закрытия. Это выполняется с помощью строки out.close() в блоке finally.
С Java SE 7 и выше, теперь мы можем捕获 не один тип исключений одним блоком catch.
Таким образом, можно уменьшить повторение кода и повысить простоту и эффективность кода.
Каждый тип异常, который может быть обработан блоком catch, разделен вертикальной линией (|).
Его грамматика такая:
try { // код catch (ExceptionType1 | Exceptiontype2 ex) { // блок catch }
Чтобы узнать больше информации, пожалуйста, посетитеJava перехват нескольких исключений.
Предложение try-with-resources - это предложение try, которое имеет один или несколько объявлений ресурсов.
Его грамматика такая:
try (ресурс объявления) { // использование ресурса } catch (ExceptionType e1) { // блок catch }
Ресурсы - это объекты, которые необходимо закрыть в конце программы. Их необходимо объявить и инициализировать в предложении try.
Давайте приведем пример.
try (PrintWriter out = new PrintWriter(new FileWriter("OutputFile.txt"))) { // использование ресурса }
Предложение try-with-resources также называетсяАвтоматическое управление ресурсами. Это предложение автоматически закрывает все ресурсы в конце предложения.
Чтобы узнать больше информации, пожалуйста, посетитеJava предложение try-with-resources.