Exceções de compreensão de Java (superdetalhadas)

Índice

Conceitos e arquitetura de exceção

O conceito de anormalidade

Arquitetura incomum

Classificação anormal

1. Exceção de tempo de compilação

2. Exceção de tempo de execução

Manipulação de exceção

programação defensiva

LBYL

EAFP

Exceção lançada

Captura de exceção

Lançamentos de declaração de exceção

captura e processo try-catch

finalmente

Processo de tratamento de exceções


Conceitos e arquitetura de exceção

O conceito de anormalidade

Em Java, o comportamento anormal que ocorre durante a execução do programa é chamado de exceção . Por exemplo, o que é frequentemente encontrado:

1. Aritmética anormal

System.out.println(10/0);

//Resultados do

Exceção no thread "principal" java.lang.ArithmeticException: /por zero

2. Exceção de array fora dos limites

int arr[] = {1, 2, 3};
System.out.println(arr[100]);

//Resultados do

Exceção no thread "principal" java.lang.ArrayIndexOutOfBoundsException (exceção de array fora dos limites): Índice 100 fora dos limites para comprimento 3

3. Exceção de ponteiro nulo

int[] arr = nulo;
System.out.println(arr.comprimento);

//Resultados do

Exceção no thread “main” java.lang.NullPointerException(空指针异常): Não é possível ler o comprimento do array porque “arr” é nulo

Como pode ser visto no processo acima, diferentes tipos de exceções em Java possuem classes correspondentes para descrevê-las .

Nota: Quando ocorre uma exceção no programa, o código após a exceção não continuará a ser executado .

Arquitetura incomum

Existem muitos tipos de exceções. Para classificar e gerenciar adequadamente diferentes exceções ou erros, Java mantém uma arquitetura de exceções internamente.

Como você pode ver na imagem acima:

1.Throwable: refere-se à classe de exceções de nível superior, que deriva duas subclasses importantes, Erro e Exceção.

2. Erro: refere-se a problemas graves que não podem ser resolvidos pela máquina virtual Java, como: erros internos da JVM, esgotamento de recursos , etc. Representantes típicos: StackOverflowError (erro de estouro de pilha) e OutOfMemoryError ( erro de falta de memória ) . ocorre, não há como se recuperar.

3.Exceção: Após a geração da exceção, o programador pode tratá-la por meio do código para continuar a execução do programa.

Classificação anormal

As exceções podem ocorrer durante a compilação ou enquanto o programa está em execução. Dependendo do momento da ocorrência, as exceções podem ser divididas em:

1. Exceção de tempo de compilação

As exceções que ocorrem durante a compilação do programa são chamadas de exceções em tempo de compilação, também chamadas de exceções verificadas (ou seja, devem ser tratadas durante a compilação, caso contrário o código não passará)

public class Person {
    private String name;
    private String gender;
    int age;
    
    //想要让该类支持深拷贝,覆写Object类的clone方法即可
    
    @Override
    public Person clone() {
        return (Person)super.clone();
    }
}

//编译时报错
//Error:java:未报告的异常错误java.lang.CloneNotSupportedException;
//必须对其进行捕获或声明以便抛出

2. Exceção de tempo de execução

As exceções que ocorrem durante a execução do programa são chamadas de exceções de tempo de execução, também conhecidas como exceções não verificadas.

RunTimeException e as exceções correspondentes às suas subclasses são chamadas de exceções de tempo de execução . Por exemplo: NullPointerException, ArrayIndexOutOfBoundsException, ArithmeticException

Nota: Ocorre um erro de sintaxe durante a compilação e não pode ser chamado de exceção . Como erros ortográficos, etc. Neste momento, ocorrerá um erro durante o processo de compilação, que é um erro em tempo de compilação . O tempo de execução refere-se aos erros que ocorrem durante a execução da JVM após o programa ter sido compilado e obtido o arquivo de classe .

Manipulação de exceção

programação defensiva

Erros existem objetivamente no código. Portanto, precisamos notificar o programador a tempo quando houver um problema com o programa.

Maneira principal

LBYL

Olhe antes de saltar Faça inspeções adequadas antes de operar. Ou seja: tipo defensivo de antemão

boolean ret = false;
ret = 登陆游戏();
if(!ret) {
    //处理登陆游戏时的错误;
    return;
}
ret = 开始匹配();
if(!ret) {
    //处理匹配错误;
    return;
}
ret = 游戏确认();
if(!ret) {
    //处理游戏确认错误
    return;
}
ret = 选择英雄();
if(!ret) {
    //处理选择英雄错误
    return;
}
...

