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

Операторы «кораблей»

Итак, все знают об операторе «космический корабль» с момента выхода PHP 7. Но менее известно, что одновременно с этим релизом был введён целый флот космических кораблей для проведения крупномасштабных операций.

Крошечный космический корабль

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

X-истребители

Если вы хотите добавить огневую мощь к предыдущему флоту, вы можете вызвать истребителей типа X к источнику PHP: . Следующий код вычитает 3 у (в оригинальной статье написано, что оператор прибавит 3 (), но это не так, см. вывод примера ниже — прим. пер.)

Линейный корабль

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

Разве не лучший способ написать так?

Звезда Смерти

Многие из вас бы спросили, а был ли встроен в PHP оператор «звезда смерти», и ответ таков: в данный момент неизвестно. Есть планы на это, но никто никогда не видел реального экземпляра. Мне бы очень хотелось видеть оператор в три строки, так как PHP будет первым, кто будем иметь подобное (и, когда это произойдёт, надеюсь, не с моего счёта спишут стоимость этого оператора).

Генерация исключений

Последнее обновление: 24.03.2021

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

class Person
{
	private $name, $age;
	function __construct($name, $age)
	{
		$this->name = $name;
		$this->age = $age;
	}
	function printInfo()
	{
		echo "Name: $this->name<br>Age: $this->age";
	}
}
$tom = new Person("Tom", -105);
$tom->printInfo();

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

Для генерации исключения применяется оператор throw, после которого указывается объект исключения.

Например, изменим выше определенный код класса Person:

class Person
{
	private $name, $age;
	function __construct($name, $age)
	{
		if($age < 0)
		{
			throw new Exception("Недействительный возраст");
		}
		$this->name = $name;
		$this->age = $age;
	}
	function printInfo()
	{
		echo "Name: $this->name<br>Age: $this->age";
	}
}
$tom = new Person("Tom", -105);
$tom->printInfo();

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

throw new Exception("Недействительный возраст");

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

В итоге при выполнении строки

$tom = new Person("Tom", -105);

будет выполняться код

throw new Exception("Недействительный возраст");

И в итоге в браузере мы увидем информацию об ошибке:

Fatal error: Uncaught Exception: Недействительный возраст in D:\localhost\hello.php:17 Stack trace: #0 D:\localhost\hello.php(26): Person->__construct('Tom', -105) #1 {main} thrown in D:\localhost\hello.php on line 17

Поскольку вызов конструктора класса Person создает ситуацию, в которой потенциально может возникнуть исключение, то лучше вызов конструктора поместить
в конструкцию :

class Person
{
	private $name, $age;
	function __construct($name, $age)
	{
		$this->name = $name;
		if($age < 0)
		{
			throw new Exception("Недействительный возраст");
		}
		$this->age = $age;
	}
	function printInfo()
	{
		echo "Name: $this->name<br>Age: $this->age";
	}
}

try
{
	$tom = new Person("Tom", -105);
	$tom->printInfo();
}
catch(Exception $ex)
{
	echo $ex -> getMessage();
}

Вывод браузера:

Недействительный возраст

Создание классов исключений

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

class PersonInvalidAgeException extends Exception
{
	function __construct($age)
	{
		$this -> message = "Недействительный возраст: $age. Возраст должен быть в диапазоне от 0 до 120";
	}
}
class Person
{
	private $name, $age;
	function __construct($name, $age)
	{
		$this->name = $name;
		if($age < 0)
		{
			throw new PersonInvalidAgeException($age);
		}
		$this->age = $age;
	}
	function printInfo()
	{
		echo "Name: $this->name<br>Age: $this->age";
	}
}

try
{
	$tom = new Person("Tom", -105);
	$tom->printInfo();
}
catch(PersonInvalidAgeException $ex)
{
	echo $ex -> getMessage();
}

Для примера здесь определен простенькй класс исключения, который унаследован от класса Exception. (В реальности чтобы создать класс исключения,
достаточно реализовать интерфейс Throwable). В этом классе переопределяется конструктор, который в качестве параметра принимает недействительный возраст.

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

Недействительный возраст: -105. Возраст должен быть в диапазоне от 0 до 120

НазадВперед

Несколько блоков catch

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

  1. Один блок try может иметь любое количество блоков catch.
  2. Общий блок catch может обрабатывать все исключения. Будь то ArrayIndexOutOfBoundsException или ArithmeticException или NullPointerException или любой другой тип исключения.
