JavaRush /Blogue Java /Random-PT /Exceções em Java
Roman
Nível 33

Exceções em Java

Publicado no grupo Random-PT
Quando me deparei com o tema “Exceções”, surgiram muitas dúvidas para as quais tive que procurar respostas em vários cantos da Internet para entender detalhadamente como tudo funciona. Como resultado, compilei minha própria explicação, que pode ser mais compreensível para iniciantes que acabaram de encontrar esse fenômeno. Exceções em Java - 1Nos computadores, uma interrupção é um sinal recebido pelo processador de que está ocorrendo um evento que requer uma resposta imediata. Um sinal de interrupção exige que o processador pause um programa em execução para que ele possa continuar um pouco mais tarde, ou seja, o computador deve lembrar todas as informações associadas à execução do programa. Tais interrupções são temporárias, se não fatais. Tais interrupções podem ser causadas por código de programa ou por alguma funcionalidade de hardware (por exemplo, simplesmente pressionar teclas no teclado; temporizadores, por exemplo, para desligar automaticamente o computador). O número de interrupções é limitado a um determinado número, embutido na produção de um determinado processador, ou seja, são alocados “canais” de comunicação especiais para isso, permitindo o acesso ao processador contornando todos os demais processos. As interrupções também são geradas automaticamente quando ocorre um erro no código do programa em execução (por exemplo, se ocorrer uma divisão por zero). Tais interrupções são tradicionalmente chamadas de armadilhas ou exceções . Nesses casos, costuma-se dizer: “Uma exceção foi lançada”, ou seja, uma exceção foi acionada ou uma exceção foi lançada (lançada), ou seja, uma solicitação de interrupçãocom a pergunta “o que fazer?” enviado ao processador. Neste momento, o processador para de funcionar, lembrando o ponto em que parou, ou melhor, o cluster da próxima célula, cuja informação deve ser executada. Toda a cadeia de instruções executadas e NÃO executadas é lembrada. Depois disso, o processador lê as instruções da memória para agir no caso de tal erro. De acordo com esta instrução, ele pode inserir novos valores em determinados clusters, adicionar algumas cadeias de ações ou um novo ciclo (por exemplo, um ciclo de retorno ou loop), etc., ou seja, dependendo do erro previamente definido instruções down são executadas. O próprio sistema de computador possui muitas interrupções automáticas integradas, que são acionadas após um determinado período de tempo, por exemplo, para controlar processos em execução no computador ou executar alarmes definidos, coletar sinais externos de entrada e vários conversores de dados. Vale lembrar que um grande número de Interrupções, por diversos motivos, pode “travar” completamente o sistema. Um erro no código do programa causará automaticamente uma interrupção no processador, que tentará processar de acordo com as instruções estabelecidas. Mas nem todas as interrupções são projetadas para lidar com elas, ou podem produzir um procedimento que não nos convém, por exemplo, simplesmente travará o aplicativo. Portanto, na programação é possível organizar sua própria interrupção para uma determinada seção do código na qual o programador potencialmente vê a possibilidade de um erro. Neste caso, o erro será processado dentro do programa e não entrará em contato com o processador para instruções de processamento. A definição de tais blocos é organizada através da criação de um Objeto “Exceção” . Este objeto é criado automaticamente no bloco try-catch. O bloco >tryé verificado quanto à presença de erro e, se houver, o programa vai para o bloco catch, onde são tomadas ações para prevenir ou nivelar o erro. Por exemplo, se inserirmos números no teclado , que posteriormente devem ser somados e subtraídos, a inserção de letras no teclado tornará impossível adicioná-las com números (vamos denotar a soma dessas duas variáveis ​​​​pela letra S). Portanto, como equipe, trydevemos verificar se o número A, contendo Números, pode ser adicionado ao número B, contendo Letras (ou seja, S = A + B), e se isso não for possível, e é impossível, então certos devem ser tomadas medidas para que Erros NÃO aconteçam e uma nova Interrupção com a pergunta “o que fazer?” não voe para o processador. Caso não haja Exceção no programa, sua execução será interrompida pelo processador. Caso haja uma Exceção, ao ser “capturada” pelo comando try, o controle passa para o comando catch, que pode definir uma solução alternativa, por exemplo, não iremos somar esses dois números, mas definir S = A.
int a = 4;
String b = “hello”;
int S = 0;
 try {
   S = a + b;
   int r = 1;
 } catch (Exception igogo1) {
   S = a;
 }
 return S;