Defeitos: Os códigos dos processos normais e dos processos de tratamento de erros são misturados e o código geral parece confuso.

EAFP

É mais fácil pedir perdão do que permissão. "É mais fácil pedir perdão depois do que pedir permissão antes." Ou seja, agir primeiro e depois lidar com os problemas quando eles os encontrarem. Ou seja, admitir os erros depois .

try {
    登录游戏();
    开始匹配();
    游戏确认();
    选择英雄();
    ...
} catch(登陆游戏时异常) {
    //处理登陆游戏时异常
} catch(开始匹配时异常) {
    //处理开始匹配时异常
} catch(游戏确认时异常) {
    //处理确认游戏时异常
} catch(选择英雄时异常) {
    //处理选择英雄时异常
}
...




Vantagens: O processo normal e o processo de erro são separados. Os programadores prestam mais atenção ao processo normal. O código é mais claro e fácil de entender. A ideia central do tratamento de exceções é EAFP.

Em Java, as cinco palavras-chave para tratamento de exceções: throw, try, catch, final, throws

Exceção lançada

Ao escrever um programa, caso ocorra um erro no programa, as informações do erro precisam ser informadas ao chamador, como: detecção de parâmetros

Em Java, você pode usar a palavra-chave throw para lançar um objeto de exceção especificado e informar o chamador sobre a mensagem de erro. A sintaxe específica é a seguinte:

throw new XXXException("O motivo da exceção");

Maneiras de lançar uma exceção: 1. Acionada por um determinado programa 2. Lançar uma exceção por meio da palavra-chave throw .

throw geralmente é usado para lançar exceções personalizadas .

Por exemplo: implemente um método para obter um elemento em qualquer posição de um array.

Precauções

1.throw deve ser escrito dentro do corpo do método

2. O objeto lançado deve ser Exception ou um objeto da subclasse de Exception

3. Se o que for lançado for uma RunTimeException ou uma subclasse de RunTimeException, ela não precisará ser processada e poderá ser deixada para processamento pela JVM.

4. Se uma exceção em tempo de compilação for lançada, o usuário deverá tratá-la, caso contrário, a compilação não será aprovada.

5. Depois que uma exceção for lançada, o código subsequente não será executado.

Captura de exceção

Existem dois tipos principais de captura de exceções, ou seja, os métodos específicos de tratamento de exceções: declaração de exceção: lançamentos e processamento de captura try-catch.

Lançamentos de declaração de exceção

Após a lista de parâmetros quando o método é declarado, quando uma exceção em tempo de compilação é lançada no método e o usuário não deseja tratar a exceção, você pode usar throws para lançar a exceção ao chamador do método para tratamento. Ou seja, o método atual não trata exceções e lembra ao chamador o método para tratar exceções .

Existem várias maneiras de não tratar exceções no método, mas de lançar a exceção ao chamador para processamento:

1. Não adicione código de tratamento de exceções, não adicione diretamente try-catch e outros códigos de tratamento de exceções e deixe a exceção ser lançada dentro do método.