catch(Exception e){
  //This catch block catches all the exceptions
}

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

  1. Если в блоке try не возникает исключение, блоки catch полностью игнорируются.
  2. Соответствующие блоки catch выполняются для конкретного типа исключения: catch(ArithmeticException e) является блоком catch, который может обрабатывать ArithmeticException catch(NullPointerException e) является блоком catch, который может обрабатывать NullPointerException
  3. Вы также можете выбросить исключение. Это рассмотрено в других уроках: пользовательское исключение, ключевое слово throws, throw vs throws.

Пример нескольких блоков catch

class Example2{
   public static void main(String args[]){
     try{
         int a[]=new int;
         a=30/0;
         System.out.println("First print statement in try block");
     }
     catch(ArithmeticException e){
        System.out.println("Warning: ArithmeticException");
     }
     catch(ArrayIndexOutOfBoundsException e){
        System.out.println("Warning: ArrayIndexOutOfBoundsException");
     }
     catch(Exception e){
        System.out.println("Warning: Some Other exception");
     }
   System.out.println("Out of try-catch block...");
  }
}

Выход:

Warning: ArithmeticException
Out of try-catch block...

В приведенном выше примере есть несколько блоков catch, и эти блоки выполняются последовательно, когда в блоке try возникает исключение. Это означает, что если вы поместите последний блок catch(catch(Exception e)) на первое место, сразу после блока try, то в случае любого исключения этот блок будет выполнен, поскольку он может обрабатывать все исключения. Этот блок должен быть размещен в последнюю очередь, чтобы избежать таких ситуаций.

Использование предопределенных типов исключений .NETUse the predefined .NET exception types

Создавайте новый класс исключений, только если предопределенное исключение не подходит.Introduce a new exception class only when a predefined one doesn’t apply. Пример:For example:

  • Вызывайте исключение InvalidOperationException, если значение свойства или вызов метода не соответствуют текущему состоянию объекта.Throw an InvalidOperationException exception if a property set or method call is not appropriate given the object’s current state.

  • Порождайте исключение ArgumentException или одного из предварительно определенных классов, которые являются производными от ArgumentException, если передаются недопустимые параметры.Throw an ArgumentException exception or one of the predefined classes that derive from ArgumentException if invalid parameters are passed.

Basic Use of Exceptions

When an exception is thrown, the code following it will not be executed, and
PHP will try to find the matching «catch» block.

If an exception is not caught, a fatal error will be issued with an «Uncaught
Exception» message.

Lets try to throw an exception without catching it:

<?php
//create function with an exception
function checkNum($number) {
  if($number>1) {
    throw new Exception(«Value must be 1 or below»);
  }
  return true;
}
//trigger exception
checkNum(2);
?>

The code above will get an error like this:

Fatal error: Uncaught exception ‘Exception’
with message ‘Value must be 1 or below’ in C:\webfolder\test.php:6
Stack trace: #0 C:\webfolder\test.php(12):
checkNum(28) #1 {main} thrown in C:\webfolder\test.php on line 6

Примеры обработки ошибок

Давайте теперь рассмотрим несколько простых примеров с процедурами обработки ошибок.

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

Приведенный ниже код реализует приведенный выше пример.

Предполагая, что вы сохранили файл simple_error.php в папке phptuts, откройте URL-адрес http: //localhost/phptuts/simple_error.php

Вы получите следующие результаты

Как видно из приведенных выше результатов, это делает наше приложение непрофессиональным и может раздражать пользователя.

Мы изменим приведенный выше код и напишем обработчик ошибок для приложения.

Предполагая, что вы сохранили приведенный выше код как error_handling.php, откройте URL-адрес http: //localhost/phptuts/error_handling.php.

Примечание. Для обеспечения безопасности рекомендуется отображать сообщение, подобное показанному выше, вместо сообщения типа «Файл не найден».

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

Пользовательский обработчик ошибок будет установлен как функция обработки ошибок PHP по умолчанию и будет в основном отображать номер ошибки и сообщение.

Приведенный ниже код иллюстрирует реализацию приведенного выше примера.

Откройте URL-адрес http: //localhost/phptuts/custom_error_handler.php, вы получите следующие результаты

.

Как видно из приведенного выше примера, специальные обработчики ошибок мощны в том смысле, что

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

Давайте теперь посмотрим на третий тип обработки ошибок. Мы будем использовать встроенную функцию PHP error_reporting. Он имеет следующий базовый синтаксис

ЗДЕСЬ,

  • Error_reporting — функция отчета об ошибках PHP.
  • «$ Reporting_level» является необязательным, может использоваться для установки уровня отчетности. Если уровень отчетности не указан, PHP будет использовать уровень отчетов об ошибках по умолчанию, как указано в файле php.ini.
Уровень отчетности Описание Пример
E_WARNING Отображает только предупреждающие сообщения. Не останавливает выполнение скрипта error_reporting (E_WARNING);
E_NOTICE Отображает уведомления, которые могут появиться во время нормального выполнения программы или могут быть ошибкой. error_reporting (E_ УВЕДОМЛЕНИЕ);
E_USER_ERROR Отображает сгенерированные пользователем ошибки, то есть настраиваемый обработчик ошибок error_reporting (E_ USER_ERROR);
E_USER_WARNING Отображает предупреждающие сообщения, созданные пользователем error_reporting (E_USER_WARNING);
E_USER_NOTICE Отображает уведомления, созданные пользователями error_reporting (E_USER_NOTICE);
E_RECOVERABLE_ERROR Отображает ошибку, которая не является фатальной и может быть обработана с помощью пользовательских обработчиков ошибок. сообщение об ошибке (E_RECOVERABLE_ERROR);
E_ALL Отображает все ошибки и предупреждения error_reporting (E_ ALL);

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

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

  • Вы хотите отображать настраиваемое сообщение в зависимости от сгенерированного исключения
  • Вы хотите выполнить уникальную операцию в зависимости от сгенерированного исключения

На блок-схеме ниже показано, как работают несколько исключений.

Давайте посмотрим на пример, в котором используется несколько исключений.

Мы изменим код, который делит число на переданный знаменатель.

Мы ожидаем возникновения двух типов исключений;

  • Деление на ноль
  • Деление на отрицательное число

Для простоты мы будем отображать только тип исключения в наших блоках catch.

Встроенный в PHP класс Exception используется для создания исключений.

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

В приведенном ниже коде показана реализация.

Учебный пример, в котором есть примеры использования всех классов исключений:

class Example
{
  protected $author;  
  protected $month;  
  protected $goals = [];
  
  public function exceptions(int $a, int $b): int
  {
    $valid_a = ;
    if (!is_int($a)) {
      throw new InvalidArgumentException("a должно быть целочисленным!");
    }
    if ($a > 5 || !in_array($a, $valid_a, true)) {
      throw new DomainException("a не может быть больше 5");
    }
    
    $c = $this->getByIndex($a);
    if (!is_int($c)) {
      throw new RangeException("c посчитался неправильно!");
    } else {
      return $c;
    }      
  }
  
  private function getByIndex($a)
  {
    return ($a < 100) ? $a + 1 : null;
  }
  
  public function deleteNextGoal()
  {
    if (empty($this->goals)) {
      throw new UnderflowException("Нет цели, чтобы удалить!");
    } elseif (count($this->goals) > 100000) {
      throw new OverflowException("Система не может оперировать больше, чем 100000 целями одновременно!");
    } else {
      array_pop($this->goals);
    }
  }
  
  public function getGoalByIndex($i)
  {
    if (!isset ($this->goals)) {
      throw new OutOfBoundsException("Нет цели с индексом $i"); // легитимные значения известны только во время выполнения
    } else {
      return $this->goals;
    }
  }
  
  public function setPublicationMonth(int $month)
  {
    if ($month < 1 || $month > 12) {
      throw new OutOfRangeException("Месяц должен быть от 1 до 12!"); // легитимные значения известны заранее
    }
    $this->month = $month;
  }
  
  public function setAuthor($author)
  {
    if (mb_convert_case($author, MB_CASE_UPPER) !== $author) {
      throw new InvalidArgumentException("Все буквы имени автора должны быть заглавными");
    } else {
      if (mb_strlen($author) > 255) {
        throw new LengthException("Поле автор не должно быть больше 255 сиволов!");
      } else {
        $this->author = $author;
      }
    }
  }
  
  public function __call(string $name, array $args)
  {
    throw new BadMethodCallException("Метод Example>$name() не существует");
  }
}

Вот и всё. Думаю, материал буде полезен как новичкам, так и более продвинутым программистам. Я постарался систематизировать информацию об исключениях в одной статье.

Исключения[править]

В Java возможна обработка ошибок с помощью исключений:

Double f(Double a, Double b) {
     ((a == ) || (b == )) {
         IllegalArgumentException();
    }
    
     a / b;
}

Проверять на равенство нулю уже нет необходимости, так как при делении на ноль метод бросит .

Исключения позволяют:

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

