04 - JavaSE之异常处理

异常的概念(运行期出现的错误)

  • java 异常是 java 提供的用于处理程序中错误的一种机制。
  • 所谓的错误是指在程序运行的过程中发生的一些异常事件。(如:除0溢出,数组下标越界,所要读取的文件不存在)
  • 设计良好的程序应该在异常发生时提供处理这些错误的方法,使得程序不会因为异常的发生而阻断或产生不可预见的结果。
  • java 程序的执行过程中如果出现异常事件,可以生成一个异常类对象,该异常对象封装了异常事件的信息并将被提交给java运行时系统,这个过程被称为抛出(throw)异常。
  • 当 java 运行时系统接收到异常对象时,会寻找能处理这一异常的代码并把当前异常对象叫给其处理,这一过程称为捕获(catch)异常。
  • try里面编写可能抛出异常的代码,catch编写捕获异常后处理的代码。
  • 把发生异常的堆栈打印出来:e.printStackTrace();

异常的分类

  • 异常根类 Throwable 分子类 Error + Exception
  • Error 是系统内部错误(虚拟机生成并抛出,包括动态链接失败,虚拟机错误等,程序不对其做处理)。
  • Exception是我们可以处理的所有异常类的父类,其子类对应了各种各样可能出现的异常事件,一般需要用户显式的声明或捕获。
  • Exception 分 RuntimeException(运行期异常)+ 其他。
  • RuntimeException:一类特殊的异常,如除0异常,数组下标越界等,其产生的比较频繁,处理麻烦,如果显式的声明或者捕获将会对程序的可读性和运行效率影响很大。因此由系统自动检测并将它们交给缺省的异常处理程序,用户可以catch,也可以不catch。
void m(int i) throws ArithmeticException {
    if(0==i) {
        throw new ArithmeticException("除0异常 1th");
    }
}

public class Test {
    public static void main(String[] args) {
        
        try {
            Test t = new Test();
            t.m(0);
        } 
        catch (Exception e) {
            System.out.println("除0异常 2th");
        }
    }
}
  • 常见异常类型举例:
  1. ArithmeticException
int i = 1;
int k = 0;
int m = i/k;
  1. NullPointerException
String s = null;
int l = s.length();
  1. ClassCastException
Object o = new Object();
String s = (String)o;
int l = s.length();
  1. NegativeArraySizeException
int len = -1;
int[] a = new int[len];
a[0] = 0;
  1. ArrayIndexOutOfBoundsException
int len = 10;
int[] a = new int[len];
a[10] = 10;

异常的捕获和处理

  • try语句:
  1. try语句制定了一段代码,该段代码就是一次捕获并处理的例外的情况。
  2. 在执行的过程中,该段代码可能会产生并抛出一种或几种类型的异常对象,它后面的catch语句要分别对这些异常做相应的处理。
  3. 如果没有例外产生,所有的catch代码段都被忽略不执行。
  • catch语句:
  1. 在catch语句块中是对异常进行处理的代码,每个try语句块可以伴随一个或多个catch语句,用于处理可能产生的不同类型的异常对象。
  2. 在catch中声明的异常对象(catch (someExpresion e))封装了异常事件发生的信息,在catch语句块中可以使用这个对象的一些方法获取这个信息:例如:getMessage(); 用来得到有关异常事件的信息;printStackTrace();用来跟踪异常事件发生时执行堆栈的内容。
  • finally语句:
  1. catch语句块后面可以跟上一个finally语句块。
  2. finally语句为异常处理提供一个统一的出口,使得在控制流程转到程序的其他部分以前,能对程序的状态作统一的管理。
  3. 无论try所指向的程序是否抛出异常,finally所指定的代码都要被执行。
  4. 通常在finally语句中可以进行资源的清理工作。如:关闭打开的文件;删除临时文件等。
FileInputStream in = null;

try {
    in = new FileInputStream("myfile.txt");
    int b = 0;
    b = in.read();
    while(-1 != b) {
        System.out.print((char)b);
        b = in.rasd();
    }
} 
catch (FileNotFoundException e) {
    e.printStackTrace();
} 
catch (IOException e) {
    System.out.println(e.getMessage());
} 
finally {
    try {
        in.clsoe();
    }
    catch (IOException e) {
        e.printStackTrace();
    }
}

异常的抛出

public void someMethod() throws someExpresion { 
    if(someCondition()) {
        throw new someExpresion("错误原因"); // 然后在某种情况下抛出这种异常
    }
}

try {
    someMethod(); // 调用该方法时试图捕获异常
}
catch(someExpresion e) {
    // 异常处理代码
}

** Tips:

  1. public void someMethod() throws someExpresion: throws写在后面声明该方法可能抛出异常(由系统自动抛出异常),如果写了这句话,对于RuntimeException 则可以不catch,其他的异常则需要写try catch,如果你不想写try catch,则你可以再继续往外抛(在方法后面写throws)。

2.throw new someExpresion("错误原因"); 表示的是手动抛出异常。 **

public class Test {
    public static void main(String[] args) {
        Test t = new Test();
        try {
            t.method1();
        } catch (someException e) {
            e.printStackTrace();
        }
    }
    
    public void method1() throws someException {
         method2();
    }
    
    public void method2() throws someException {
         method3();
    }
    
    public void method3() throws someException {
         throw new someException("someException occur in method3.");
    }
}

注意

  1. 执行throw语句之后,运行流程立即停止(如上第一份代码第二个End未打印)。然后系统立即检查是否有能够匹配的catch语句块,如果找到则执行对应的catch语句块,如果找不到则转向上一层的try语句块并继续查找对应的catch语句块,如果一直找不到对应的catch语句块,则异常对象被抛到系统异常处理。
public class Test {
    public static void pro(String s) {
        if(s != null) {
            System.out.println(s);
        }
        else {
            throw new NullPointerException("Ooops!, s is null.");
        }
        System.out.println("End");
    }
    
    public static void main(String[] args) {
        
        try {
            pro("Hello Java");
            pro(null);
        }
        catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}
/*
打印结果:
Hello Java
End
Ooops!, s is null.
*/
  1. catch时注意:应该先捕获小的,再捕获大的,否则编译报错。
catch (NullPointerException e) {
    System.out.println("NullPointerException");
}
catch (Exception e) {
    System.out.println(e.getMessage());
}

使用自定义的异常

使用自定义异常一般有如下步骤:

  1. 通过集成 java.lang.Exception 类声明自己的异常类。
  2. 在方法适当的位置生成自定义异常的实例,并用 throw 语句抛出。
  3. 在方法的声明部分用 throws 语句声明该方法可能抛出的异常。
class MyException extends Exception {
    private int id;
    
    public MyException(String message, int id) {
        super(message);
        this.id = id;
    }
    
    public int getId() {
        return id;
    }
}

public class Test {
    public void regist(int num) throws MyException {
        if(num < 0) {
            throw new MyException("人数为负。", 3);
        }
        System.out.println("登记人数:" + num);
    }
    
    public void manager() {
        try {
            regist(100);
        }
        catch (MyException e) {
            System.out.println("登记失败,出错类型码:" + e.getId());
            e.printStackTrace();
        }
        System.out.println("操作结束");
    }
    
    public static void main(String[] args) {
        Test t = new Test();
        t.manager();
    }
}

异常与继承

重写方法需要抛出与原方法所抛出异常类型一致的异常或不抛出异常。

例如:

class A {
    public void method() throws IOException {...}
}

class B1 extends A {
    public void method() throws FileNotFoundException {...} // 范围小了,错误
}

class B2 extends A {
    public void method() throws Exception {...} // 范围大了,错误
}

class B3 extends A {
    public void method() {...} // 正确
}

class B3 extends A {
    public void method() throws IOException, MyException{...} // 错误
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏xingoo, 一个梦想做发明家的程序员

剑指OFFER之把数组排成最小的数(九度OJ1504)

题目描述: 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排...

19210
来自专栏ShaoYL

深刻理解----修饰变量----关键字

34911
来自专栏Python小屋

详解Python序列解包

序列解包(Sequence Unpacking)是Python中非常重要和常用的一个功能,可以使用非常简洁的形式完成复杂的功能,大幅度提高了代码的可读性,减少了...

3497
来自专栏Pythonista

__slots__(面向对象进阶)

1024
来自专栏hrscy

Swift2.1-下标脚本下标脚本

类,结构体和枚举可以定义下标脚本,下标脚本可以认为是访问集合(collection),列表或序列的成员元素。你可是使用下标脚本来设置或通过索引检索值,而不需要调...

783
来自专栏大愚Talk

我对变量产生了这些想法

最近在学习Golang的过程中,发现一个有意思的事情,有的文章说函数调用传参时 slice 是引用传递,有的说是值传递。为什么同一个东西大家会不同认识?为了搞清...

831
来自专栏企鹅号快讯

如何写好python代码

写代码好比画画,好的代码就像一件艺术品,美观、可读性高,让人看着舒服。代码是写给人看的,不是写给机器看的,遵守一定的代码规范很重要,就像写作文需要总分总结构,这...

4027
来自专栏前端黑板报

(转)JS算法系列-数组去重

1.遍历数组法 最简单的去重方法, 实现思路:新建一新数组,遍历传入数组,值不在新数组就加入该新数组中;注意点:判断值是否在数组的方法“indexOf”是ECM...

2139
来自专栏LuckQI

Redis初识~List命令

1062
来自专栏青玉伏案

Java编程之委托代理回调、内部类以及匿名内部类回调(闭包回调)

最近一直在看Java的相关东西,因为我们在iOS开发是,无论是Objective-C还是Swift中,经常会用到委托代理回调,以及Block回调或者说是闭包回调...

2029

扫码关注云+社区

领取腾讯云代金券