CodeGym /Blogue Java /Random-PT /Exceções: captura e manuseio
John Squirrels
Nível 41
San Francisco

Exceções: captura e manuseio

Publicado no grupo Random-PT
Oi! Odeio mencionar isso, mas uma grande parte do trabalho de um programador é lidar com erros. Na maioria das vezes, o próprio. Acontece que não há quem não erre. E também não existem tais programas. Exceções: captura e manuseio - 1 Claro, ao lidar com um erro, o principal é entender sua causa. E muitas coisas podem causar bugs em um programa. Em algum momento, os criadores do Java se perguntaram o que deveria ser feito com os erros de programação mais prováveis? Evitá-los totalmente não é realista, os programadores são capazes de escrever coisas que você nem imagina. :) Então, precisamos dar à linguagem um mecanismo para trabalhar com erros. Em outras palavras, se houver um erro em seu programa, você precisará de algum tipo de script para saber o que fazer a seguir. O que exatamente um programa deve fazer quando ocorre um erro? Hoje vamos nos familiarizar com esse mecanismo. É chamado de " exceções em Java ".

O que é uma exceção?

Uma exceção é uma situação excepcional e não planejada que ocorre durante a execução de um programa. Existem muitas exceções. Por exemplo, você escreveu um código que lê o texto de um arquivo e exibe a primeira linha.

public class Main {

   public static void main(String[] args) throws IOException {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));
       String firstString = reader.readLine();
       System.out.println(firstString);
   }
}
Mas e se não houver tal arquivo! O programa irá gerar uma exceção: FileNotFoundException. Saída: Exceção no encadeamento "principal" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (O sistema não pode encontrar o caminho especificado) Em Java, cada exceção é representada por uma classe separada. Todas essas classes de exceção derivam de um "ancestral" comum - a Throwableclasse pai. O nome de uma classe de exceção geralmente reflete de forma concisa por que a exceção ocorreu:
  • FileNotFoundException(o arquivo não foi encontrado)

  • ArithmeticException(ocorreu uma exceção durante a execução de uma operação matemática)

  • ArrayIndexOutOfBoundsException(o índice está além dos limites da matriz). Por exemplo, esta exceção ocorre se você tentar exibir a posição 23 de uma matriz que possui apenas 10 elementos.
Ao todo, Java tem quase 400 dessas classes! Por que tantos? Para torná-los mais convenientes para os programadores trabalharem. Imagine o seguinte: você escreve um programa e, enquanto ele é executado, gera uma exceção semelhante a esta:

Exception in thread "main"
Uhhhh. :/ Isso não ajuda muito. Não está claro o que o erro significa ou de onde veio. Não há informações úteis aqui. Mas a grande variedade de classes de exceção em Java dá ao programador o que mais importa: o tipo de erro e sua causa provável (embutida no nome da classe). É outra coisa para ver

Exception in thread "main" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (The system cannot find the specified path)
Fica imediatamente claro qual pode ser o problema e onde começar a cavar para resolvê-lo! Exceções, como instâncias de quaisquer classes, são objetos.

Capturando e tratando exceções

Java possui blocos especiais de código para trabalhar com exceções: try, catche finally. Exceções: captura e manuseio - 2 O código onde o programador acredita que pode ocorrer uma exceção é colocado no trybloco. Isso não significa que uma exceção ocorrerá aqui. Isso significa que pode ocorrer aqui, e o programador está ciente dessa possibilidade. O tipo de erro que você espera que ocorra é colocado no catchbloco. Isso também contém todo o código que deve ser executado se ocorrer uma exceção. Aqui está um exemplo:

public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {

       System.out.println("Error! File not found!");
   }
}
Saída: Erro! Arquivo não encontrado! Colocamos nosso código em dois blocos. No primeiro bloco, antecipamos que pode ocorrer um erro "Arquivo não encontrado". Este é o trybloco. Na segunda, dizemos ao programa o que fazer se ocorrer um erro. E o tipo de erro específico: FileNotFoundException. Se colocarmos uma classe de exceção diferente entre parênteses do catchbloco, ela FileNotFoundExceptionnão será capturada.

public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));
       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (ArithmeticException e) {

       System.out.println("Error! File not found!");
   }
}
Saída: Exceção no thread "main" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (O sistema não pode encontrar o caminho especificado) O código no catchbloco não foi executado porque nós "configuramos" este bloco para catch ArithmeticException, e o código no trybloco lançou um tipo diferente: FileNotFoundException. Não escrevemos nenhum código para manipular FileNotFoundException, então o programa exibe as informações padrão para FileNotFoundException. Aqui você precisa prestar atenção a três coisas. Número um. Assim que ocorrer uma exceção em alguma linha do trybloco, o código a seguir não será executado. A execução do programa "pula" imediatamente para o catchbloco. Por exemplo:

public static void main(String[] args) {
   try {
       System.out.println("Divide by zero");
       System.out.println(366/0);// This line of code will throw an exception

       System.out.println("This");
       System.out.println("code");
       System.out.println("will not");
       System.out.println("be");
       System.out.println("executed!");

   } catch (ArithmeticException e) {

       System.out.println("The program jumped to the catch block!");
       System.out.println("Error! You can't divide by zero!");
   }
}
Saída: Dividir por zero O programa saltou para o bloco catch! Erro! Você não pode dividir por zero! Na segunda linha do trybloco, tentamos dividir por 0, resultando em um ArithmeticException. Consequentemente, as linhas 3-9 do trybloco não serão executadas. Como dissemos, o programa imediatamente começa a executar o catchbloco. Número dois. Pode haver vários catchblocos. Se o código no trybloco pode lançar não um, mas vários tipos diferentes de exceções, você pode escrever um catchbloco para cada um deles.

public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       System.out.println(366/0);
       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {
      
       System.out.println("Error! File not found!");
      
   } catch (ArithmeticException e) {

       System.out.println("Error! Division by 0!");
      
   }
}
Neste exemplo, escrevemos dois catchblocos. Se FileNotFoundExceptionocorrer um no trybloco, o primeiro catchbloco será executado. Se ArithmeticExceptionocorrer um, o segundo bloco será executado. Você poderia escrever 50 catchblocos se quisesse. Obviamente, é melhor não escrever código que possa lançar 50 tipos diferentes de exceções. :) Terceiro. Como você sabe quais exceções seu código pode lançar? Bem, você pode adivinhar alguns deles, mas é impossível para você manter tudo em sua cabeça. O compilador Java, portanto, conhece as exceções mais comuns e as situações em que elas podem ocorrer. Por exemplo, se você escrever um código que o compilador sabe que pode gerar dois tipos de exceções, seu código não será compilado até que você os trate. Veremos exemplos disso a seguir. Agora algumas palavras sobre tratamento de exceções. Existem 2 maneiras de lidar com exceções. Já encontramos a primeira: o próprio método pode tratar a exceção em um catch()bloco. Existe uma segunda opção: o método pode lançar novamente a exceção na pilha de chamadas. O que isso significa? Por exemplo, temos uma classe com o mesmo printFirstString()método, que lê um arquivo e exibe sua primeira linha:

public static void printFirstString(String filePath) {

   BufferedReader reader = new BufferedReader(new FileReader(filePath));
   String firstString = reader.readLine();
   System.out.println(firstString);
}
No momento, nosso código não compila, pois possui exceções não tratadas. Na linha 1, você especifica o caminho para o arquivo. O compilador sabe que tal código poderia facilmente produzir um arquivo FileNotFoundException. Na linha 3, você lê o texto do arquivo. Este processo pode facilmente resultar em um IOException(erro de entrada/saída). Agora o compilador diz para você: "Cara, não vou aprovar esse código e não vou compilá-lo até que você me diga o que devo fazer se uma dessas exceções ocorrer. E elas certamente podem acontecer com base no código que você escreveu !" Não tem como contornar: você precisa dar conta dos dois! Já conhecemos o primeiro método de tratamento de exceção: precisamos colocar nosso código em um trybloco e adicionar dois catchblocos:

public static void printFirstString(String filePath) {

   try {
       BufferedReader reader = new BufferedReader(new FileReader(filePath));
       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {
       System.out.println("Error, file not found!");
       e.printStackTrace();
   } catch (IOException e) {
       System.out.println("File input/output error!");
       e.printStackTrace();
   }
}
Mas esta não é a única opção. Poderíamos simplesmente lançar a exceção mais alto em vez de escrever o código de tratamento de erros dentro do método. Isso é feito usando a palavra-chave throwsna declaração do método:

public static void printFirstString(String filePath) throws FileNotFoundException, IOException {
   BufferedReader reader = new BufferedReader(new FileReader(filePath));
   String firstString = reader.readLine();
   System.out.println(firstString);
}
Após a palavra-chave throws, indicamos uma lista separada por vírgulas de todos os tipos de exceções que o método pode lançar. Por que? Agora, se alguém quiser chamar o printFirstString()método no programa, ele ou ela (não você) terá que implementar o tratamento de exceção. Por exemplo, suponha que em algum lugar do programa um de seus colegas escreveu um método que chama seu printFirstString()método:

public static void yourColleagueMethod() {

   // Your colleague's method does something

   //...and then calls your printFirstString() method with the file it needs
   printFirstString("C:\\Users\\Henry\\Desktop\\testFile.txt");
}
Recebemos um erro! Este código não compila! Não escrevemos código de tratamento de exceção no printFirstString()método. Com isso, essa tarefa agora recai sobre os ombros de quem utiliza o método. Em outras palavras, o methodWrittenByYourColleague()método agora tem as mesmas 2 opções: ele deve usar um try-catchbloco para lidar com ambas as exceções ou lançá-las novamente.

public static void yourColleagueMethod() throws FileNotFoundException, IOException {
   // The method does something

   //...and then calls your printFirstString() method with the file it needs
   printFirstString("C:\\Users\\Henry\\Desktop\\testFile.txt");
}
No segundo caso, o próximo método na pilha de chamadas — aquele que está chamando methodWrittenByYourColleague()— terá que lidar com as exceções. É por isso que chamamos isso de "lançar ou passar a exceção". Se você lançar exceções usando a palavra-chave throws, seu código será compilado. Nesse ponto, o compilador parece estar dizendo: "Ok, ok. Seu código contém várias exceções em potencial, mas vou compilá-lo. Mas voltaremos a esta conversa!" E quando você chama qualquer método que tenha exceções não tratadas, o compilador cumpre sua promessa e o lembra novamente. Por fim, falaremos sobre o finallybloqueio (desculpe o trocadilho). Esta é a última parte do try-catch-finallytriunvirato de tratamento de exceções..

public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {
       System.out.println("Error! File not found!");
       e.printStackTrace();
   } finally {
       System.out.println ("And here's the finally block!");
   }
}
Neste exemplo, o código dentro do finallybloco será executado em ambos os casos. Se o código no trybloco for executado por completo sem lançar nenhuma exceção, o finallybloco será executado no final. Se o código dentro do trybloco for interrompido por uma exceção e o programa pular para o catchbloco, o finallybloco ainda será executado após o código dentro do catchbloco. Por que isso é necessário? Seu principal objetivo é executar código obrigatório: código que deve ser executado independentemente das circunstâncias. Por exemplo, muitas vezes libera alguns recursos usados ​​pelo programa. Em nosso código, abrimos um stream para ler as informações do arquivo e passá-las para o BufferedReaderobjeto. Devemos fechar nosso leitor e liberar os recursos. Isso deve ser feito não importa o que aconteça - quando o programa funcionar como deveria e quando lançar uma exceção. O finallybloco é um local muito conveniente para fazer isso:

public static void main(String[] args) throws IOException {

   BufferedReader reader = null;
   try {
       reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {
       e.printStackTrace();
   } finally {
       System.out.println ("And here's the finally block!");
       if (reader != null) {
           reader.close();
       }
   }
}
Agora temos a certeza de que cuidaremos dos recursos, independentemente do que aconteça durante a execução do programa. :) Isso não é tudo que você precisa saber sobre exceções. O tratamento de erros é um tópico super importante na programação. Muitos artigos são dedicados a ele. Na próxima lição, descobriremos quais tipos de exceções existem e como criar suas próprias exceções. :) Vejo você então!
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION