JavaRush /Blogue Java /Random-PT /Pausa para café #220. Como corrigir exceções em Java – um...

Pausa para café #220. Como corrigir exceções em Java – um guia detalhado

Publicado no grupo Random-PT
Fonte: JavaTechOnline Este tutorial irá ajudá-lo a aprender como corrigir exceções comuns em Java. Além da teoria, você verá exemplos de código para corrigir esses problemas. Pausa para café #220.  Como corrigir exceções em Java – um guia detalhado – 1Tal como acontece com outras linguagens de programação, os desenvolvedores Java podem encontrar erros ou exceções ao escrever código. As exceções devem ser levadas a sério, pois sua ocorrência ocupa tempo de trabalho. Porém, com um pouco de conhecimento, você pode acelerar a resolução da maioria desses problemas. Então, vamos aprender como corrigir exceções comuns em Java.

Diretrizes Gerais para Evitar Exceções em Java

Para evitar lançar exceções em Java, é importante compreender e seguir as diretrizes de codificação:
  1. Sempre valide a entrada do usuário antes de usá-la em seu código.
  2. Use try-catch , throws , throw blocks , dependendo do que for apropriado para um cenário específico.
  3. Não negligencie as mensagens no código sobre processamento e erros. Isso ajudará a identificar e corrigir problemas.
  4. Certifique-se de registrar exceções para fins de depuração. Você pode usar mensagens do criador de logs para ajudar a identificar problemas.
  5. Siga as práticas recomendadas de codificação para evitar exceções e teste seu código completamente.
  6. Atualize suas dependências de API para garantir que você esteja usando as versões mais recentes e estáveis ​​de bibliotecas e estruturas.
  7. Use as ferramentas e estruturas de teste necessárias para identificar possíveis problemas em seu código antes que eles gerem exceções.
  8. Monitore o desempenho e os logs do seu aplicativo para identificar e resolver rapidamente quaisquer problemas.
  9. Mantenha-se atualizado com as práticas recomendadas de segurança para garantir que seu código esteja seguro e protegido contra possíveis ataques.
  10. Documente seu código e suas exceções minuciosamente para facilitar a compreensão e a manutenção de outros desenvolvedores.

Lista das exceções mais comuns em Java

Java tem uma lista bastante longa de exceções. Vejamos alguns dos mais comuns:

Null Pointer Exception

NullPointerException é um tipo de exceção RuntimeException . Ocorre quando tentamos usar uma variável de referência que possui um valor nulo. Isso significa que aponta para um objeto ou variável cujo valor é null . Tal erro pode ocorrer quando tentamos chamar um método ou acessar um campo de um objeto que não foi inicializado, ou quando passamos null como parâmetro para um método que não o trata. Para evitar que uma NullPointerException seja lançada , você pode verificar se uma variável de referência é nula usando o operador == . Se for esse o caso, o caso nulo precisa ser tratado corretamente. Alternativamente, podemos inicializar nossas variáveis ​​com valores padrão (quando possível) para garantir que nunca encontraremos uma referência nula. Outra maneira de evitar uma NullPointerException é usar a classe Opcional . Em Java, um Opcional é um objeto contêiner que pode ou não conter um valor não nulo. É usado para representar a presença ou ausência de um valor, semelhante à forma como o valor nulo é usado para representar a ausência de um valor. Se um programador tentar acessar o valor vazio de um objeto Opcional , o programa não lançará uma NullPointerException , mas retornará um objeto Opcional vazio . Em outras palavras, Opcional força o programador a lidar com o caso em que o valor está faltando, o que ajuda a evitar NullPointerException .

IndexOutOfBoundsException

IndexOutOfBoundsException é uma exceção de tempo de execução lançada quando o índice usado para acessar uma matriz ou coleção é negativo ou maior ou igual ao tamanho da matriz ou coleção. Para evitar que essa exceção ocorra, devemos garantir que o índice utilizado para acessar o array ou coleção esteja dentro de seus limites, ou seja, deve ser maior ou igual a zero e menor que o tamanho do array ou coleção.

Índice de matriz fora dos limites de exceção

ArrayIndexOutOfBoundsException é um tipo de IndexOutOfBoundsException que é lançado quando é feita uma tentativa de acessar uma matriz em um índice inválido. Em Java, os índices do array começam em 0 e terminam em length()-1 , onde length() é o número de elementos no array. Se você tentar acessar um elemento em um índice fora desse intervalo, Java lançará um ArrayIndexOutOfBoundsException . Ao encontrar um ArrayIndexOutOfBoundsException , você deve revisar seu código para garantir que está usando os índices corretos ao acessar os elementos na matriz.

StringIndexOutOfBoundsException

StringIndexOutOfBoundsException é um tipo IndexOutOfBoundsException lançado quando é feita uma tentativa de acessar um caractere em uma string que possui um índice inválido. Tal como acontece com o ArrayIndexOutOfBoundsException anterior , lembre-se de que em Java, o índice de uma string começa em 0 e termina em length()-1 , onde length() é o número de caracteres na string. Se você tentar acessar um caractere em um índice fora desse intervalo, poderá encontrar uma StringIndexOutOfBoundsException . Se você encontrar StringIndexOutOfBoundsException , deverá revisar seu código para garantir que está usando os índices corretos ao acessar caracteres na string.

ClassCastException

Esta exceção ocorre quando tentamos converter um objeto para um tipo que é incompatível com seu tipo real. Para resolver um problema como esse, é importante garantir que seu programa Java tente apenas converter objetos nas classes das quais eles são instâncias. Você pode verificar o tipo de um objeto usando o operador instanceof antes de aplicar a conversão.

Exceção de argumento ilegal

IllegalArgumentException é um tipo de RuntimeException lançado quando um método é chamado com um argumento ilegal ou inadequado. Em outras palavras, esse erro pode ocorrer quando um método é chamado com um argumento que está fora do intervalo esperado ou não possui o formato ou estrutura esperado. Por exemplo, um método requer um número positivo como argumento e fornecemos um número negativo, que é uma entrada inválida. Se você encontrar uma IllegalArgumentException , verifique seu código para garantir que está chamando métodos com argumentos válidos e apropriados.

IllegalStateException

IllegalStateException é um tipo de RuntimeException lançado quando um objeto está em um estado inadequado para a operação que está sendo executada. Isso pode acontecer se um método for chamado em um objeto que não esteja no estado esperado. Por exemplo, se criarmos um objeto de conexão com o banco de dados e depois fechá-lo. Então, se tentarmos criar um objeto Statement em uma conexão fechada, ele lançará uma IllegalStateException porque o método createStatement() requer uma conexão aberta. Se você encontrar um IllegalStateException , deverá revisar seu código para garantir que está chamando métodos em objetos que estão no estado apropriado.

UnsupportedOperationException

UnsupportedOperationException é um tipo RuntimeException lançado quando é feita uma tentativa de executar uma operação não suportada em um objeto. Este erro pode acontecer quando chamamos um método que não é implementado pelo objeto ou não é suportado pelo objeto. Para evitar que uma exceção seja lançada, não devemos chamar operações que não sejam suportadas em objetos. Precisamos revisar nosso código para ter certeza de que estamos chamando métodos em objetos que suportam a operação.

Exceção Aritmética

ArithmeticException é um tipo de RuntimeException lançado quando uma operação aritmética produz um resultado inválido. Esta exceção pode ocorrer quando tentamos realizar uma operação aritmética com um argumento inválido ou inválido. Por exemplo, ao tentar dividir por zero. Para resolver este problema, podemos realizar a validação de entrada e garantir que os argumentos atendam às condições exigidas antes de realizar a operação aritmética.

Exceção de segurança

SecurityException é um tipo de RuntimeException lançado quando ocorre uma violação de segurança durante a execução do programa. Este erro pode ocorrer quando um programa tenta executar uma operação que não é permitida pela política de segurança. Para resolver o problema, devemos garantir que temos acesso aos recursos e realizar operações para as quais temos permissão específica.

NumberFormatException

NumberFormatException é um tipo de RuntimeException lançado quando um método é chamado para converter uma string em um formato numérico, mas a string não está no formato apropriado. Para resolver este problema, devemos primeiro validar a entrada do usuário antes de tentar convertê-la. Verifique também seu código para ter certeza de que você está tentando converter strings formatadas adequadamente para o tipo numérico de destino.

Exceção Interrompida

InterruptedException é uma exceção verificada que é lançada se um thread estiver aguardando, dormindo ou bloqueando algum evento e esse evento for interrompido por outro thread. O erro pode ocorrer quando um thread está aguardando uma entrada, liberando um bloqueio ou concluindo alguma outra operação, e outro thread interrompe o thread em espera. Para resolver esse problema, você pode capturar InterruptedException e responder limpando recursos, interrompendo o thread ou executando outra ação apropriada. Se você encontrar um InterruptedException , verifique seu código para ter certeza de que está lidando corretamente com as interrupções de thread.

FileNotFoundException

FileNotFoundException é uma exceção verificada lançada quando um programa tenta acessar um arquivo que não existe ou não pode ser encontrado no local especificado. Pode aparecer se um arquivo for digitado incorretamente, movido ou excluído, ou mesmo quando um programa não possui as permissões necessárias para acessar o arquivo. Para corrigir o erro, você pode realizar a validação de entrada para garantir que o caminho do arquivo esteja correto e que o programa tenha as permissões necessárias para acessar o arquivo.

IOException

IOException é uma exceção verificada em Java que representa um erro encontrado ao executar operações de entrada ou saída, como leitura ou gravação em um arquivo ou soquete de rede. Isso pode acontecer por vários motivos, como falta ou inacessibilidade do arquivo especificado, erro de rede ou permissões insuficientes. Para corrigir o problema, você precisa realizar diversas ações, como verificar a mensagem de erro, tratar a exceção usando try-catch , fechar recursos, verificar a permissão do arquivo e assim por diante.

NoSuchMethodException

NoSuchMethodException é uma exceção lançada em tempo de execução quando tentamos chamar um método que não existe na classe. Esta exceção geralmente ocorre se chamarmos um método usando Class.getMethod() ou Class.getDeclaredMethod() e o nome do método especificado não for encontrado na classe ou interface. Uma exceção também pode ocorrer quando tentamos chamar um método usando a classe java.lang.reflect.Method e o nome do método especificado não existe no objeto. Para evitar essa exceção, certifique-se de chamar um método válido com a assinatura de método e o especificador de acesso corretos.

NoSuchFieldException

NoSuchFieldException é uma exceção de tempo de execução que ocorre quando tentamos acessar um campo que não está na classe. Esta exceção geralmente ocorre quando chamamos um método usando Class.getField() ou Class.getDeclaredField() e o nome do campo especificado não é encontrado na classe ou interface. Além disso, também pode ser chamado se estivermos tentando acessar um campo usando a classe java.lang.reflect.Field e o nome do campo especificado não existir no objeto. Para evitar essa exceção, certifique-se de acessar um campo válido com o nome e modificadores de acesso corretos. Se você estiver acessando um campo privado, certifique-se de usar o método getDeclaredField() em vez do método getField() .

Exceção de acesso ilegal

IllegalAccessException é uma exceção em tempo de execução que ocorre quando tentamos acessar um campo ou método em uma classe, mas não temos os direitos de acesso necessários. Esta exceção geralmente aparece quando tentamos acessar um campo ou método privado de fora de uma classe ou quando tentamos acessar um campo ou método protegido de uma classe que não é uma subclasse da classe original. Também pode ser chamado ao tentar acessar um campo ou método que foi marcado como indisponível pela classe java.lang.reflect.AccessibleObject . Para evitar esse problema, certifique-se de ter as permissões necessárias no campo ou método que está tentando acessar. Se o campo ou método for privado, talvez seja necessário usar reflexão e definir AccessibleObject como true (para acessá-lo). Porém, tenha cuidado ao usar reflexão para acessar campos ou métodos privados, pois isso pode quebrar o encapsulamento e comprometer a integridade da classe.