public void method() {   // A operação pode lançar exceções   throw new Exception(); } 2. Use throws para declarar exceções e use a palavra-chave throws na declaração do método para declarar os tipos de exceções que podem ser lançadas.



public void method() throws Exception {   // ... } 3. Relançar a exceção. Use a instrução throw para relançar a exceção após capturá-la.


public void method() {   try {   // ...   } catch (Exception e) {   throw e;    } } 4. Lançar exceções não verificadas. Para exceções de tempo de execução, você pode lançá-las diretamente, sem declaração.






método public void() {   lançar new RuntimeException(); }

Formato gramatical principal:

Tipo de valor de retorno do modificador nome do método (lista de parâmetros) lança tipo de exceção 1, tipo de exceção 2...{
 

}

Por exemplo: carregue o arquivo de configuração especificado config.ini

public class Config {
    File file;
    /*
    FileNotFoundException:编译时异常,表明文件不存在
    此处不处理,也没有能力处理,应该将错误信息报告给调用者,让调用者检查文件名字是否给错误了
     */
    public void OpenConfig(String filename) throws FileNotFoundException {
        if(filename.equals("config.ini")) {
            throw new FileNotFoundException("配置文件名字不对");
        }
        //打开文件
    }
    public void readConfig() {
        
    }   
}

Precauções

1.throws deve seguir a lista de parâmetros do método

2. A exceção declarada deve ser Exception ou uma subclasse de Exception

3. Se várias exceções forem lançadas dentro do método, os lançamentos devem ser seguidos por vários tipos de exceção, separados por vírgulas. Se vários tipos de exceção forem lançados e tiverem um relacionamento pai-filho, basta declarar a classe pai diretamente.

public class Config {
    File file;
    //public void OpenConfig(String filename)throws IOException, FileNotFoundException {
    //FileNotFoundException继承自IOException
    public void OpenConfig(String filename) throws IOException {
        if(filename.endsWith(".ini")) {
            throw new IOException("文件不是.ini文件");
        }
        
        if(filename.equals("config.ini")) {
            throw new FileNotFoundException("配置文件名字不对");
        }
        
        //打开文件
    }
    
    public void readConfig() {
        
    }
}

4. Ao chamar um método que declara lançar uma exceção, o chamador deve tratar a exceção ou continuar a usar lançamentos (a exceção não é realmente tratada pelo programador, mas na verdade é entregue à JVM)

public static void main(String[] args) throws IOException {
    Config config = new Config();
    config.OpenConfig("config.ini");
}

captura e processo try-catch

throws na verdade não trata a exceção, mas relata a exceção ao chamador do método que lançou a exceção, e o chamador a trata, o que requer try-catch.

O formato da sintaxe é o seguinte

try{
    //将可能出现异常的代码放在这里
} catch(要捕获的异常类型 e){
    /*如果try中的代码抛出异常了,此处catch捕获时的异常类型与try中抛出的异常类型
一致时,或者是try中抛出异常的基类型时,就会被捕捉到*/
    //对异常就可以正常处理,处理完成后,就会跳出try-catch结构,继续执行后续代码
} [{catch(异常类型 e) {
    //对异常进行处理
} finally {
    //此处代码一定会被执行到
}]

//后续代码
//当异常被捕获到时,异常就被处理了,这里的后续代码一定会被执行到
//如果捕获了,由于捕获时的类型不对,那就没有被捕获到,这里的代码就不会执行

Perceber:

1. [ ] indica itens opcionais, que podem ser adicionados ou não.

2. O código em tentativa pode lançar uma exceção ou não

Vamos continuar o exemplo anterior e usar try-catch para escrever este modo de captura de exceção:

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

public class Config {
    File file;
    public void openConfig(String filename) throws FileNotFoundException {
        if(filename.equals("config.ini")) {
            throw new FileNotFoundException("配置文件名字不对");
        }
        //打开文件
    }
    public void readConfig() {

    }

    public static void main(String[] args) {
        Config config = new Config();
        try {
            //可能出现异常的代码
            config.openConfig("config.ini");
            System.out.println("文件打开成功");
        } catch(IOException e) {
            //异常的处理方式
            //System.out.println(e.getMessage());//只打印出异常信息
            //System.out.println(e);//打印异常类型:异常信息
            e.printStackTrace();//打印信息最全面
        }

        //一旦异常被捕获处理了,此处的代码会执行
        System.out.println("异常如果被处理了,这里的代码也可以执行");
    }
}

Sobre o tratamento de exceções

Existem muitos tipos de exceções e temos que decidir de acordo com os diferentes cenários de negócios.

Para problemas mais sérios, o programa deve travar diretamente para evitar consequências mais graves.

Para problemas menos graves, os registos de erros podem ser registados e os programadores podem ser notificados em tempo útil através de programas de monitorização e alarme.

Para problemas que podem ser recuperados (cenários relacionados à rede), você pode tentar novamente

Em nosso código atual, adotamos um segundo método simplificado. O log de erros que registramos quando ocorrem chamadas de método anormais pode nos permitir encontrar rapidamente a localização da exceção. Adotaremos uma abordagem mais completa em trabalhos futuros. maneira de registrar informações de exceção .

Precauções

1. O código após o local da exceção no bloco try não será executado.

2. Se o tipo de exceção lançada não corresponder ao tipo de exceção quando capturada, ou seja, a exceção não será capturada com sucesso e não será processada, ela continuará a ser lançada até que a JVM interrompa o programa após recebê-la - exceções são capturados de acordo com o tipo.

3. Várias exceções diferentes podem ser lançadas na tentativa e várias capturas devem ser usadas para capturá-las - ou seja, múltiplas exceções e múltiplas capturas ( embora várias exceções possam ser capturadas, apenas uma exceção pode ser lançada ao mesmo tempo )

Se múltiplas exceções forem tratadas da mesma maneira, isso também poderá ser feito (não recomendado)

catch(NullPointerException | ArrayIndexOutOfBoundsException e){...}

Se houver um relacionamento pai-filho entre as exceções, a exceção da classe filha deverá ser capturada primeiro e a exceção da classe pai será capturada mais tarde. Caso contrário, a sintaxe estará incorreta:

public class Test2 {
    public static void main(String[] args) {
        int[] arr = {1,2,3};
        try {
            System.out.println("before");
            arr = null;
            System.out.println(arr[0]);
            System.out.println("after");
        } catch(Exception e) {//Exceiom可以捕获到所有异常
            e.printStackTrace();
        } catch (NullPointerException e) {//永远都可以被执行到
            e.printStackTrace();
        }
        System.out.println("after try catch");
    }
}

4. Todas as exceções podem ser capturadas através de uma captura, ou seja, múltiplas exceções, capturadas de uma só vez (não recomendado: ou seja, você não pode usar a classe pai para receber todas as subclasses de exceção, o que é impreciso (pode ser colocado posteriormente para capturar o último)) 

Nota: Quando catch executa correspondência de tipo, ele não apenas corresponderá a objetos de exceção do mesmo tipo, mas também capturará objetos de subclasse do tipo de exceção de destino.

finalmente

Ao escrever um programa, existem alguns códigos específicos que precisam ser executados independentemente de ocorrer uma exceção no programa, como a abertura de recursos no programa: conexões de rede, conexões de banco de dados, fluxos de IO, etc. anormalmente, os recursos devem ser reciclados . Além disso, alguns saltos do programa causados ​​por exceções podem não ser executados e, finalmente, são usados ​​para resolver este problema.

Formato de sintaxe:

try{
    //可能会发生异常的代码
    //如果这里有return,仍会执行finally,finally执行时机在return之前
}catch(异常类型 e){
    //对捕获的异常进行处理
}finally{
    //此处的语句无论是否发生异常,都会被执行到
}

O tempo de execução de finalmente é antes do retorno do método (se houver um retorno em try ou catch, finalmente será executado antes desse retorno).Mas se também houver uma instrução de retorno em finalmente, o retorno em finalmente será executado, então que não será executado em try.return. (Geralmente não é recomendado escrever return finalmente)

Processo de tratamento de exceções

pilha de chamadas

Existe um relacionamento de chamada mútua entre métodos. Esse relacionamento de chamada pode ser descrito por uma "pilha de chamadas". Existe um espaço de memória na JVM chamado "pilha de máquina virtual" que armazena especificamente o relacionamento de chamada entre métodos. Quando ocorre uma exceção no código, podemos usar e.printStackTrace() para visualizar a pilha de chamadas do código de exceção

Se não houver um método apropriado de tratamento de exceções neste método, ele será passado para cima na pilha de chamadas. Por exemplo:

public class Test3 {
    public static void main(String[] args) {
        try{
            func();
        }catch(ArrayIndexOutOfBoundsException e){
            e.printStackTrace();
        }
        System.out.println("after try catch");
    }

    public static void func() {
        int[] arr = {1,2,3};
        System.out.println(arr[100]);
    }
}

Resultados do:

Resumo do processo de tratamento de exceções:

1. O programa primeiro executa o código em try

2. Se ocorrer uma exceção no código em tentativa, o código em tentativa terminará para verificar se corresponde ao tipo de exceção em captura.

3. Se um tipo de exceção correspondente for encontrado, o código catch será executado.

4. Se nenhum tipo de exceção correspondente for encontrado, a exceção será passada para o chamador superior.

5. Independentemente de um tipo de exceção correspondente ser encontrado, o código finalmente será executado (executado antes do final do método

6. Se o chamador superior não tiver nenhuma exceção tratada, continue a transmiti-la para cima.

7. Não há código apropriado para tratar a exceção até o método principal, e ele será entregue à JVM para processamento, neste momento o programa será encerrado de forma anormal.

Acho que você gosta

Origin blog.csdn.net/asdssadddd/article/details/132736668
Recomendado
Clasificación