1. Exceções

>

Por fim, os programadores pensaram em padronizar e automatizar o tratamento de erros. Isso aconteceu quando as exceções foram inventadas. Agora, o mecanismo de exceção lida com 80% das situações excepcionais.

Se algum estudioso apresentou exceções, provavelmente foi o assunto de sua dissertação de doutorado. Se um programador surgiu com isso, então ele pode ter recebido um tapinha amigável nas costas de um colega de trabalho: "Parece bom, mano."

Quando ocorre um erro em um programa Java, como a divisão por 0, algumas coisas maravilhosas acontecem:

Passo um

Um objeto de exceção especial é criado, contendo informações sobre o erro ocorrido.

Tudo em Java é um objeto, e exceções não são exceções 🙂 Objetos de exceção têm suas próprias classes, e a única coisa que os distingue das classes comuns é que eles herdam a classe Throwable.

Passo dois

O objeto de exceção é "lançado". Talvez a formulação aqui poderia ser melhor. "Lançar uma exceção" é mais como disparar um alarme de incêndio ou soar um alerta "DEFCON 1".

Quando uma exceção é lançada para a máquina Java, a operação normal do programa é interrompida e os "protocolos de emergência" começam.

Passo três

O método no qual a exceção foi lançada sai imediatamente. A exceção é passada para o método de chamada, que também sai imediatamente. E assim por diante na cadeia até que o mainmétodo saia. Quando o mainmétodo termina, o programa também termina.

Exemplo:

Código Saída do console
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

Uma exceção ocorre na linha 20: divisão por 0. A máquina Java imediatamente cria uma exceção — um ArithmeticExceptionobjeto e o "lança" para o método.

O divide()método termina imediatamente, então nunca vemos a string: Nothing terrible aconteceu: 0. O programa retorna ao endTheWorld()método, e a situação se repete: há uma exceção não tratada no sistema, o que significa que o endTheWorld()método também termina de forma anormal. Em seguida, o mainmétodo termina e o programa para.

Qual é o objetivo dessas exceções? Bem, você pode escrever seu próprio código para capturar determinados tipos de exceções e escrever sua própria lógica para lidar com situações excepcionais.


2. Capturando exceções:try-catch

Java tem um mecanismo de captura de exceção que permite interromper essa finalização anormal de métodos. Se parece com isso:

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

Essa construção é chamada de try-catchbloco.

O código onde podem ocorrer exceções é colocado entre chaves, precedido pela palavra try.

Após as chaves, temos a catchpalavra-chave e, entre parênteses, a declaração de uma variável de exceção . Isso é seguido por chaves que envolvem o código a ser executado se ocorrer uma exceção do tipo especificado .

Se nenhuma exceção for lançada durante a execução do " código primário ", o código dentro do bloco catch não será executado. Se ocorrer uma exceção, ela será (se o tipo da exceção lançada for o mesmo que o tipo da variável entre parênteses).

Exemplo:

Código Saída do console
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. Múltiplos catchblocos

Vários blocos de captura

Em teoria, todos os tipos de exceções podem ser lançados em um bloco de código. Alguns você vai querer lidar de um jeito, outros de outro jeito, e ainda outros você vai decidir não lidar de jeito nenhum.

Os desenvolvedores Java decidiram ajudá-lo e permitir que você escreva não um, mas muitos catchblocos após o trybloco.

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
}

Exemplo:

Código Saída do console
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. Ordem dos catchblocos

Exceções que ocorrem em um trybloco só podem ser capturadas por um único catchbloco. Você não pode ter uma situação de manipulação de exceção em que o código de vários catchblocos é executado.

Mas a ordem dos blocos é importante.

Você pode ter uma situação em que uma exceção pode ser capturada por vários blocos. Se for esse o caso, a exceção será capturada pelo bloco catch que vier primeiro (mais próximo do trybloco).

Como você pode ter uma situação em que vários blocos catch podem capturar a mesma exceção?

Todas as exceções pertencem a uma única hierarquia de herança — veja o diagrama.

Hierarquia de exceção

Um ArithmeticExceptionobjeto pode ser atribuído a uma variável cujo tipo é ArithmeticExceptionou qualquer uma de suas classes ancestrais: RuntimeException , Exceptione Throwable— veja o diagrama.

Falaremos mais sobre herança e classes ancestrais no Nível 21.

Este código irá compilar perfeitamente:

Benefícios da herança:
ArithmeticException ae    = new ArithmeticException();
RuntimeException runtime  = new ArithmeticException();
Exception exception       = new ArithmeticException();
Throwable trwbl           = new ArithmeticException();

Então você pode pegar um ArithmeticExceptioncom qualquer um dos 4 catchblocos acima.

Exemplo 1:

Código Saída do console
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

Neste exemplo, o ArithmeticExceptionpode ser capturado pelos blocos catch (Exception e)e catch (ArithmeticException e). Ele será capturado pelo bloco mais próximo do trybloco - o primeiro catchbloco.

Para evitar surpresas, é melhor colocar catchblocos que possam capturar quase todas as exceções perto do final da lista de catchblocos.

O Throwabletipo geralmente é capaz de capturar todas as exceções possíveis em Java . Se você colocá-lo no primeiro catchbloco, o código não será compilado, pois o compilador sabe que existem blocos de código inacessíveis.