VerifyError

VerifyError é um erro em tempo de execução que é uma subclasse de LinkageError . Ocorre quando a Java Virtual Machine (JVM) encontra um arquivo de classe que viola certas regras de validação. Quando uma classe Java é compilada, o compilador verifica se o bytecode segue certas regras e restrições, como segurança de tipo e uso adequado da pilha e de variáveis ​​locais. Se um arquivo de classe violar essas regras, a JVM lançará um VerifyError ao carregar e verificar a classe em tempo de execução. Para evitar VerifyError , certifique-se de que seu código siga a sintaxe e a semântica corretas da linguagem Java. Se você encontrar um VerifyError , verifique seu código para garantir que ele seja válido e que não haja violações das regras de verificação de bytecode Java.

Erro de falta de memória

OutOfMemoryError é uma subclasse de Error , um tipo Throwable que apresenta problemas graves que não podem ser resolvidos em tempo de execução. Embora o Java 8 inclua algumas melhorias na coleta de lixo e no gerenciamento de memória, você ainda poderá encontrar um OutOfMemoryError se seu aplicativo estiver usando muita memória ou gerenciando o uso de memória incorretamente. Para evitar OutOfMemoryError , você precisa gerenciar adequadamente o uso de memória em seu aplicativo Java. Isso envolve o uso de estruturas de dados e algoritmos que utilizam a memória de forma eficiente, evitando a criação desnecessária de objetos e excluindo adequadamente os objetos quando eles não são mais necessários. Além disso, é possível aumentar o tamanho máximo de heap para a JVM usando o sinalizador -Xmx ao executar seu programa Java.

Erro StackOverflow

StackOverflowError é um tipo de erro que ocorre quando o tamanho da pilha exigido por um programa excede a quantidade de memória alocada para ele. Pode ocorrer quando um programa chama muitos métodos aninhados ou quando um método chama a si mesmo recursivamente muitas vezes, resultando em um loop infinito. A Java Virtual Machine (JVM) aloca uma quantidade fixa de memória para a pilha de execução, que é usada para controlar chamadas de métodos e variáveis ​​locais. Quando a pilha transborda, a JVM lança StackOverflowError . Para evitar StackOverflowError , é importante garantir que seu programa Java faça uso adequado de recursão e chamadas de método. Se você encontrar StackOverflowError , poderá tentar aumentar o tamanho da pilha usando o sinalizador -Xss ao executar seu programa Java.

InvocaçãoTargetException

InvocationTargetException é uma exceção verificada lançada pelo mecanismo de reflexão Java. Faz parte do pacote java.lang.reflect.InvocationTargetException e é usado para indicar que ocorreu uma exceção durante uma invocação de método ou construtor. Quando um método ou construtor é invocado usando o mecanismo de reflexão Java, o método invocar() da classe java.lang.reflect.Method ou java.lang.reflect.Constructor é chamado . Se o método ou construtor invocado lançar uma exceção, o método invocar() a capturará e a agrupará em uma InvocationTargetException . Esta exceção é então passada para o chamador do método Invoke() . Para corrigir InvocationTargetException , precisamos capturá-lo, obter a exceção de causa raiz usando o método getCause() e tratar a exceção de causa raiz de acordo. Observe que a causa raiz pode ser uma exceção verificada ou uma exceção de tempo de execução, portanto, trate-a corretamente.

Maneiras de corrigir as exceções mais comuns em Java

Como corrigir NullPointerException

Cenário: você tem um método que acessa um objeto que possui o valor null .
String title= null;
System.out.println(title.length()); // Это вызовет NullPointerException
Solução nº 1: verifique se o objeto é nulo antes de usar.
if(title!= null) {
   System.out.println(title.length());
} else {
   System.out.println("title is null");
}
Solução nº 2: use Opcional para evitar NullPointerException .
Optional<String> optionalTitle = Optional.ofNullable(getTitle());
if (optionalTitle.isPresent()) {
   String title= optionalTitle.get();
   System.out.println("Title: " + title);
} else {
   System.out.println("Title is not available.");
}