/* string “int r = 1;” não é executado porque ocorreu um erro e o programa redireciona o trabalho diretamente para o manipulador de exceções (bloco catch*/ Assim, a presença de Exceções é uma oportunidade de resolver o problema dentro do programa sem lançá-lo no nível do processador. O objeto “Exceção”, que é criado automaticamente no bloco tryquando um erro é detectado, contém o valor do tipo de erro. Vamos chamá-lo de “OurException” – para o nosso caso específico com uma descrição do nosso erro específico. Os criadores da linguagem Java criaram antecipadamente uma certa lista de erros típicos e opções típicas para corrigi-los, ou seja, em java existe uma certa biblioteca de Exceções , à qual podemos recorrer para tratar um erro ocorrido, assim como não devemos escrever o código de processamento nós mesmos e, portanto, OurException provavelmente já foi descrito por alguém, então só precisamos saber o nome de qual dessas exceções inserir em nosso programa para lidar com o código onde uma falha poderia ocorrer. Se cometermos um erro e selecionarmos uma Exceção incorreta da biblioteca , o manipulador não a “capturará”, o erro não encontrará solução dentro do programa e a solicitação será enviada ao processador. Mas existe um caminho para os preguiçosos. Se não soubermos o nome da exceção que precisamos da biblioteca, podemos pegar a geral com o nome “ Exceção ”, como no exemplo descrito acima. Esta Exceção é capaz de tratar qualquer tipo de erro, mas não é capaz de fornecer informações específicas sobre o incidente que poderíamos registrar. A biblioteca de Exceções escritas anteriormente consiste em Exceções marcadas e não verificadas . Os verificáveis ​​​​são aqueles que podem ser corrigidos sem interromper o trabalho do programa, ou seja, se tentarmos abrir um arquivo em uma pasta onde ele não existe, o sistema nos avisará, podemos descartar o arquivo na pasta desejada e continue o programa. Ou seja, de fato, foi enviado ao processador uma solicitação de Interrupção , mas sem a pergunta: “procura o que fazer em relação a esse problema?!?!” Enviamos um Interrupt, que nós mesmos detectamos, com uma instrução pronta, que o processador processou e continuou executando o programa. Desmarcados são aqueles erros que não podem ser corrigidos e o programa será fechado antes de ser concluído, ou seja, uma solicitação de interrupção será enviada ao processador, o que em qualquer caso interromperá a execução do programa. O único sentido em escrever tais exceções no programa é deixar o usuário entender o que aconteceu, pois, ao detectar essa interrupção, podemos exibir na tela uma mensagem informativa de que o programa travou. A segunda razão para detectar tais interrupções é a capacidade de registrá-las nos logs para análise posterior (você foi hackeado, mas pelo menos sabe onde). Uma consequência da presença de tais bibliotecas é a necessidade de lembrar de incluí-las. (Uma lista de exceções marcadas e desmarcadas com bibliotecas pode ser encontrada, por exemplo, aqui ) Se não sabemos exatamente qual biblioteca incluir ou se houver várias opções de erro, podemos catchlistar as exceções necessárias em várias. O próprio sistema selecionará o manipulador correto se estiver na lista. Em vez de uma Exceção específica, você pode escrever uma “ Exceção ” geral que pode tratar qualquer tipo de Exceção se não tiver sido processada em blocos anteriores.
int a = 4;
String b = “hello”;
int S = 0;
 try {
   S = a + b;
   int r = 1;
 }
catch(NullPointerException blabla2) {
   System.out.println("Exception handling code for the NullPointerException.");
 }
catch (ArithmeticException ex1) {
   S = a;
 }
catch(Exception uups1) {
   System.out.println("Exception occured");
 }
 return S;
Se houver um bloco, tryuma exceção será criada automaticamente. Se precisarmos forçar uma exceção em algum momento , então o comando será usado throw. Ou seja, criamos um objeto de forma independente new throw... após o qual o programa interrompe seu trabalho, envia uma solicitação de interrupção ao processador e é transferido para a seção do programa catch, de onde tenta obter instruções para ações futuras. Ao criar manualmente uma Exception , podemos especificar seu tipo específico na biblioteca:

throw new ArithmeticException("Access denied - You must be at least 18 years old.");
então o manipulador procurará um bloco catchcom esta exceção específica - pesquisará em todo o programa, em todos os lados catch. Após o throwcomando de tratamento de exceções, todo o código restante do programa NÃO será executado, exceto aquele que está no bloco catch. Se o manipulador não for encontrado no programa, é feita a pergunta ao processador: “decida por si mesmo o que fazer” e ele interrompe o programa. A chamada new throw... pode ser feita tanto dentro >tryquanto fora do bloco (em qualquer lugar do programa)
try {
   /* функция or действие, в котором есть сомнения. То есть: «попробуй выполнить это, а если не получится, а, если не получится, запускай режим исключения» */
   throw new CallForException(); /* Назначаем исключение, которое будет работать в случае наличия ошибки в функции, описанной выше. Здесь исключение «CallForException» - берется из библиотеки существующих исключений */
} catch (CallForException ee1) {
   /* Корректируем ошибку, чтобы программа не «отвалилась» or выводим сообщение об ошибке or что-то ещё */
} finally {
   /* этот блок работает всегда независимо от того была ошибка or нет. А если была, то сработало ли решение в catch or нет */
   /* часто используется для подчистки хвостов, например, для закрытия запущенного file or базы данных */
   /* в ряде случаев блок catch вообще может быть опущен и оставлен только блок finally и наоборот finally может быть опущен и оставлен только catch */
   /* Не допускается использование этого блока в ряде случаев, например, когда функция System.exit() запущена or другие системные Исключения, типа «отключение электроэнергии» и т.п. */
}

Notificação de Exceções

Métodos previamente escritos por alguém podem incluir o lançamento de exceções. Só por segurança, o programador que escreveu o código avisou aos programadores subsequentes que poderia ocorrer um erro no método que ele escreveu. Assim, por exemplo, o método de criação de arquivo descrito abaixo estipula que ao criar um arquivo pode ocorrer um erro (não há arquivo no caminho fornecido), o que significa que será necessário um manipulador de erros:
public void createFile(String path, String text) throws IOException {
    FileWriter writer = new FileWriter(path, true);
    writer.write(text);
    writer.close();
}
Mas, ao mesmo tempo, não existe um manipulador propriamente dito, o que significa que agora não poderemos simplesmente chamar o método escrito em nosso programa no modo normal. Agora devemos escrever um manipulador de erros e chamar este método no bloco try:
String filePath = "hello.txt";
String text = "Hello World";

try {
    createFile(filePath, text);
} catch (IOException ex) {
    System.err.println("Error creating file: " + ex);
}

Exceções nativas

É possível escrever suas próprias exceções para lidar com certos erros se as bibliotecas existentes não forem suficientes para nós. Para fazer isso, simplesmente criamos uma classe que herda da classe Exception
public class StudentNotFoundException extends Exception {

    public StudentNotFoundException (String message) {
        super(message);
    }
}
Há duas regras a serem lembradas ao criar suas próprias exceções:
  1. Nosso nome de classe deve terminar com “Exception”
  2. A classe deve conter um construtor com uma variável string descrevendo os detalhes do problema de Exceção. No construtor, o superconstrutor é chamado e uma mensagem é passada.
Um exemplo de uso da exceção gerada:
public class StudentManager {
    public Student find(String studentID) throws StudentNotFoundException {
        if (studentID.equals("123456")) {
            return new Student();
        } else {
            throw new StudentNotFoundException(
                "Could not find student with ID " + studentID);
        }
    }
}
Capturamos esta exceção com o código:
public class StudentTest {
    public static void main(String[] args) {
        StudentManager manager = new StudentManager();
         try {
            Student student = manager.find("0000001");
        } catch (StudentNotFoundException ex) {
            System.err.print(ex);
        }
    }
}
O resultado da execução do programa será: StudentNotFoundException: Não foi possível encontrar aluno com ID 0000001

Por que você precisa escrever exceções?

Em 1996, o foguete Ariane 5 caiu devido a uma conversão incorreta de uma variável flutuante em uma variável inteira. Não houve exceções ou manipuladores para esta situação. Se durante o download de um arquivo houver perda de conexão com a Internet, a presença de uma Exceção permitirá que você continue o download após a restauração da conexão. Se não houver Exceção, o download deverá ser reiniciado.

Referências:

Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION