Обработка исключений
В теме Введение в обработку исключений были рассмотрены некоторые основные моменты обработки исключений. Сейчас более подробно поговорим о других моментах, связанных с обработкой исключений.
Оператор throws
Иногда метод, в котором может генерироваться исключение, сам не обрабатывает это исключение. В этом случае в объявлении метода используется оператор throws , который надо обработать при вызове этого метода. Например, у нас имеется метод вычисления факториала, и нам надо обработать ситуацию, если в метод передается число меньше 1:
public static int getFactorial(int num) throws Exception < if(num<1) throw new Exception("The number is less than 1"); int result=1; for(int i=1; i<=num;i++)< result*=i; >return result; >
С помощью оператора throw по условию выбрасывается исключение. В то же время метод сам это исключение не обрабатывает с помощью try..catch, поэтому в определении метода используется выражение throws Exception .
Теперь при вызове этого метода нам обязательно надо обработать выбрасываемое исключение:
public static void main(String[] args) < try< int result = getFactorial(-6); System.out.println(result); >catch(Exception ex) < System.out.println(ex.getMessage()); >>
Без обработки исключение у нас возникнет ошибка компиляции, и мы не сможем скомпилировать программу.
В качестве альтернативы мы могли бы и не использовать оператор throws, а обработать исключение прямо в методе:
public static int getFactorial(int num) < int result=1; try< if(num<1) throw new Exception("The number is less than 1"); for(int i=1; i<=num;i++)< result*=i; >> catch(Exception ex) < System.out.println(ex.getMessage()); result=num; >return result; >
Исключения в Java — пояснение и примеры
Исключение – это нежелательная ситуация, которая возникает во время выполнения программы и нарушает нормальный ход ее работы.
Освітній курс від laba: Клієнтський сервіс.
Залучайте та зберігайте клієнтів.
Такая ситуация может возникнуть, например, при попытке чтения из несуществующего файла, делении на ноль, сбое устройства и так далее. Исключение можно перехватить, чтобы принять соответствующие меры.
Приведем пример кода, в котором возникает исключение.
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)); >>
Если его запустить, получим следующий вывод:
Програмний курс від robotdreams: С++ для GameDev.
Розробка ігор на високому рівні.
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
Для перехвата исключения используется конструкция try – catch . Код, который нужно проверить на исключение, заключается в блок try, а код, обрабатывающий исключение – в блок catch.
Добавим эти блоки в приведенный выше блок кода и дополним его парой переменных для наглядности.
Потужний курс від skvot: blender.
Відкрийте для себе світ 3D-графіки.
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) < LinkedListfruits = new LinkedList(); fruits.add("apple"); fruits.add("banana"); fruits.add("orange"); fruits.add("mango"); // Печатает список ThrowTest.PrintMe(fruits); // Выбрасывает исключение ThrowTest.PrintMe(null); > public static void PrintMe(LinkedList 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.
Професійний курс від laba: Проджект-менеджмент в ІТ.
Ефективне управління проектами.
Когда возникает встроенное исключение, виртуальная машина 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 предоставляет обширный набор встроенных исключений, а также дает программисту гибкость, позволяя создавать собственные исключения в соответствии с потребностями приложения.
Чем опасна throws Exception в сигнатуре функции
Достаточно часто в процессе написания мы используем функции, которые выкидывают исключения (throws Exception).
String returnFoo() throws IllegalArgumentException
Exception — исключение в работе программы. Оно возникает, когда что-то пошло не так. К примеру, не была проинициализирована переменная, а мы обращаемся к ней (и получаем Null Pointer Exception).
В процессе разработки ПО, разработчик может пометить, что данная функция может вызывать исключение, чтобы использующий этот метод обработал исключение. Для чего это надо? Представим, что вы подключились к базе данных, но по какой-то причине не смогли выполнить запрос. В обработке исключений вы должны сообщить (написать в лог), что произошла ошибка выполнения запроса и завершить работу с БД.
Когда мы у себя в коде вызываем функции, которые выкидывают исключения, IDE (среда разработки) заставляет нас их обработать. И сделать мы это можем двумя способами: 1. Добавить в сигнатуру, что этот метод тоже выкидывает данное исключение. Тем самым, мы как бы перекладываем обработку на другого. 2. Добавляем try<> catch <> и обрабатываем исключение сами.
И оба эти метода, в контексте автотестов, таят подводные камни при неправильном их использовании, ведь при обработке ошибок выполнение программы не прерывается.
Рассмотрим первый вариант — исключение в сигнатуре.
Предположим, у нас есть метод, который проверяет две переменные:
public static void checkEquals() throws Exception
Данная проверка заведомо будет провалена. Однако если мы в главном методе вызовем данную функцию (и тоже добавим throws в сигнатуру), то наш код выполнится без ошибок.
public static void main(String[] args) throws Exception
А что, если бы данный метод, скажем, не проверял, а обновлял данные? А мы потом ссылались на эти данные? В итоге, у нас будет ложные срабатывания в тесте, а дебаг будет крайне затруднен.
Рассмотрим теперь второй вариант, где мы обрабатываем ошибку через try<> catch<>. Обычно, начинающие автоматизаторы просто выводят стектрейс в консоль, где они видят, что данный метод завалился:
try < checkEquals(); >catch (Exception e)
Вроде бы, в данном случае все хорошо, ведь ошибка отображается в консоли. Но это более-менее работает до тех пор, пока тесты запускаются локально, а не на удаленной машине из под, к примеру, Jenkins. Ведь он может и не выводить полный лог, а ведь в этом случае вы не увидите ошибку. И, опять же, если у нас на результат выполнения данного метода завязан тест, то выполнение может пойти по совсем непредвиденному пути.
Выводы:
1) e.printStactTrace() можно использовать только для дебага. В продакшн-коде его быть не должно; 2) не используйте throws в сигнатуре методов (при разработке автотестов это нужно очень редко); 3) если вы используете конструкцию try<> catch<> , то обрабатывайте ошибку! Если у вас не получается обработать ошибку или вы не знаете, что делать, то лучше выкиньте throw new RuntimeException(e) в блоке catch , чтобы выполнение тестов сразу завершилось.
Зачем нужен Throws в исключениях?
Возможно я задам глупый вопрос , но я действительно не понимаю зачем нужен throws если есть try и catch? Ведь throws по сути ничего не делает он не обрабатывает исключение а просто их бросает Так зачем тогда нужен throws в исключениях? Заранее спасибо
Отслеживать
задан 20 июл 2020 в 11:49
123 1 1 серебряный знак 10 10 бронзовых знаков
Возможный дубликат вопроса: Почему не обрабатывается исключение IOException?
20 июл 2020 в 11:58
Если у функции есть throws, то при использовании этой функции компилятор заставит вас обернуть её в try catch или добавить очередной throws. загуглите checked exception
20 июл 2020 в 12:08
или отправит дальше проблему
20 июл 2020 в 12:09
На всякий случай уточню: речь точно идет о ключевом слове throws в объявлении метода, а не о throw при выбрасывании исключения. Вообще, не могли бы Вы привести пример кода, который вызывает у Вас вопросы? Так будет яснее что именно вызывает затруднения.
20 июл 2020 в 12:18
Если вопрос именно о throws , то он сводится к более общему вопросу, который уже был задан: Проверяемые исключения 2. А смысл?
20 июл 2020 в 12:22
5 ответов 5
Сортировка: Сброс на вариант по умолчанию
Во-первых, есть два ключевых слова throw и throws . Они используются по разному и я о них поговорю чуть ниже.
Но сначала разберемся зачем нужны механизмы обработки исключений вообще.
Может возникнуть резонный вопрос, «почему бы не отреагировать на ошибку сразу как она возникла?» Зачем вообще нужно «бросать» исключение, чтобы потом его где-то «ловить» и обрабатывать?
Ответ на это такой: далеко не всегда часть программы, в которой случилась ошибка, знает, как на нее правильно отреагировать.
Например, программа для чата по сети (типа skype или telegram) может использовать системную функция send , которая собственно посылает сообщение по сети. Как работает эта функция нас как ее пользователей не особо интересует. Теперь представьте, что во время посылки сообщения, компьютер-адресат выключился (грубо говоря пропало электричество). Функция send определит, что невозможно послать сообщение и вот у нас возникла ошибка.
Теперь встает вопрос, что с этой ошибкой делать. Сама функция не знает, что с ней делать. Эту функцию писали совсем другие люди, они не знают в какой программе ее собираются использовать. Например, функция не может просто показать сообщение об ошибке на экран пользователю, потому, что возможно она используется в программе запущеной на сервере, где и экрана то нету, да и пользователя может не быть, так как это серверная программа, которая запустилась по расписанию, чтобы загрузить в базу данных, скажем, информацию о новых курсах валют из интернета.
Итак, получается. что сама функция send знает, что случилась ошибка, но не знает, что с ней делать. А кто же знает? А знает клиент этой функции, т.е. программа, которая вызвала функцию send . Она то точно знает, что делать. Например, показать пользователю сообщение «Не удалось отослать сообщение» и кнопку «попробовать еще раз», если это программа чата. Или если это была серверная программа, которая загружает курсы валют в базу данных, то она может послать письмо администратору и запланировать повторное выполнение загрузки скажем через час.
Вот мы и подошли к throw . Этот оператор как раз и нужен, чтобы send могла сообщить вызывающей программе об ошибке, т.е. «бросить» (или по другому «возбудить») исключение в функции типа send (т.е. той, которая знает об ошибке, но не знает, что нужно делать, если ошибка возникла).
send будет схематично выглядеть так:
void send(String data) < if (connectToTarget()) < // тут реализация собственно посылки по сети >else < throw new CannotConnectException("Cannot connect to target server"); >>
Теперь, что касается throws . Вопрос зачем это ключевое слово нужно довольно непростой. Тут я упрощенно описываю, чтобы было понятнее. А вообще есть много нюансов, которых я тут не касаюсь (смотрите многочисленные темы по поводу checked vs unchecked exceptions).
Так вот, ключевое слово throws указывается в определении (сигнатуре) функции и оно говорит о том, что функция может бросить такое исключение. Например, для send будет так:
void send(String data) throws CannotConnectException
При этом, когда вы такуя функция вызываете, то либо должны это исключение обработать, т.е. завернуть вызов send в блок try/catch , либо (в случае если вызывающая функция тоже не знает, как обработать исключение) тоже объявить в своей сигнатуре, что она может бросить данное исключение.
Тут важный момент, что эта необходимость обработать или объявить контролируется еще на этапе компиляции, т.е. до того как программа будет запущена.
Задумка авторов языка была такая, чтобы пользователи функции, не забывали обрабатывать исключения, и компилятор об этом напоминал и даже не позволял компилировать (и запускать) такую программу.