九、异常处理

一、 什么是异常

生活中:在事情发展过程中出现意外情况

程序中:在代码编译或运行过程中,程序出现错误,导致程序不能正常执行。

二、为什么要处理异常

程序一旦发生异常,会导致程序中途退出(程序崩溃),所以需要进行处理。处理之后,让程序正常执行。

三、 异常分类

Throwable中的方法:

  • printStackTrace():打印异常的堆栈信息,追根溯源。
  • getMessage():获取异常的详细信息。

Error:表示严重的问题,合理的应用程序不应该试图去捕获,通过代码无法处理。 Error异常一般是jvm发生的错误

Exception:异常

编译时异常:可以预测的,检查异常,需要进行强制的异常处理或者抛出。

运行时异常:在运行过程中发生的异常,不作强制处理要求。非检查异常。

InputMismatchException(输入不匹配异常)

ArithmeticException(数学运算异常)

ArrayIndexOutOfBoundsException(数组下标越界异常)

NullPointerException(空指针异常)

NumberFormatException(数据转换格式错误)

四、 如何进行异常处理

关键字:try:监视、catch:捕获、finally:最终、throw:抛出、throws:声明

 如何做异常处理:
1.在代码上加try..catch
2.在代码所在的方法上添加异常抛出声明

4.1 捕获异常

结构1: try..catch

应用场景: 可能发生异常的代码

try{
    //可能发生异常的代码
}
catch(异常类型 对象){
   //处理异常
}

结构2: try..catch..finally

finally应用场景:存在必须执行的代码(释放资源的代码)

finally块中的代码:无论代码是否出现异常,一定会执行,并且会在return之前运行。

public class Test2 {
    public static void main(String[] args) {
        try{
            int num1 = 10;
            int num2 = 0;
            System.out.println(num1/num2);
        }
catch (Exception ex){
            System.out.println("出错了");
            return; //在方法中,遇到return,代码执行到此结束,不再往下走
        }finally {
            // 代码1
            System.out.println("无论上面的代码是否出错,finally中的代码一定会执行...");
        }
        // 代码2
        System.out.println("=========================");
    }
}

结构3: 多重catch

应用场景:如果需要精确的把控各种异常的处理的话。

注意:先捕获细的异常,再捕获粗的异常

多分枝捕获,按从上到下的次序依次匹配,所以细粒度的异常要发放到上面,粗粒度的异常要放到下边

try{
  ...
}
catch(异常1){
  ...
}catch(异常2){
  ...
}catch(异常3){
  ...
}

public static void main(String[] args) {
    try {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入第一个数字:");
        int num1 = sc.nextInt();
        System.out.println("请输入第二个数字:");
        int num2 = sc.nextInt();
        // 进行两个数字的除法运算
        int res = num1 / num2;
        // 输出结果
        System.out.println("结果:" + res);
        String str = null;
        System.out.println(str.length());
    }catch (ArithmeticException ex){
 // 细粒度异常
        System.out.println("发生了数学运算异常:"+ex.getMessage());
    }catch (InputMismatchException ex){
 // 细粒度异常
        System.out.println("发生了输入不匹配异常");
    }catch (Exception ex){
 // 粗粒度异常 
       System.out.println("出错了:"+ex.getMessage());
    }
    //多分枝捕获,按从上到下的次序依次匹配
    //所以细粒度的异常要发放到上面,粗粒度的异常要放到下边
    System.out.println("=========================");}

结构4: try..finally

发生异常时finally的代码会被执行,但是因为没有catch处理异常,所以程序会崩溃

public class Test3 {
    public static void main(String[] args) {
        try{
            System.out.println("这是try代码");
            System.out.println(1/0);
        }finally {
            System.out.println("这是finally");
        }
        System.out.println("=======================");
    }
}

4.1 手动抛出异常

用于个性化(特定的业务需求)的异常处理

比如:学生的性别,年龄输入错误

方法1:throw

//在方法中使用:
if(条件)	
throw new Exception("错误消息");

方法2:throws

在方法签名后面使用,声明方法可能抛出的异常,一般会配合检查异常(编译时异常)使用

 

