美文网首页
Java之 Exception和Error

Java之 Exception和Error

作者: 五月笙 | 来源:发表于2021-01-08 09:50 被阅读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
    • Checked Exceptions
      This exception is typically a way to say that something on the network, filesystem, or database failed.
    RuntimeExceptions
    • ArrayIndexOutOfBoundsException
      this exception means that we tried to access a non-existent array index, like when trying to get index 5 from an array of length 3.
    • ClassCastException
      this exception means that we tried to perform an illegal cast, like trying to convert a String into a List. We can usually avoid it by performing defensive instanceof checks before casting.
    • IllegalStateException
      This exception is a generic way for us to say that our internal state, like the state of our object, is invalid.
    • NullPointerException
      This exception means we tried to reference a null object. We can usually avoid it by either performing defensive null checks or by using Optional.
    • NumberFormatException
      This exception means that we tried to convert a String into a number, but the string contained illegal characters, like trying to convert “5f3” into a number.
    Errors
    • StackOverflowError
      this exception means that the stack trace is too big. This can sometimes happen in massive applications; however, it usually means that we have some infinite recursion happening in our code.
    • NoClassDefFoundError
      this exception means that a class failed to load either due to not being on the classpath or due to failure in static initialization.
    • OutOfMemoryError
      this exception means that the JVM doesn’t have any more memory available to allocate for more objects. Sometimes, this is due to a memory leak.

    参考

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

    相关文章

      网友评论

          本文标题:Java之 Exception和Error

          本文链接:https://www.haomeiwen.com/subject/ocumnktx.html