Java基础之异常

异常

  • 编译时检测:Exception和其子类(除了RuntimeExpection)
  • 运行时检测:RuntimeException

编译时异常

继承自Exception的,编译时就检查,一般来自外界因素,或者语法错误,比如有时候读文件,当路径错误或者文件名打错了,就会抛出。这种类型的异常抛出后必须处理,比如在某个方法内可能出现该类型的异常,要么在方法头加上throws继续往上抛,直到某一级catch到为止。要么在方法体里try catch,这里处理过了调用时就不用再处理了。当调用该方法时,也可以用throws或者用try catch。

public class Test {
  // 方法体内try-catch
public void run1() {
  try {
            throw new Exception();
        } catch (Exception e) {
            e.printStackTrace();
        }
}

// 方法头throws给上级调用者
public void run2() throws Exception {
        throw new Exception();
}
  
  public static void main(String args[]) /*run2()或者在这里throws*/{
    Test t = new Test();
    t.run1();  // run1()方法体内已经处理,这里不用catch,也不用在main上throws
    
        // run2()只是throws,仅提示这里可能会抛出,并没有处理,所以这里必须处理,要么继续抛(main函数上throws,要么catch)
    try {
        t.run2();
    } catch (Exception e) {
      // 实际开发肯定不能这样,必须进行相应处理
      // handle code
      e.printStackTrace();
    }
  }
}

运行时异常

继承自RuntimeException,编译时不会抛出,直到运行到那行代码才抛出,此时问题发生无法让功能正常进行,如数组下边越界,更多是由于调用者的原因(代码写得有问题,比如本应该是arr[i]写成了arr[i+1])或者引发了内部状态改变导致,异常抛出后可处理可不处理,编译让其通过,运行时强制停止,让调用者去处理。即方法头不用加throws,方法体内也不用catch。

public class Test {
    // 不用处理
    public void run1() {
        throws new RuntimeException();
    }

    public static void main(String args[]) {
        Test t = new Test();
        t.run1(); // 调用也不处理,程序终止
      
      // 调用时正确处理,程序继续
        try {
          t.run1();
        } catch (Exceptipon e) {
          // 实际开发肯定不能这样,必须进行相应处理
          // handle code
          e.printtStackTrace();
        }
    }
}

自定义异常类

public class MyException extends RuntimeException {
  // 构造函数一般用父类的
  MyException(String s) { super(s); }
}

// another file
public class Test {
  public void run() {
    if (/*expression*/) {
      throws new MyException("自定义异常") // 传入实参给了super(s)
    }
    else {
      // code...
    }
  }
  
  public static void main(String args[]) {
    Test t = new Test();
    try {
       t.run();
    } catch (RuntimeException e) {
      // handle code
      e.printStackTrace();
    }
   
  }
}

什么时候用try,什么时候用throws

  • 能自己解决的用try,比如数组下标越界,调用者可以事先作判断下标的范围,防止该异常发生。即使造成异常,程序终止,也可以通过修改代码解决。
  • 不能自己解决的,比如IO异常,文件没有被关闭,数据库连接异常,访问不存在的路径等,我们没有办法自己搞定,只能上报上级(throws),试想如果路径出错了,根本就没有这个文件。而又try-catch,捕获后程序正常运行,并没有把路径错误给暴露出去。(路径都错了后面的程序能正常运行吗?)这就叫“把异常给吃(隐藏)了”。相反,如果继续抛出,一直到程序终止,用户看到异常信息就知道是路径错了,需要改路径。这样的异常写代码的人根本无法处理,不是改代码就可以的,毕竟程序猿怎么改也可能有人把路径写错:)

异常的其他注意事项

  • try -catch还可搭配finally使用,无论捕获异常否,finally里面的内容必然或执行,一般用于关闭文件、关闭连接、释放资源等
  • 也可以不catch,只try-finally。比如某个函数可能抛出异常,我不想处理,但是又必须要把某件事给做了,这是就可以用这种结构。
  • throw了多少(n)个异常,就要catch多少(n)个异常。
  • 父类方法头若没有throws异常,子类方法覆盖父类时候,子类的方法头不能throw异常。
  • throw是确确实实抛出了一个异常,而throws是提醒、标注这儿可能出现异常,并没有实际抛出。

异常的一个形象的例子

上面说的什么时候用try,什么时候用throws还是很抽象的,我也不知带自己在说什么。和实际生活结合起来,看下面这个例子就豁然开朗了,为了直观,部分代码采用中文,注意这很不规范,仅为了便于理解异常。

// 老师用电脑上课

class 电脑蓝屏异常 extends RuntimeException {
    电脑蓝屏异常(String s) { super(s); }
}
class 电脑烧坏异常 extends RuntimeException {
    电脑烧坏异常(String s) { super(s); }
}
// 电脑烧坏时,午饭自己解决,抛出这个异常个老板,让老板给出解决方案
class 上报老板异常 extends Exception {
    上报老板异常(String s) { super(s); }
}
class Computer {
    // 电脑运行状态标志位,0位正常运行
    private int flag = 1;
    public void run() {
        if (flag == 1) {
            throw new 电脑蓝屏异常("你的电脑蓝屏啦!");
        } else if (flag == -1) {
            throw new 电脑烧坏异常("你的电脑烧坏啦!");
        } else {
            System.out.println("老师上课中...");
        }
    }
    public void reset() {
        // 重启后正常运行,标志位置0
        flag = 0;
        // 重启电脑
        System.out.println("电脑重启中...");
    }
}


public class Teacher {
    public static void main(String args[]) throws 上报老板异常 {
        Computer pc = new Computer();
        try {
            pc.run();
        } catch(电脑蓝屏异常 e) {
            System.out.println("同学们,电脑出了点小毛病,大家等几分钟就好了");
            // 蓝屏了可以自己处理,重启一下电脑就行,所以
            pc.reset();
            pc.run();
        } catch(电脑烧坏异常 e) {
            System.out.println("同学们,这节课我们不能继续上课了,自习");
            e.printStackTrace();
            // 烧坏了,没办法自己解决,要么拿去给修电脑的,要么上报给老板买个新的
            // 所以继续抛向上级
            throw new 上报老板异常("老板..电脑..坏了..需要买新的");
        }
    }
}
  • flag设置为1,说明电脑蓝屏了,运行以上代码,打印如下信息,可以看到,正确处理了异常后,老师又开始上课了。

同学们,电脑出了点小毛病,大家等几分钟就好了
电脑重启中...
老师上课中...

  • flag设置了-1,说明电脑烧坏了,会打印以下信息。抛出异常。

同学们,这节课我们不能继续上课了,自习
Test.电脑烧坏异常: 你的电脑烧坏啦!

at Test.Computer.run(Teacher.java:21)
at Test.Teacher.main(Teacher.java:39)
Exception in thread "main" Test.上报老板异常: 老板..电脑..坏了..需要买新的
at Test.Teacher.main(Teacher.java:50)
同学们,这节课我们不能继续上课了,自习

注意:以上代码虽然很多中文,但是可以直接编译运行成功的。因为默认编码方式是UTF-8。


by @sunhaiyu

2016.12.12

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 导语 异常指的是在程序运行过程中发生的异常事件,通常是由硬件问题或者程序设计问题所导致的。异常处理提供了处理程序运...
    jerrwy阅读 3,349评论 0 2
  • 一、异常处理机制1、异常的祖先是Throwable,有如下两个子类:a、Error:表示错误,错误产生后程序员不能...
    坚持也是一种成功阅读 4,241评论 3 27
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 32,449评论 18 399
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,833评论 19 139
  • 个体心理学在心理和教育方面视野开阔,固然不会忽视外在环境的影响。所有的教育者都必须考虑到经济因素对儿童的影响。例如...
    美好jenny阅读 3,411评论 0 0

友情链接更多精彩内容