异常

模块说明
先简介 从功能层面 为什么设计这个 为什么设计成这个样子
然后可以跟一些重要的模块 贴代码过来
然后就是结合项目理解一哈 最好能对应上之前梳理的设计理念

  • 异常处理的设计理念:把功能模块代码与系统中可能出现的错误的处理代码分离开来,以此来达到使我们的代码组织起来更美观、逻辑上更清晰,并且同时从根本上来提高我们软件系统长时间稳定运行的可靠性
    Java中的异常可以是函数中的语句执行时引发的,也可以是程序员通过throw 语句手动抛出的,只要在Java程序中产生了异常,就会用一个对应类型的异常对象来封装异常,JRE就会试图寻找异常处理程序来处理异常
    http://www.importnew.com/26613.html这上面的图

总体上我们根据Javac对异常的处理要求,将异常类分为2类。

非检查异常(unckecked exception):Error 和 RuntimeException 以及他们的子类。javac在编译时,不会提示和发现这样的异常,不要求在程序处理这些异常。所以如果愿意,我们可以编写代码处理(使用try…catch…finally)这样的异常,也可以不处理。对于这些异常,我们应该修正代码,而不是去通过异常处理器处理 。这样的异常发生的原因多半是代码写的有问题。如除0错误ArithmeticException,错误的强制类型转换错误ClassCastException,数组索引越界ArrayIndexOutOfBoundsException,使用了空对象NullPointerException等等。

检查异常(checked exception):除了Error 和 RuntimeException的其它异常。javac强制要求程序员为这样的异常做预备处理工作(使用try…catch…finally或者throws)。在方法中要么用try-catch语句捕获它并处理,要么用throws子句声明抛出它,否则编译不会通过。这样的异常一般是由程序的运行环境导致的。因为程序可能被运行在各种未知的环境下,而程序员无法干预用户如何使用他编写的程序,于是程序员就应该为这样的异常时刻准备着。如SQLException , IOException,ClassNotFoundException 等。

需要明确的是:检查和非检查是对于javac来说的,这样就很好理解和区分了(毕竟检查异常孙哥下的是死命令)。(跑起来日志里看到exception都是unchecked exception,不然都不能编译通过)

  • 看一哈异常
import java. util .Scanner ;
public class AllDemo
{
      public static void main (String [] args )
      {
            System . out. println( "----欢迎使用命令行除法计算器----" ) ;
            CMDCalculate ();
      }
      public static void CMDCalculate ()
      {
            Scanner scan = new Scanner ( System. in );
            int num1 = scan .nextInt () ;
            int num2 = scan .nextInt () ;
            int result = devide (num1 , num2 ) ;
            System . out. println( "result:" + result) ;
            scan .close () ;
      }
      public static int devide (int num1, int num2 ){
            return num1 / num2 ;
      }
}
/*****************************************
 
----欢迎使用命令行除法计算器----
0
Exception in thread "main" java.lang.ArithmeticException : / by zero
     at com.example.AllDemo.devide( AllDemo.java:30 )
     at com.example.AllDemo.CMDCalculate( AllDemo.java:22 )
     at com.example.AllDemo.main( AllDemo.java:12 )
 
----欢迎使用命令行除法计算器----
r
Exception in thread "main" java.util.InputMismatchException
     at java.util.Scanner.throwFor( Scanner.java:864 )
     at java.util.Scanner.next( Scanner.java:1485 )
     at java.util.Scanner.nextInt( Scanner.java:2117 )
     at java.util.Scanner.nextInt( Scanner.java:2076 )
     at com.example.AllDemo.CMDCalculate( AllDemo.java:20 )
     at com.example.AllDemo.main( AllDemo.java:12 )
*****************************************/

函数层级调用,有调用栈,故有异常追踪栈
---main(异常最先发生的地方,也称异常抛出点)
------CMDCalculate
---------devide
这个例子中没有使用异常处理机制,但是因为是非检查异常,所以可以顺利编译,但是这个异常会*冒泡到main,main函数最终抛给JRE,导致程序终止

  • 异常处理机制
    多个catch块顺序执行,如果异常有父子关系,应该将子类异常放在前面,不然子类就没有存在的意义了。
    如果try中的异常没有被捕获,就执行finally,然后往上抛。
    finally主要做一些清理工作,如流的关闭,数据库连接的关闭等。

有的编程语言当异常被处理后,控制流会恢复到异常抛出点接着执行,这种策略叫做:resumption model of exception handling(恢复式异常处理模式 )
而Java则是让执行流恢复到处理了异常的catch块后接着执行,这种策略叫做:termination model of exception handling(终结式异常处理模式)

  • 异常的链化
    为了追踪到异常的根源信息,我们用异常的链化
public class Throwable implements Serializable {
    private Throwable cause = this;
 
    public Throwable(String message, Throwable cause) {
        fillInStackTrace();
        detailMessage = message;
        this.cause = cause;
    }
     public Throwable(Throwable cause) {
        fillInStackTrace();
        detailMessage = (cause==null ? null : cause.toString());
        this.cause = cause;
    }
 
    //........
}

异常链化:以一个异常对象为参数构造新的异常对象。新的异对象将包含先前异常的信息。这项技术主要是异常类的一个带Throwable参数的函数来实现的。这个当做参数的异常,我们叫他根源异常(cause)。
就是调试的时候看到的那个一层一层的cause.
注意到Throwable的数据结构,不就是个链表么。

  • 自定义异常
    参考IOException
package java.io;

/**
 * Signals that an I/O exception of some sort has occurred. This
 * class is the general class of exceptions produced by failed or
 * interrupted I/O operations.
 *
 * @author  unascribed
 * @see     java.io.InputStream
 * @see     java.io.OutputStream
 * @since   JDK1.0
 */
public
class IOException extends Exception {
    static final long serialVersionUID = 7818375828146090155L;

    /**
     * Constructs an {@code IOException} with {@code null}
     * as its error detail message.
     */
    public IOException() {
        super();
    }

    /**
     * Constructs an {@code IOException} with the specified detail message.
     *
     * @param message
     *        The detail message (which is saved for later retrieval
     *        by the {@link #getMessage()} method)
     */
    public IOException(String message) {
        super(message);
    }

    /**
     * Constructs an {@code IOException} with the specified detail message
     * and cause.
     *
     * <p> Note that the detail message associated with {@code cause} is
     * <i>not</i> automatically incorporated into this exception's detail
     * message.
     *
     * @param message
     *        The detail message (which is saved for later retrieval
     *        by the {@link #getMessage()} method)
     *
     * @param cause
     *        The cause (which is saved for later retrieval by the
     *        {@link #getCause()} method).  (A null value is permitted,
     *        and indicates that the cause is nonexistent or unknown.)
     *
     * @since 1.6
     */
    public IOException(String message, Throwable cause) {
        super(message, cause);
    }

    /**
     * Constructs an {@code IOException} with the specified cause and a
     * detail message of {@code (cause==null ? null : cause.toString())}
     * (which typically contains the class and detail message of {@code cause}).
     * This constructor is useful for IO exceptions that are little more
     * than wrappers for other throwables.
     *
     * @param cause
     *        The cause (which is saved for later retrieval by the
     *        {@link #getCause()} method).  (A null value is permitted,
     *        and indicates that the cause is nonexistent or unknown.)
     *
     * @since 1.6
     */
    public IOException(Throwable cause) {
        super(cause);
    }
}

一个无参构造函数
一个带有String参数的构造函数,并传递给父类的构造函数。
一个带有String参数和Throwable参数,并都传递给父类构造函数
一个带有Throwable 参数的构造函数,并传递给父类的构造函数。
想要checked就扩展Exception 想要unchecked就扩展RuntimeException

  • 非人类的点 finally块和return
    在try块中即便有return,break,continue等改变执行流的语句,fianlly也会执行,故finally中的return会抑制try catch中的异常,所以最好减轻finallyd的任务,尽量把return写在函数的最后面,不要写在异常处理过程中。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 转载:http://www.cnblogs.com/lulipro/p/7504267.html 一、异常简介 程...
    SinX竟然被占用了阅读 4,542评论 2 2
  • Java中的异常和处理详解 简介 程序运行时,发生的不被期望的事件,它阻止了程序按照程序员的预期正常执行,这就是异...
    Richard2016阅读 1,711评论 1 0
  • 引言 在程序运行过程中(注意是运行阶段,程序可以通过编译),如果JVM检测出一个不可能执行的操作,就会出现运行时错...
    Steven1997阅读 7,249评论 1 6
  • 就像宫崎骏《哈尔的移动城堡》里说的那样:爱,不是寻找一个完美的人,而是学会用完美的眼光,欣赏那个并不完美的人。 也...
    秋水盈盈999阅读 1,270评论 0 1
  • 因为看了李月亮的一篇文章,所以喜欢上了她。满世界找她的作品,一眼看到书名《爱比现实高半米》,就心心念念,熬夜看完过...
    盈盈她说阅读 4,668评论 0 1

友情链接更多精彩内容