public class Student {
    // 属性
    private String name;
    private int age;
    // getter,setter
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    // 设置年龄
    //  throws Exception:方法的异常抛出声明
    public void setAge(int age) throws Exception {
        if(age<0 || age>100){
            // 手动抛出错误,中断程序执行
            throw new Exception("年龄设置错误");
        }
        this.age = age;
    }
}

public class Test {
    public static void main(String[] args) {
        try {
            Student student = new Student();
            student.setName("张三");
            student.setAge(-18);
            System.out.println("姓名:"+student.getName());
            System.out.println("年龄:"+student.getAge());
        }catch (Exception ex){
            System.out.println("设置对象出错:"+ex.getMessage());
        }
    }
}
public class Test2 {
    // throws: 异常抛出声明,表示当前这个方法可能会出错,以此提示方法的调用者要进行异常处理
    //测试方法
    public static  void aaa() throws Exception{
    }
    // main方法是jvm运行程序的入口,有了错误,有jvm直接处理(中断程序执行)
    public static void main(String[] args) throws Exception {
        System.out.println("程序开始执行");
        // main方法中如何调用aaa方法
        // 1.让aaa也变成静态的,可以直接调用
        // 2.当aaa是实例方法的时候,如何调用
        //   先创建实例方法对应类的对象,通过对象调用实例方法
        //Test2 t = new Test2();
        //t.aaa();
        // 实例方法只能通过对象调用
        // 如何做异常处理:
        // 1.在代码上加try..catch
        // 2.在代码所在的方法上也添加异常抛出声明
//        try {
//            aaa();
//        }catch (Exception ex){
//
//        }
        aaa();
    }
}

五、自定义异常

        java中给我们提供的异常很多,但是有些满足不了我们的需求,所以此时需要我们自己去定义异常。

// 自定义异常
public class SexException extends Exception {
    // 自定义异常类的构造
    public SexException(String errorMsg){
        // 调用父类异常的有参构造,让父类维护异常信息
        super(errorMsg);
    }
}

public class AgeException extends Exception{
    // 有参构造
    public AgeException(String errorMsg){
        // 调用父类构造,让父类维护异常信息
        super(errorMsg);
    }
}

public class Student {
    // 属性
    private String name;
    private String sex; // 加校验
    private int age; // 加校验
    // getter,setter
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) throws SexException {
        if(sex.equals("男") || sex.equals("女")) {
            this.sex = sex;
        }else{
            throw new SexException("性别设置错误");
        }
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) throws AgeException {
        if(age>=0 && age<=100) {
            this.age = age;
        }else{
            throw new AgeException("年龄设置错误");
        }
    }

    // toString()
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", age=" + age +
                '}';
    }
}

public class Test {
    public static void main(String[] args) {
        try {
            Student student = new Student();
            student.setName("张三");
            student.setSex("x"); //爆出性别异常
            student.setAge(180); // 爆出年龄异常
            System.out.println(student);
        }catch (SexException ex){
            System.out.println("设置学生出错:"+ex.getMessage());
        }catch (AgeException ex){
            System.out.println("设置学生出错:"+ex.getMessage());
        }catch (Exception ex){
            System.out.println("出错了:"+ex.getMessage());
        }
//        Student student = new Student();
//        student.setName("张三");
//
//
        try {
//            student.setSex("x");//爆出性别异常
//        } catch (SexException e) {
//            e.printStackTrace();
//        }
//
//        try {
//            student.setAge(180); // 爆出年龄异常
//        } catch (AgeException e) {
//            e.printStackTrace();
//        }
//
//        System.out.println(student);
    }
}

六、 debug调式测试

java中如何调试代码

1) 在代码的指定位置设置断点

 2) 用debug方式启动程序,当程序执行到断点处时,会自动停下,此时需要通过手动控制程序的执行

3) 手动控制程序执行的主要方式:

stepover(步过) : 遇到单行代码,逐行执行,遇到方法不进入

stepinto(步入): 遇到单行代码,逐行执行,遇到方法会进入方法内部执行

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值