Olá! Na lição de hoje, falaremos sobre Java Exceptions. A vida cotidiana está cheia de situações que não antecipamos. Por exemplo, você se levanta para trabalhar de manhã e procura o carregador do telefone, mas não o encontra em lugar nenhum. Você vai ao banheiro para tomar banho e descobre que os canos estão congelados. Você entra no carro, mas ele não dá partida. Um ser humano é capaz de lidar com tais circunstâncias imprevistas com bastante facilidade. Neste artigo, tentaremos descobrir como os programas Java lidam com eles.
A capacidade de prevenir e resolver situações excepcionais em um programa, permitindo que ele continue rodando, é uma das razões para usar exceções em Java. O mecanismo de exceção também permite proteger seu código (API) contra uso indevido, validando (verificando) quaisquer entradas. Agora imagine que você é o departamento de transporte por um segundo. Primeiro, você precisa conhecer os locais onde os motoristas podem esperar problemas. Em segundo lugar, você precisa criar e instalar sinais de alerta. E, finalmente, você precisa fornecer desvios se surgirem problemas na rota principal. Em Java, o mecanismo de exceção funciona de maneira semelhante. Durante o desenvolvimento, usamos um bloco try para criar "barreiras de exceção" em torno de seções de código perigosas, fornecemos "rotas de backup" usando um catch {}bloco e escrevemos o código que deve ser executado em um bloco {}finalmente . Se não pudermos fornecer uma "rota de backup" ou quisermos dar ao usuário o direito de escolha, devemos pelo menos alertá-lo sobre o perigo. Por que? Imagine a indignação de um motorista que, sem ver um único sinal de alerta, chega a uma pequena ponte que não consegue atravessar! Na programação, ao escrever nossas classes e métodos, nem sempre podemos prever como eles podem ser usados por outros desenvolvedores. Como resultado, não podemos prever a maneira 100% correta de resolver uma situação excepcional. Dito isso, é bom alertar outras pessoas sobre a possibilidade de situações excepcionais. O mecanismo de exceção do Java nos permite fazer isso com os lancespalavra-chave — essencialmente uma declaração de que o comportamento geral do nosso método inclui lançar uma exceção. Portanto, qualquer pessoa que use o método sabe que deve escrever código para lidar com exceções.
Quando uma exceção é lançada em um bloco try , a JVM procura um manipulador de exceção apropriado no próximo bloco catch . Se um bloco catch tiver o manipulador de exceção necessário, o controle passará para ele. Caso contrário, a JVM procurará mais abaixo na cadeia de blocos catch até que o manipulador apropriado seja encontrado. Depois de executar um bloco catch , o controle é transferido para o bloco finalmente opcional. Se uma captura adequadabloco não for encontrado, a JVM interromperá o programa e exibirá o rastreamento de pilha (a pilha atual de chamadas de método), depois de executar primeiro o bloco final , se existir. Exemplo de tratamento de exceção:
O que é uma exceção Java?
No mundo da programação, erros e imprevistos na execução de um programa são chamados de exceções. Em um programa, podem ocorrer exceções devido a ações inválidas do usuário, espaço em disco insuficiente ou perda da conexão de rede com o servidor. As exceções também podem resultar de erros de programação ou uso incorreto de uma API. Ao contrário dos humanos no mundo real, um programa deve saber exatamente como lidar com essas situações. Para isso, o Java possui um mecanismo conhecido como tratamento de exceções.Algumas palavras sobre palavras-chave
O tratamento de exceções em Java é baseado no uso das seguintes palavras-chave no programa:- try - define um bloco de código onde pode ocorrer uma exceção;
- catch - define um bloco de código onde as exceções são tratadas;
- finalmente - define um bloco de código opcional que, se presente, é executado independentemente dos resultados do bloco try.
- throw - usado para gerar uma exceção;
- throws - usado na assinatura do método para avisar que o método pode lançar uma exceção.
// This method reads a string from the keyboard
public String input() throws MyException { // Use throws to warn
// that the method may throw a MyException
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String s = null;
// We use a try block to wrap code that might create an exception. In this case,
// the compiler tells us that the readLine() method in the
// BufferedReader class might throw an I/O exception
try {
s = reader.readLine();
// We use a catch block to wrap the code that handles an IOException
} catch (IOException e) {
System.out.println(e.getMessage());
// We close the read stream in the finally block
} finally {
// An exception might occur when we close the stream if, for example, the stream was not open, so we wrap the code in a try block
try {
reader.close();
// Handle exceptions when closing the read stream
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
if (s.equals("")) {
// We've decided that an empty string will prevent our program from working properly. For example, we use the result of this method to call the substring(1, 2) method. Accordingly, we have to interrupt the program by using throw to generate our own MyException exception type.
throw new MyException("The string cannot be empty!");
}
return s;
}
Por que precisamos de exceções?
Vejamos um exemplo do mundo real. Imagine que um trecho de uma rodovia tenha uma pequena ponte com capacidade de carga limitada. Se um carro mais pesado que o limite da ponte passar por cima dela, ela pode desabar. A situação para o motorista se tornaria, para dizer o mínimo, excepcional. Para evitar isso, o departamento de transporte instala sinais de alerta na estrada antes que algo dê errado. Vendo o sinal de alerta, o motorista compara o peso de seu veículo com o peso máximo da ponte. Se o veículo for muito pesado, o motorista faz uma rota alternativa. O departamento de transportes, em primeiro lugar, possibilitou que os caminhoneiros mudassem de rota se necessário, em segundo lugar, alertou os motoristas sobre os perigos na estrada principal e, em terceiro lugar, alertou os motoristas de que a ponte não deve ser usada em certas condições.
Advertir os outros sobre "problemas"
Se você não planeja lidar com exceções em seu método, mas deseja avisar outras pessoas que exceções podem ocorrer, use a palavra-chave throws . Essa palavra-chave na assinatura do método significa que, sob certas condições, o método pode gerar uma exceção. Este aviso faz parte da interface do método e permite que seus usuários implementem sua própria lógica de tratamento de exceção. Após os lançamentos, especificamos os tipos de exceções lançadas. Estes geralmente descendem da classe Exception de Java . Como Java é uma linguagem orientada a objetos, todas as exceções são objetos em Java.
Hierarquia de exceção
Quando ocorre um erro durante a execução de um programa, a JVM cria um objeto do tipo apropriado da hierarquia de exceção Java — um conjunto de exceções possíveis que descendem de um ancestral comum — a classe Throwable . Podemos dividir situações excepcionais de tempo de execução em dois grupos:- Situações das quais o programa não consegue se recuperar e continuar a operação normal.
- Situações em que a recuperação é possível.
Criando uma exceção
Quando um programa é executado, as exceções são geradas pela JVM ou manualmente usando uma instrução throw . Quando isso acontece, um objeto de exceção é criado na memória, o fluxo principal do programa é interrompido e o manipulador de exceção da JVM tenta lidar com a exceção.Manipulação de exceção
Em Java, criamos blocos de código nos quais antecipamos a necessidade de manipulação de exceção usando as construções try{}catch , try{}catch{}finally e try{}finally{} .
public class Print {
void print(String s) {
if (s == null) {
throw new NullPointerException("Exception: s is null!");
}
System.out.println("Inside print method: " + s);
}
public static void main(String[] args) {
Print print = new Print();
List list= Arrays.asList("first step", null, "second step");
for (String s : list) {
try {
print.print(s);
}
catch (NullPointerException e) {
System.out.println(e.getMessage());
System.out.println("Exception handled. The program will continue");
}
finally {
System.out.println("Inside finally block");
}
System.out.println("The program is running...");
System.out.println("-----------------");
}
}
}
Aqui estão os resultados do método principal :
Inside print method: first step
Inside finally block
The program is running...
-----------------
Exception: s is null!
Exception handled. The program will continue
Inside finally block
The program is running...
-----------------
Inside print method: second step
Inside finally block
The program is running...
-----------------
O final normalmente é usado para fechar quaisquer fluxos e liberar quaisquer recursos abertos/alocados em um bloco try . No entanto, ao escrever um programa, nem sempre é possível acompanhar o fechamento de todos os recursos. Para facilitar nossa vida, os desenvolvedores de Java oferecem a construção try-with-resources , que fecha automaticamente todos os recursos abertos em um bloco try . Nosso primeiro exemplo pode ser reescrito com try-with-resources :
public String input() throws MyException {
String s = null;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))){
s = reader.readLine();
} catch (IOException e) {
System.out.println(e.getMessage());
}
if (s.equals("")) {
throw new MyException ("The string cannot be empty!");
}
return s;
}
Graças aos recursos Java introduzidos na versão 7, também podemos combinar a captura de exceções heterogêneas em um bloco, tornando o código mais compacto e legível. Exemplo:
public String input() {
String s = null;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) {
s = reader.readLine();
if (s.equals("")) {
throw new MyException("The string cannot be empty!");
}
} catch (IOException | MyException e) {
System.out.println(e.getMessage());
}
return s;
}
GO TO FULL VERSION