Como corrigir ArrayIndexOutOfBoundsException

Cenário: você está tentando acessar um array em um índice que está fora de seus limites.
int[] numbers = {4, 5, 6};
System.out.println(numbers[3]);   // Это вызовет ArrayIndexOutOfBoundsException
Solução: Verifique o comprimento do array antes de acessá-lo e certifique-se de estar usando índices válidos.
int[] numbers = {4, 5, 6};
if (numbers.length > 3) {
   System.out.println(numbers[3]);
} else {
   System.out.println("ArrayIndexOutOfBoundsException: Please use valid indexes of the Array");
}

Como corrigir ClassCastException

Cenário: você está tentando converter um objeto em um tipo incompatível com seu tipo real.
Object obj = "Java Exception";
Integer number = (Integer) obj; // Это вызовет ClassCastException
Solução: certifique-se de converter objetos apenas em tipos com os quais eles sejam compatíveis.
Object obj = "Java Exception";
if(obj instanceof Integer) {
   Integer number = (Integer) obj;
   System.out.println(number);
} else {
   System.out.println("Object cannot caste to Integer");
}

Como corrigir IllegalArgumentException

Cenário: você passou um argumento inválido para um método.
public void printNumber(int number) {
   if(number <= 0) {
      throw new IllegalArgumentException("You cannot pass a negative number or zero");
   }
   System.out.println(number);
}

printNumber(-1); // Это вызовет IllegalArgumentException
Solução: certifique-se de passar argumentos válidos para os métodos. Neste caso, passe um número positivo.
printNumber(1); //  Это успешно напечатает 1.

Como corrigir IllegalStateException

Cenário: O objeto está em um estado inválido.
public class Bike {

   private Boolean isStarted;

   public void start() {
      if(isStarted) {
        throw new IllegalStateException("Bike is already started");
      }
      isStarted = true;
      System.out.println("Bike started");
   }
}

Bike bike= new Bike();
bike.start();
bike.start(); // Это вызовет IllegalStateException потому что bike is already started
Solução: certifique-se de manter o estado do objeto corretamente.
Bike bike= new Bike();
bike.start();

Como corrigir UnsupportedOperationException

Cenário: você usa uma operação que não é suportada por um objeto. Um exemplo popular é quando você usa a operação remove() em uma coleção imutável, provavelmente verá uma exceção UnsupportedOperationException .
List<String> list = Arrays.asList("Java", "Angular", "Spring");
list.add("Python"); // Это вызовет UnsupportedOperationException
Como o método Arrays.asList() retorna uma lista imutável, ele não oferece suporte à adição ou remoção de elementos. Solução: certifique-se de chamar apenas operações suportadas em objetos.
List<String> list = new ArrayList<>(Arrays.asList("Java", "Angular" "Spring"));
list.add("Python");
System.out.println(list);

Como corrigir ArithmeticException

Cenário nº 1: você está tentando realizar uma operação de divisão inteira que produz um resultado fracionário.
int i = 10;
int j = 4;
int k = i/j; // Это вызовет исключение ArithmeticException: целочисленное деление будет дробным
Aqui o resultado da operação de divisão é 2,5, que é um valor fracionário. Como números inteiros não podem armazenar valores fracionários, uma ArithmeticException é lançada . Solução: Para evitar esta exceção, podemos utilizar um tipo de dados que suporte valores fracionários, como double , para armazenar o resultado da operação de divisão. Aqui está um exemplo:
int i = 10;
int j = 4;
double k = (double) i/j;
Cenário nº 2: você tenta dividir por zero e obtém esta exceção. Este é o cenário mais comum.
int i = 4;
int j = 0;
int k = i/j; // Это вызовет исключение ArithmeticException: нельзя делить на ноль
Solução: Trate a divisão por zero corretamente. Por exemplo, o código abaixo demonstra o processamento correto.
int i = 4;
int j = 0;
if(j != 0) {
int k = i/j;
System.out.println(k);
} else {
System.out.println("ArithmeticException: Cannot divide by zero");
}