Каждый раз, когда при выполнении программы происходит ошибка, создается объект-исключение, содержащий информацию об ошибке, включая её тип и состояние программы на момент возникновения ошибки.
После создания исключения среда выполнения пытается найти в стеке вызовов метод, который содержит код, обрабатывающий это исключение. Поиск начинается с метода, в котором произошла ошибка, и проходит через стек в обратном порядке вызова методов. Если не было найдено ни одного подходящего обработчика, выполнение программы завершается.

Таким образом, механизм обработки исключений содержит следующие операции:

  1. Создание объекта-исключения.
  2. Заполнение stack trace’а этого исключения.
  3. Stack unwinding (раскрутка стека) в поисках нужного обработчика.

Обеспечение доступности данных об исключении при удаленном выполнении кодаEnsure that exception data is available when code executes remotely

При создании пользовательских исключений следует обеспечить доступность метаданных исключений для удаленно исполняемого кода.When you create user-defined exceptions, ensure that the metadata for the exceptions is available to code that is executing remotely.

Например, для реализаций .NET, которые поддерживают домены приложений, могут возникать исключения для этих доменов.For example, on .NET implementations that support App Domains, exceptions may occur across App domains. Предположим, что домен приложения А создает домен приложения В, который выполняет код, вызывающий исключение.Suppose App Domain A creates App Domain B, which executes code that throws an exception. Чтобы домен приложения A правильно перехватил и обработал исключение, он должен найти сборку, которая содержит исключение, порожденное доменом приложения B. Если домен приложения B порождает исключение, содержащееся в сборке в его базовой папке приложения, но не в базовой папке приложения домена A, то домен приложения A не сможет найти исключение и среда CLR породит исключение FileNotFoundException.For App Domain A to properly catch and handle the exception, it must be able to find the assembly that contains the exception thrown by App Domain B. If App Domain B throws an exception that is contained in an assembly under its application base, but not under App Domain A’s application base, App Domain A will not be able to find the exception, and the common language runtime will throw a FileNotFoundException exception. Чтобы избежать такой ситуации, можно развернуть сборку, содержащую сведения об исключении, двумя способами:To avoid this situation, you can deploy the assembly that contains the exception information in two ways:

  • Поместите эту сборку в общую базу приложения, совместно используемую обоими доменами приложений.Put the assembly into a common application base shared by both app domains.

    — или — or —

  • Если у этих доменов нет общей базы приложения, то подпишите сборку, содержащую сведения об исключении, строгим именем и разверните ее в глобальном кэше сборок.If the domains do not share a common application base, sign the assembly that contains the exception information with a strong name and deploy the assembly into the global assembly cache.

Гарантии безопасности[править]

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

  • Отсутствие гарантий (no exceptional safety). Если было брошено исключение, то не гарантируется, что все ресурсы будут корректно закрыты и что объекты, методы которых бросили исключения, могут в дальнейшем использоваться. Пользователю придется пересоздавать все необходимые объекты и он не может быть уверен в том, что может переиспозовать те же самые ресурсы.
  • Отсутствие утечек (no-leak guarantee). Объект, даже если какой-нибудь его метод бросает исключение, освобождает все ресурсы или предоставляет способ сделать это.
  • Слабые гарантии (weak exceptional safety). Если объект бросил исключение, то он находится в корректном состоянии, и все инварианты сохранены. Рассмотрим пример:
 Interval {
    
    
    double left;
    double right;
    
}

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

Сильные гарантии (strong exceptional safety). Если при выполнении операции возникает исключение, то это не должно оказать какого-либо влияния на состояние приложения. Состояние объектов должно быть таким же как и до вызовов методов.

Гарантия отсутствия исключений (no throw guarantee). Ни при каких обстоятельствах метод не должен генерировать исключения. В Java это невозможно, например, из-за того, что VirtualMachineError может произойти в любом месте, и это никак не зависит от кода. Кроме того, эту гарантию практически невозможно обеспечить в общем случае.

Проверяемые исключения: throws, checked exceptions

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

Все исключения, унаследованные от классов и , считаются unchecked-исключениями, все остальные — checked-исключениями.

Важно!

Спустя 20 лет после введения проверяемых исключений, почти все Java-программисты считают это ошибкой. 95% всех исключений в популярных современных фреймворках — непроверяемые. Тот же язык C#, который чуть ли не скопировал Java подчистую, не стал добавлять checked-исключения.

В чем же основное отличие checked-исключений от unchecked?

К checked-исключениям есть дополнительные требования. Звучат они примерно так.

Требование 1

Если метод выбрасывает checked-исключение, он должен содержать тип этого исключения в своем заголовке (сигнатуре метода)

Чтобы все методы, которые вызывают данный метод, знали о том, что в нем может возникнуть такое «важное исключение»

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

Пример:

checked-исключение unchecked-исключение

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

Если метод планирует выкидывать несколько checked-исключений, все их нужно указать после ключевого слова через запятую. Порядок неважен. Пример:

Требование 2

Если вы вызываете метод, у которого в сигнатуре прописаны checked-исключения, то вы не можете проигнорировать этот факт.

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

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

Пример:

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

Создаем Землю Примечание
Метод потенциально кидает два checked-исключения:

  • ПустойМир
  • ОдинокийМир

Вызов этого метода можно обработать 3 способами:

1. Не перехватываем возникающие исключения

Чаще всего это делается в случае, когда в методе не известно, как правильно обработать эту ситуацию.

Код Примечание
Вызывающий метод не перехватывает исключения и вынужден информировать о них других: добавить их себе в

2. Перехватывать часть исключений

Обрабатываем понятные ошибки, непонятные — прокидываем в вызывающий метод. Для этого нужно добавить их название в throws:

Код Примечание
Вызывающий метод перехватывает только одно checked-исключение – , второе он должен добавить в свою сигнатуру: указать после слова

3. Перехватываем все исключения

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

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

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

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

 (t == ) {
     NullPointerException();
}

Есть два стандартных конструктора для всех исключений: первый — конструктор по умолчанию, второй принимает строковый аргумент, поэтому можно поместить подходящую информацию в исключение.

Возможна ситуация, когда одно исключение становится причиной другого. Для этого существует механизм exception chaining. Практически у каждого класса исключения есть конструктор, принимающий в качестве параметра – причину исключительной ситуации. Если же такого конструктора нет, то у есть метод , который можно вызвать один раз, и передать ему исключение-причину.

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

 f()  InterruptedException, IOException { 

try-catch-finallyправить

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

 {
    
}

Сразу после блока проверки следуют обработчики исключений, которые объявляются ключевым словом catch.

 {
    
} (Type1 id1) {
    
} (Type2 id2) {
    
}

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

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

NB: Если JVM выйдет во время выполнения кода из или , то -блок может не выполниться. Также, например, если поток выполняющий или код остановлен, то блок может не выполниться, даже если приложение продолжает работать.

Блок удобен для закрытия файлов и освобождения любых других ресурсов. Код в блоке должен быть максимально простым. Если внутри блока будет брошено какое-либо исключение или просто встретится оператор , брошенное в блоке исключение (если таковое было брошено) будет забыто.

 java.io.IOException;

 ExceptionTest {
   
     main(String[] args) {
         {
             {
                Exception();
            }  {
                 IOException();
            }
        }  (IOException ex) {
            System..println(ex.getMessage());
        }  (Exception ex) {
            System..println(ex.getMessage());
        }
    }
}

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

Обработка исключений, вызвавших завершение потокаправить

При использовании нескольких потоков бывают ситуации, когда поток завершается из-за исключения. Для того, чтобы определить с каким именно, начиная с версии Java 5 существует интерфейс . Его реализацию можно установить нужному потоку с помощью метода . Можно также установить обработчик по умолчанию с помощью статического метода .

Интерфейс имеет единственный метод , в который передается экземпляр потока, завершившегося исключением, и экземпляр самого исключения. Когда поток завершается из-за непойманного исключения, JVM запрашивает у потока , используя метод , и вызвает метод обработчика – . Все исключения, брошенные этим методом, игнорируются JVM.

Информация об исключенияхправить

  • . Этот метод возвращает строку, которая была первым параметром при создании исключения;
  • возвращает исключение, которое стало причиной текущего исключения;
  • печатает stack trace, который содержит информацию, с помощью которой можно определить причину исключения и место, где оно было брошено.
Exception in thread "main" java.lang.IllegalStateException: A book has a null property
        at com.example.myproject.Author.getBookIds(Author.java:38)
        at com.example.myproject.Bootstrap.main(Bootstrap.java:14)
Caused by: java.lang.NullPointerException
        at com.example.myproject.Book.getId(Book.java:22)
        at com.example.myproject.Author.getBookIds(Author.java:35)

Все методы выводятся в обратном порядке вызовов. В примере исключение было брошено в методе , который был вызван в . «Caused by» означает, что исключение является причиной .

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector