1. Изключения

>

Най-накрая програмистите се сетиха да стандартизират и автоматизират обработката на грешки. Това се случи, когато бяха измислени изключения . Сега механизмът за изключения обработва 80% от изключителните ситуации.

Ако някой учен направи изключения, това вероятно е било темата на неговата or нейната докторска дисертация. Ако програмист го е измислил, тогава той може да е получил приятелско потупване по гърба от колега: "Изглежда добре, брато."

Когато възникне грешка в Java програма, като деление на 0, се случват някои чудесни неща:

Първа стъпка

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

Всичко в Java е обект и изключенията не са изключения 🙂 Обектите с изключения имат свои собствени класове и единственото нещо, което ги отличава от обикновените класове е, че наследяват класа Throwable.

Стъпка втора

Обектът за изключение е "хвърлен". Може би формулировката тук би могла да бъде по-добра. „Подаване на изключение“ е по-скоро като задействане на пожарна аларма or прозвучаване на предупреждение „DEFCON 1“.

Когато бъде хвърлено изключение към Java машината, нормалната работа на програмата спира и започват „спешни протоколи“.

Стъпка трета

Методът, в който е хвърлено изключението, излиза веднага. Изключението се предава на извикващия метод, който също излиза незабавно. И така надолу по веригата, докато mainметодът излезе. Когато mainметодът се прекрати, програмата също.

Пример:

Код Конзолен изход
class Solution
{
   public static void main(String[] args)
   {
      System.out.println("Your attention, please! Preparing for the end of the world");
      endTheWorld();
      System.out.println("The world ended successfully");
   }

   public static void endTheWorld()
   {
      System.out.println("We're doing something important");
      doSomeWork(0);
      System.out.println("Everything is working well");
   }

   public static void doSomeWork(int n)
   {
      System.out.println("Nothing terrible will happen: " + n);
      System.out.println(2 / n);
      System.out.println("Nothing terrible happened: " + n);
   }
}
Your attention, please! Preparing for the end of the world
We're doing something important
Nothing terrible will happen: 0

Възниква изключение на ред 20: деление на 0. Java машината незабавно създава изключениеArithmeticExceptionобект и го „хвърля“ към метода.

Методът divide()приключва незабавно, така че никога не виждаме низа: Нищо ужасно не се е случило: 0. Програмата се връща към метода endTheWorld()и ситуацията се повтаря: в системата има необработено изключение, което означава, че методът endTheWorld()също прекратява необичайно. След това mainметодът се прекратява и програмата спира.

Каква е целта на тези изключения? Е, можете да напишете свой собствен code за улавяне на определени видове изключения и да напишете своя собствена логика за справяне с изключителни ситуации.


2. Улавяне на изключения:try-catch

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

try
{
   // Code where an exception might occur
}
catch(ExceptionType name)
{
   // Exception handling code
}

Тази конструкция се нарича try-catchблок.

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

След фигурните скоби имаме catchключовата дума и, в скобите, декларацията на променлива за изключение . Това е последвано от фигурни скоби, които обгръщат codeа, който трябва да бъде изпълнен, ако възникне изключение от посочения тип .

Ако не бъдат хвърлени изключения по време на изпълнението на " първичния code ", тогава codeът вътре в блока catch няма да бъде изпълнен. Ако възникне изключение, то ще бъде (ако типът на хвърленото изключение е същият като типа на променливата в скобите).

Пример:

Код Конзолен изход
class Solution
{
   public static void main(String[] args)
   {
      System.out.println("Hadron Collider launched");

      try
      {
         launchHadronCollider(1);
         launchHadronCollider(0);
      }
      catch(Exception e)
      {
         System.out.println("Error! Caught an exception");
         System.out.println("The planet was sucked into a black hole!");
      }

      System.out.println("The Hadron Collider stopped");
   }

   public static void launchHadronCollider(int n)
   {
      System.out.println("Everything is working well: " + n);
      System.out.println(2/n);
      System.out.println("There are no problems: " + n);
   }
}
Hadron Collider launched
Everything is working fine: 1
2
There are no problems: 1
Everything is working fine: 0
Error! Caught an exception
The planet has been sucked into a black hole!
The Hadron Collider is stopped


3. Множество catchблокове

Множество блокове за улавяне

На теория всяHowви изключения могат да бъдат хвърлени в блок от code. С някои ще искате да се справите по един начин, с други по друг начин, а с трети ще решите да не се справяте изобщо.

Разработчиците на Java решиха да ви помогнат и ви позволиха да пишете не един, а много catchблокове след tryблока.

try
{
   // Code where an exception might occur
}
catch (ExceptionType1 name1)
{
   // Code for handling ExceptionType1
}
catch (ExceptionType2 name2)
{
   // Code for handling ExceptionType2
}
   catch (ExceptionType3 name3)
{
   // Code for handling ExceptionType3
}

Пример:

Код Конзолен изход
class Solution
{
   public static void main(String[] args)
   {
      System.out.println("Start of main method");
      try
      {
         calculate(0);
      }
      catch (ArithmeticException e)
      {
         System.out.println("Division by 0");
      }
      catch(Exception e)
      {
         System.out.println("Caught some kind of exception");
      }

      System.out.println("End of main method");
   }

   public static void calculate(int n)
   {
      System.out.println("Start of calculate method: " + n);
      System.out.println(2/n);
      System.out.println("End of calculate method: " + n);
   }
}
Start of main method
Start of calculate method: 0
Division by 0
End of main method


4. Ред на catchблоковете

Изключенията, които възникват в tryблок, могат да бъдат уловени само от един catchблок. Не можете да имате ситуация на обработка на изключения, при която codeът от множество catchблокове се изпълнява.

Но редът на блоковете има meaning.

Може да имате ситуация, при която изключение може да бъде уловено от множество блокове. Ако случаят е такъв, тогава изключението ще бъде уловено от който блок catch е първи (най-близо до tryблока).

Как може да имате ситуация, в която множество catch блокове могат да хванат едно и също изключение?

Всички изключения принадлежат към една единствена йерархия на наследяване - вижте диаграмата.

Йерархия на изключенията

Обект ArithmeticExceptionможе да бъде присвоен на променлива, чийто тип е ArithmeticExceptionor който и да е от неговите предшестващи класове: RuntimeException , Exceptionи Throwable— вижте диаграмата.

Ще говорим повече за класовете на наследяване и предшественици в ниво 21.

Този code ще се компorра добре:

Предимства на наследството:
ArithmeticException ae    = new ArithmeticException();
RuntimeException runtime  = new ArithmeticException();
Exception exception       = new ArithmeticException();
Throwable trwbl           = new ArithmeticException();

Така че можете да хванете ArithmeticExceptionс някой от 4-те catchблока по-горе.

Пример 1:

Код Конзолен изход
class Solution
{
   public static void main(String[] args)
   {
      System.out.println("Start of main method");
      try
      {
         calculate(0);
      }
      catch(ArithmeticException e)
      {
         System.out.println("Division by 0");
      }
      catch(Exception e)
      {
         System.out.println("Caught some kind of exception");
      }

      System.out.println("End of main method");
   }

   public static void calculate(int n)
   {
      System.out.println("Start of calculate method: " + n);
      System.out.println(2/n);
      System.out.println("End of calculate method: " + n);
   }
}
Start of main method
Start of calculate method: 0
Division by 0
End of main method

В този пример ArithmeticExceptionможе да бъде уловен Howто от блоковете, catch (Exception e)така и catch (ArithmeticException e)от блоковете. Ще бъде уловен от блока, който е най-близо до tryблока — първият catchблок.

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

Типът Throwableобикновено е в състояние да улови всяко възможно изключение в Java . Ако го поставите в първия catchблок, codeът няма да се компorра, тъй като компилаторът знае, че има недостижими блокове code.