Java异常处理

目录

异常引出

 异常事件分类

运行时异常和编译时异常的区别

异常体系图

常见的运行时异常

 异常处理的两种方式

对多个异常的捕获处理

异常处理注意事项

自定义异常

常用的异常方法

throws和throw的区别


异常引出

* 异常基本介绍

对于程序员来说,编程中遇到大大小小的错误十分常见(应该不会有什么大佬一次写完几百行代码还不会报错吧)。当程序报错时,要么它无法运行,要么运行时会提示一行醒目的红色信息。导致程序不能运行的也许是一个简单的错误,但会让整个大型项目崩溃。所以可以用一些方法让程序在有错误的情况还能继续运行。我们把写代码是遇到的错误称为异常,把这些针对异常的处理方法叫做异常处理。我们先展示一段有异常的代码:

定义:Java语言中,将程序执行中发生的不正常情况称为“异常”(开发中的语法错误和逻辑错误不是异常)。

public class Exception {
    public static void main(String[] args) {
        //把引用变量person指向空值
        Person person = null;
        person.getName();
        System.out.println("程序运行完毕、、、");
    }
}
//含有一个成员变量的Person类
class Person{ 
    private String name = "小黄";

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

运行结果如下:

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "Exception.Person.getName()" because "person" is null
	at Exception.Exception.main(Exception.java:7)

代码说明:1:以上代码因为把Person类的引用指向了空,所以会报NullPointerException(空指  针异常);

2:我们看到最后的输出语句没有执行,因为遇到异常时,JVM会把异常信息打印出来                  (如图),然后终止程序执行;

3:因为一个异常可能导致后续的重要项目停止执行,所以需要异常处理机制。

 异常事件分类

程序执行中把可能发生的异常事件分为两大类:

1:Error(错误):JVM无法解决的严重问题:如:JVM系统内部错误,资源耗尽等严重情况。比如:StackOverflowError(栈溢出)和OOM,Error是严重错误,程序会崩溃;

2:Exception(异常):其他因编程错误或偶然的外在元素导致的一般性问题,可以使用针对性的代码进行处理。例如空指针访问,试图读取不存在的文件,网络连接中断等等;

Exception分为两大类:运行时异常(程序运行时发生)和编译时异常(编程时编译器检查出的异常)。

运行时异常和编译时异常的区别

运行时异常:一般指代码中的逻辑错误,在程序运行时发生,编译器不会进行自动提示(不要求必须处理)。会由JVM输出异常信息。

编译时异常:编程时编译器会自动提示的异常,要求必须处理

异常体系图

说明: 1:可以捕获的异常都被封装在Exception类中,该类继承了Throwable类;

2:运行时异常包含了很多子类异常;

3:常见的子类异常有:NullPointerException(空指针异常),                                                        ArrayIndexOutOfBoundsException(数组下标越界异常),ArithmeticException(算数异              常),ClassCastException(类型转换异常),NumberFormatException(数字格式不正              确异常)。

常见的运行时异常

*  NullPointerException空指针异常

实例代码如上所示:

说明:当程序试图在需要对象的地方使用null时,抛出该异常;

*   ArrayIndexOutOfBoundsException数组下标越界异常

public class Exception02 {
    public static void main(String[] args) {
        //定义下标最大值为2的数组
        int[] array = {1,2,3};
        //输出下标为3的数组
        System.out.println(array[3]);
    }
}

说明:1:用非法索引访问数组时抛出的异常;

2:如果索引为负或大于等于数组的大小,则该索引为非法索引。

*  ClassCastException类型转换异常 

public class Exception03 {
    public static void main(String[] args) {
        //向上转型使Person父类引用指向Student子类实例
        Person1 person1 = new Student();
        //Person1对象接收了Student类的实例,所以可以把Person类的引用强转为Student类
        Student student = (Student)person1;
        //Person类的引用没有接收Teacher类的实例(Teacher类不是person1对象的实例)
        //所以不能把Person类的引用强转为Teacher类
        Teacher teacher =(Teacher)person1;
    }
}
class Person1{}
class Student extends Person1{}
class Teacher extends Person1{}

说明:当试图将对象转换为不是实例的子类时,抛出该异常。

补充:在对象向下转型中,父类是实例不能强制转换为任意子类实例的,应该先通过向上转型和子类实例产生联系,然后才能通过向下转型转为子类实例,否则会抛出ClassCastException异常。

*  ArithmeticException数学运算异常

public class Exception04 {
    public static void main(String[] args) {
        //o不能做被除数
        int a = 1/0;
        System.out.println(a);
    }
}

说明:当出现异常的运算条件时,抛出此异常。

*  NumberFormatException数字格式不正确异常

public class Exception05 {
    public static void main(String args[]){
        String name = "小黄";
        //文字字符串不能通过方法转变为整型变量
        int num = Integer.parseInt(name);  
    }
}

说明:当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换成适当格式时,抛出该异常。

 异常处理的两种方式

*  try--catch方式

public class Exception06 {
    public static void main(String[] args) {
        try{
            //用try代码块把可能出现异常的语句装起来
            int n = 1/0;
            System.out.println(n);
        }catch (ArithmeticException e){
            //catch代码块捕获异常,并调用getMessage方法输出异常信息
            System.out.println("打印出异常信息:" + e.getMessage());
        }finally {
            //处理完毕后执行finally代码块的内容
            System.out.println("程序继续运行、、、");
        }
    }
}

运行结果:

打印出异常信息:/ by zero
程序继续运行、、、

说明: 1:该方式由三个代码块组成;

2:用try代码块把程序员认为可能出现异常的代码段括起来;

3:用catch代码块捕获该异常传递给异常类的对象,可以用该对象调用异常类的方法进行                处理,怎么处理看自己;

4: finally代码块进行异常处理后的后续工作,常常进行释放资源的操作;

5:如果try代码块中发生了异常,则异常后的代码不执行,跳到catch代码块;

6:如果try代码块中没有出现异常,则不会执行catch代码块的内容,直接执行finally的内                容;

7:finally代码块可以不写。

8:格式:

try{
//可能发生的异常
}catch(异常类名 异常对象){
//对异常的处理操作
}finally{
//异常处理之后的操作
}

注:异常类名应该和可能发生的异常一致,或者是它的父类;

*  throws方式

public class Exception07 {
    //指定该方法抛出算数异常
    public void age1() throws ArithmeticException{
        System.out.println("我的年龄为:" + (1/0));
    }
    //方法的调用者age2方法处理了该异常
    public void age2(){
        try {
            new Exception07().age1();
            System.out.println("说错了,我的年龄是12岁。");
        }catch (ArithmeticException e){
            System.out.println("调用者捕获了该异常。");
            System.out.println(e.getMessage());
        }finally {
            System.out.println("程序继续运行。。。");
        }
    }

    public static void main(String[] args) {
        //调用age2方法
        Exception07 exception07 = new Exception07();
        exception07.age2();
    }
}

运行结果:

调用者捕获了该异常。
/ by zero
程序继续运行。。。

说明:1: 该方式只相当于修饰方法的语句,不影响程序运行;

2:如果一个方法可能出现某种异常,但不确定或不想马上处理该异常,可以用throws显式             的抛出该异常,由该方法的调用者处理;

3:throws使用目的在于声明方法的可能出现的异常,表示当前方法不处理该异常,由此提             醒方法的调用者处理该异常;

4:方法的调用者也可选择try - catch捕获该异常或者继续用throws向上抛出异常;

5:最后一定要有方法捕获该异常进行处理;

6:如果一直不处理该异常,程序会默认向上一级抛出异常,最后会交给JVM处理(JVM为             最高级);

7:JVM会输出异常信息,并中断程序执行;

8:throws后面可以跟多个异常(异常列表),不同的异常用","隔开。

对多个异常的捕获处理

如果程序有多个不同类的异常,可以用 try-catch同时处理,有两种方式:

*  用包含这些异常的父类异常同时捕获

public class Exception08 {
    public static void main(String[] args) {
        try{
            //空指针异常
            Person03 person03 = null;
            person03.call();
            //算数异常
            int n = 1/0;
            //用父类异常RuntimeException同时捕获
        }catch (RuntimeException e){
            //输出异常信息
            System.out.println(e.getMessage());
        }finally {
            System.out.println("程序继续执行、、、");
        }
    }
}
class Person03{
    public void call(){
        System.out.println("这是个person。。。");
    }
}

说明:ArithmeticException和NullPointerException都是运行时异常(RuntimeException)的子  类,因此可以用RuntimeException的对象同时封装两种异常进行处理;

*  用不同的子类异常单独捕获

public class Exception09 {
    public static void main(String[] args) {
        try {
            //算数异常
            int n = 1 / 0;
            //空指针异常
            Person4 person4 = null;
            person4.p4();
        }
            //单独捕获算数异常
        catch (ArithmeticException ar){
            System.out.println(ar.getMessage());
            //单独捕获空指针异常
        }catch (NullPointerException un){
            System.out.println(un.getMessage());
        }finally {
            System.out.println("程序继续运行、、");
        }
    }
}
class Person4{
    public void p4(){
        System.out.println("这是一个人。");
    }
}

说明:该代码分别用子类异常捕获了不同的异常,分别进行处理。

注:要求子类异常写在前面,父类异常写在后面,或者两者都为同级的异常类;

原因:父类异常会一并捕获含有的子类异常,此时再写子类异常没有意义;

异常处理注意事项

1:对于编译异常程序必须处理,比如try catch或throws;

2:对于运行时异常,程序如果没有处理,默认就是throws的处理方式。

3:子类重写了父类的方法时,如果子类和父类都抛出了异常,那么子类的方法抛出的异常必须和父类的方法抛出的异常相同,要么是父类的方法抛出异常的子类;

4:throws和try catch最好二选一,不要同时存在,没有意义;

自定义异常

public class CustomException {
    public static void main(String[] args) {
        int age = 200;
        //如果年龄不在指定区间则抛出自定义异常
        if(!(age <= 0 && age >= 100)){
            //输出指定异常信息
            throw new AgeException("年龄需要在之间0-100之间");
        }
        System.out.println("你的年龄输入正确");
    }
}
//自定义AgeException类继承运行时异常类
class AgeException extends RuntimeException{
    //用构造方法调用父类异常的构造方法,接收异常信息
    public AgeException(String massage){
        super(massage);
    }
}

输出结果:

Exception in thread "main" Exception.AgeException: 年龄需要在之间0-100之间
	at Exception.CustomException.main(CustomException.java:9)

使用方法:1:自定义个异常类(类名自己写),来继承父类异常;              

2:如果继承Exception,属于编译异常;

3:如果继承RuntimeException,属于运行时异常,一般情况我们都是继承                                      RuntimeException;

4:代码中调用的父类构造方法目的在于打印指定的异常信息。

5:throw后面跟自定义异常对象的实例(或引用),可以同时进行方法的调用。

常用的异常方法

Throwable类提供了很多处理异常的方法,下面列举三个常用的:

*  getMessage方法

说明:返回指定异常的详细信息。

*  printStackTrace方法

说明:输出异常的名称,和异常的位置。

*  toString方法

说明:输出说明异常地址和类型的字符串。

throws和throw的区别

用法格式使用位置
throws异常处理的方式关键字加异常列表方法声明处
throw抛出自定义异常的关键字关键字加自定义异常对象方法体中

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值