Java之 Exception和Error

2021-01-08  本文已影响0人  五月笙

定义

An exception is an unwanted or unexpected event, which occurs during the execution of a program i.e at run time, that disrupts the normal flow of the program’s instructions.

参考:Exceptions in Java

Java 语言在设计之初就提供了相对完善的异常处理机制,这也是 Java 得以大行其道的原因之一,因为这种机制大大降低了编写和维护可靠程序的门槛。

Error vs Exception

Java exception和Error有什么区别,运行时异常与一般异常有什么区别?

Error: An Error indicates serious problem that a reasonable application should not try to catch.
Exception: Exception indicates conditions that a reasonable application might try to catch.

首先可以看一下Throwable 类图,如下:

可以看出,Exception和Error都继承自Throwable,在Java中只有Throwable类型的实例才可以被抛出(throw)或捕获(catch),它是异常处理机制的基本组成类型。

Exception

Checked Exceptions

正确的程序在运行中,很容易出现的、情理可容的异常状况。除了Exception中的RuntimeException及其子类以外,其他的Exception类及其子类(例如:IOException和ClassNotFoundException)都属于可查异常。

Checked exceptions are exceptions that the Java compiler requires us to handle。

Unchecked Exceptions

包括运行时异常(RuntimeException与其子类)和错误(Error),RuntimeException发生的时候,表示程序中出现了编程错误,所以应该找出错误修改程序,而不是去捕获RuntimeException。

Unchecked exceptions are exceptions that the Java compiler does not require us to handle.

Handling Exceptions

/**
 * @exception FileNotFoundException ...
 */
public Scanner(String fileName) throws FileNotFoundException {
   ...
}
throws
public int getPlayerScore(String playerFile)
  throws FileNotFoundException {
  
    Scanner contents = new Scanner(new File(playerFile));
    return Integer.parseInt(contents.nextLine());
}

FileNotFoundException 是一个可检测异常,最简单的方式就是抛出。

try–catch
public int getPlayerScore(String playerFile) {
    try {
        Scanner contents = new Scanner(new File(playerFile));
        return Integer.parseInt(contents.nextLine());
    } catch (FileNotFoundException noFile) {
        throw new IllegalArgumentException("File not found");
    }
}
finally

它表示无论是否出现异常,都应当执行的内容。

public int getPlayerScore(String playerFile)
  throws FileNotFoundException {
    Scanner contents = null;
    try {
        contents = new Scanner(new File(playerFile));
        return Integer.parseInt(contents.nextLine());
    } finally {
        if (contents != null) {
            contents.close();
        }
    }
}

上面的代码对于一个经验深的人来说,仍旧可能会有问题

public int getPlayerScore(String playerFile) {
    Scanner contents;
    try {
        contents = new Scanner(new File(playerFile));
        return Integer.parseInt(contents.nextLine());
    } catch (FileNotFoundException noFile ) {
        logger.warn("File not found, resetting score.");
        return 0;
    } finally {
        try {
            if (contents != null) {
                contents.close();
            }
        } catch (IOException io) {
            logger.error("Couldn't close the reader!", io);
        }
    }
}

因为close本身也是一个高风险的方法,我们也要同时抓取。

Multiple catch Blocks
public int getPlayerScore(String playerFile) {
    try (Scanner contents = new Scanner(new File(playerFile))) {
        return Integer.parseInt(contents.nextLine());
    } catch (IOException e) {
        logger.warn("Player file wouldn't load!", e);
        return 0;
    } catch (NumberFormatException e) {
        logger.warn("Player file was corrupted!", e);
        return 0;
    }
}

上面这段代码有没有问题,如果我修改成下面的代码会怎么样?

    public int getPlayerScore(String playerFile) {

        try {
            Scanner contents = new Scanner(new File(playerFile));
            return Integer.parseInt(contents.nextLine());
        } catch (Exception e) {
            logger.warning("Player file wouldn't load!");
            e.printStackTrace();
            return 0;
        }
    }
Union catch Blocks

catch 代码块可以集中一起,如下:

public int getPlayerScore(String playerFile) {
    try (Scanner contents = new Scanner(new File(playerFile))) {
        return Integer.parseInt(contents.nextLine());
    } catch (IOException | NumberFormatException e) {
        logger.warn("Failed to load score!", e);
        return 0;
    }
}

Throwing Exceptions

当出现了异常以后,我们并不知道如何处理时,或者压根就不想处理当前异常时,我看可以使用throws关键词,将异常抛给调用者,让调用者去处理异常。

创建两个可以检查异常,如下:

public class TimeoutException extends Exception {
    public TimeoutException(String message) {
        super(message);
    }
}
Throwing a Checked Exception
public List<Player> loadAllPlayers(String playersFile) throws TimeoutException {
    while ( !tooLong ) {
        ...
    }
    throw new TimeoutException("This operation took too long");
}

如果中间执行时间过长的话,调用者得到异常后可以知道下一步该如何处理。

抛出一个不可检查异常:

    public List<Player> loadAllPlayers(String playersFile) throws TimeoutException {
        if(!isFilenameValid(playersFile)) {
            throw new IllegalArgumentException("Filename isn't valid!");
        }
        return  new ArrayList<Player>();
    }

    public boolean isFilenameValid(String f){
        return true;
    }
public List<Player> loadAllPlayers(String playersFile) 
  throws PlayerLoadException {
    try {
        ...
    } catch (IOException io) {
        throw new PlayerLoadException(io);
    }
}

上面代码是什么意思?

Swallowing Exceptions

public int getPlayerScore(String playerFile) {
    try {
        // ...
    } catch (Exception e) {}
    return 0;
}

如果采取这样的话,很可能会引发难以诊断的诡异情况,生吞异常,往往是基于假设这段代码不会发生或者感觉忽略异常是无所谓的。但是如果我们不把异常抛出来,或者没有输出到日志,程序可能在后续的代码以不可控的方式结束。没人能够轻易判断究竟是哪里抛出了异常,以及是什么原因产生了异常。

try {
   // 业务代码
   // …
} catch (IOException e) {
    e.printStackTrace();
}

我们来查看一下printStackTrace() 代码可以看到 "Prints this throwable and its backtrace to the standard error stream."。问在这里,在稍微复杂的生产系统中。

Common Exceptions and Errors

Checked
RuntimeExceptions
Errors

参考

Exception Handling in Java
docs.oracle
Java - Exceptions
Exception和Error有什么区别?
Java:详解Java中的异常(Error与Exception)
Java:简述try-catch-finally异常捕获

上一篇下一篇

猜你喜欢

热点阅读