只想把基础打好之-异常

在这里说说一些容易忽略的知识点。

  1. 对异常来说最重要的就是异常的类名。要做到见名知义。比如NullPointerException,IllegalStateException等,它们都只是简单地继承了RuntimeException。
public class NullPointerException extends RuntimeException {
    private static final long serialVersionUID = 5162710183389028792L;

    /**
     * Constructs a {@code NullPointerException} with no detail message.
     */
    public NullPointerException() {
        super();
    }

    /**
     * Constructs a {@code NullPointerException} with the specified
     * detail message.
     *
     * @param   s   the detail message.
     */
    public NullPointerException(String s) {
        super(s);
    }
}
  1. printStackTrace()方法所提供人信息可以通过getStackTrace()方法来直接访问,这个方法将返回一个栈轨迹中的元素所构成的数组,其中每一个元素都表示栈中的一帧。
public class WhoCalled {
    static void f(){
        try {
            throw new Exception();
        }catch (Exception e){
                  for(StackTraceElement ste:e.getStackTrace()){
                      System.out.println(ste.getMethodName());
                  }
        }
    }
    static void g(){f();}
    static void h(){g();}
    public static void main(String[] args){
        f();
        System.out.println("#############################");
        g();
        System.out.println("#############################");
        h();
        System.out.println("#############################");
    }
}

运行结果:

f
main
invoke0
invoke
invoke
invoke
main
#############################
f
g
main
invoke0
invoke
invoke
invoke
main
#############################
f
g
h
main
invoke0
invoke
invoke
invoke
main
#############################
  1. fillInStackTrack()用来更新栈信息,fillInStackTrack()方法将返回一个Throwable对象。通过下面的例子会直观一些。
public class Rethrowing {
    public static void f() throws Exception{
        System.out.println("f方法里的原始异常");
        throw new Exception("从f方法里面抛出的异常");
    }
    public static void g() throws Exception{
        try {
            f();
        } catch (Exception e) {
            System.out.println("g方法里面的catch代码块");
            e.printStackTrace(System.out);
            throw e;
        }
    }
    public static void h()throws Exception{
        try {
            f();
        } catch (Exception e) {
            System.out.println("h方法里面的代码块");
            e.printStackTrace(System.out);
            throw (Exception) e.fillInStackTrace();
        }
    }
    public static void main(String[] args){
        try {
            g();
        } catch (Exception e) {
            System.out.println("main方法中调用g方法");
            e.printStackTrace(System.out);
        }
        System.out.println("#####################");
        try {
            h();
        } catch (Exception e) {
            System.out.println("main方法中调用h方法");
            e.printStackTrace(System.out);
        }

    }
}

运行结果:

f方法里的原始异常
g方法里面的catch代码块
java.lang.Exception: 从f方法里面抛出的异常
    at exception.Rethrowing.f(Rethrowing.java:9)
    at exception.Rethrowing.g(Rethrowing.java:13)
    at exception.Rethrowing.main(Rethrowing.java:31)
main方法中调用g方法
java.lang.Exception: 从f方法里面抛出的异常
    at exception.Rethrowing.f(Rethrowing.java:9)
    at exception.Rethrowing.g(Rethrowing.java:13)
    at exception.Rethrowing.main(Rethrowing.java:31)
#####################
f方法里的原始异常
h方法里面的代码块
java.lang.Exception: 从f方法里面抛出的异常
    at exception.Rethrowing.f(Rethrowing.java:9)
    at exception.Rethrowing.h(Rethrowing.java:22)
    at exception.Rethrowing.main(Rethrowing.java:38)
main方法中调用h方法
java.lang.Exception: 从f方法里面抛出的异常
    at exception.Rethrowing.h(Rethrowing.java:26)
    at exception.Rethrowing.main(Rethrowing.java:38)

4.异常链,Throwable的子类在构造器中都可以一个cause对象作为参数。这个cause就用来表示原始异常,这样通过把原始异常传递给新的异常,使得在当前位置创建并抛出新的异常,也能通过这个异常链追踪最初发生的位置。需要注意的是,在Throwabe的子类中,只有三种基本的异常类提供了带cause参数构造器它们是Error,Exception和RuntimeException。如果要把其它类型的异常链接起来,应该使用initCause()方法而不是构造器。比如说:

new RuntimeException的子类(RuntimeException的其它子类的对象);
Exception的子类的对象.initCause(RuntimeException的子类对象);

5.在try块里有return,finally是会执行的。那如果finally也有return呢,会返回哪个呢?

public class FinallyTest {
    public static void main(String[] args){
System.out.println(testFinally());
    }
    private static String testFinally(){
        try{
            return "try";
        }finally {
            return "finally";
        }
    }
}

运行结果:

finally

这种结构会导致代码可读性变差。
5.异常的不足就是会导致异常丢失。异常作为程序出错的标志决不应该被忽略。然而某些使用finally子句就会发生这种情况。

public class LostException {
    class VeryImportantException extends Exception{
        @Override
        public String toString() {
            return "very important exception";
        }
    }
    class HoHumException extends Exception{
        @Override
        public String toString() {
            return "hohum exception";
        }
    }
    void f() throws VeryImportantException{
        throw new VeryImportantException();
    }
    void dispose() throws HoHumException{
        throw new HoHumException();
    }
    public static void main(String[] args){
        try{
            LostException lost=new LostException();
            try{
                lost.f();
            }finally {
                lost.dispose();
            }
        }catch (Exception e){
            System.out.println(e);
        }
    }
}

运行结果:

hohum exception

从输出结果中看到VeryImportantException不见了,它被finally子句中的HoHumException取代。这是相当严重的缺陷。
6.异常的限制,当覆盖方法的时候,只能抛出在基类方法的异常说明里列出的那些异常。这些限制很有用,因为这意味着,当基类使用的代码应用到派生类对象的时候,一样能够工作,当然这是面向对象的基本概念。异常也不例外。

public class ExceptionTest {
    class BaseException extends Exception{};
    class Foul extends BaseException{};
    class Strike extends BaseException{};
    abstract class Inning{
        public Inning () throws BaseException{}
        public void event () throws BaseException{}
        public abstract void atBat() throws Strike,Foul;
        public void walk(){};
    }
    class StormException extends Exception{};
    class RainedOut extends StormException{};
    class PopFoul extends Foul{};
    interface Storm{
        public void event() throws RainedOut;
        void rainHard() throws RainedOut;
    }
    public class StormyInning extends Inning implements Storm{
        //因为Inning的构造器抛出异常,所以它的继承类必须处理父类的异常,当然也可以抛出自己想要处理的异常
        public StormyInning()  throws BaseException,Foul{
        }
        //下面这个方法不能通过编译,因为在Inning方法中并没有抛出异常
//        @Override
//        public void walk() throws PopFoul{
//
//        }
        //接口不能基类中的方法添加异常,所以下面也不能编译
//        @Override
//        public void event() throws RainedOut{
//
//        }
        @Override
        public void event() {
        }
        //重写的方法可以抛出继承的异常
        @Override
        public void atBat() throws PopFoul {
        }
        @Override
        public void rainHard() throws RainedOut {
        }
    }
}

在Inning类中。可以看到构造器和event方法都声明将抛出异常,但实际上并没有抛出,这种方式使你强制用户去捕获可能在覆盖的event版本中增加的异常。

7.被检查异常并不总是好的,它有时候会使问题变得复杂,因为它强制你在还没有准备好处理问题的时候加上catch子句。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,598评论 18 399
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,633评论 18 139
  • 小编费力收集:给你想要的面试集合 1.C++或Java中的异常处理机制的简单原理和应用。 当JAVA程序违反了JA...
    八爷君阅读 4,578评论 1 114
  • 多态 任何域的访问操作都将有编译器解析,如果某个方法是静态的,它的行为就不具有多态性 java默认对象的销毁顺序与...
    yueyue_projects阅读 936评论 0 1
  • 2017年10月21日,我参加了小康哥和红红姐的婚礼。如果不是你,我又怎么会飞了几百公里,去参加这场无关紧要的婚礼...
    左离殇阅读 473评论 0 0