Como corrigir IndexOutOfBoundsException

Cenário: Você está tentando acessar uma coleção com um índice que está fora dela.
List<String> list = Arrays.asList("Apple", "Papaya", "Mango");
System.out.println(list.get(3)); // Это вызовет IndexOutOfBoundsException
Solução: Verifique o tamanho da coleção antes de acessá-la e certifique-se de estar utilizando índices válidos.
List<String> list = Arrays.asList("Apple", "Papaya", "Mango");
if (list.size() > 3) {
   System.out.println(list.get(3));
} else {
   System.out.println("You are using the Index which is out of bounds");
}

Como corrigir IOException

Cenário: Uma operação de entrada/saída falha porque o arquivo não está acessível.
try {
   File inputFile = new FileReader("pqr.txt");
   BufferedReader reader = new BufferedReader(inputFile);
   String line = reader.readLine();
   System.out.println(line);
} catch (IOException e) {
   e.printStackTrace();
}
Solução: Trate erros de E/S e garanta que os recursos sejam fechados corretamente.
File inputFile = new File("pqr.txt");

if (!inputFile.exists() || !inputFile.canRead()) {
 System.out.println("The input file is missing or not readable.");
 return;
}

try {
BufferedReader reader = new BufferedReader(inputFile);
 String line = reader.readLine();
 System.out.println(line);
  reader.close();
} catch (IOException e) {
 e.printStackTrace();
}
Observe que, como alternativa, podemos usar o recurso try-with-resource introduzido no Java 7 para fechar recursos automaticamente, conforme mostrado abaixo. Podemos declarar um ou mais recursos em uma instrução try e Java fechará automaticamente os recursos no final do bloco, independentemente de o bloco ser concluído normalmente ou de uma exceção ser lançada.
try (BufferedReader reader = new BufferedReader(new FileReader("pqr.txt"))) {
....
} catch {
....
}

Como corrigir FileNotFoundException

Cenário: O arquivo não foi encontrado no local especificado.
try {
     BufferedReader reader = new BufferedReader(new FileReader("abc.txt"));
     String line = reader.readLine();
     System.out.println(line);
     reader.close();
} catch (FileNotFoundException | IOException e) {
     System.out.println("An error has occurred while reading the file: " + e.getMessage());
}
Solução: verifique se o arquivo existe e se você tem as permissões apropriadas para acessá-lo.
try {
    File file = new File("abc.txt");
    if(!file.exists()) {
    throw new FileNotFoundException("File not found at the specified location");
    }
    BufferedReader reader = new BufferedReader(new FileReader(file));
    String line = reader.readLine();
    System.out.println(line);
    reader.close();
} catch (IOException e) {
    e.printStackTrace();
}

Como corrigir NoSuchMethodException

Cenário: Se você estiver tentando acessar um método que não pode ser encontrado.
public class TestClass {
   public void sayHello() {
      System.out.println("Hello");
   }
}

TestClass obj = new TestClass();
Method method = obj.getClass().getMethod("printHello"); // Это вызовет NoSuchMethodException
Solução: Verifique se o método existe e se o nome e a assinatura do método estão corretos.
public class TestClass {
   public void sayHello() {
      System.out.println("Hello");
   }
}

TestClass  obj = new TestClass();
try {
    Method method = obj.getClass().getMethod("sayHello");
} catch (NoSuchMethodException e) {
    e.printStackTrace();
}

Como corrigir ConcurrentModificationException

Cenário: Uma coleção muda enquanto está sendo iterada.
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
for (String str : list) {
  list.remove(str);  // Это вызовет ConcurrentModificationException
}
Solução: Use um iterador para iterar uma coleção e modificá-la usando métodos iteradores.
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String str = iterator.next();
    iterator.remove();
}
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION