Day14 异常机制

异常引入:

这里写图片描述
这里写图片描述
程序中的异常
示例:给出除数和被除数,求商
如果除数为0,出异常
如果除数或者被除数不是数字,出异常

public class TestException {

    public static void main(String[] args) {
        int a,b,c;//a:被除数  b:除数  c:商
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入被除数");
        a = scanner.nextInt();
        System.out.println("请输入除数");
        b = scanner.nextInt();
        //求商
        c = a / b;
        System.out.println("商为:"+c);

        scanner.close();
    }
}

这里写图片描述
这里输入了字符a,虚拟机直接炸了,这里有异常没有处理。

异常概念

异常分类

这里写图片描述

Error

Error类层次描述了Java运行时系统内部错误和资源耗尽错误,一般指与JVM或动态加载等相关的问题,如虚拟机错误,动态链接失败,系统崩溃等。

这类错误是我们无法控制的,同时也是非常罕见的错误。所以在编程中,不去处理这类错误。

打开JDK包:java.lang.Error,查看他的所有子类

注:我们不需要管理Error!

Exception

所有异常类的父类,其子类对应了各种各样可能出现的异常事件。

Exception分类
运行时异常Runtime Exception(unchecked Exception)
可不必对其处理,系统自动检测处理
一类特殊的异常,如被 0 除、数组下标超范围等,其产生比较频繁,处理麻烦,如果显式的声明或捕获将会对程序可读性和运行效率影响很大
检查异常 Checked Exception
必须捕获进行处理,否则会出现编译错误

注意:只有Java提供了Checked异常,体现了Java的严谨性,提高了Java的健壮性。同时也是一个备受争议的问题。

异常处理的分类:

这里写图片描述
1. try-catch-finally 直接处理异常
2. throw 抛出异常
throws 声明异常
这里写图片描述

try-catch

catch块中如何处理异常
输出用户自定义异常信息
System.err.println(“除数不能为零。”);
System.err.println(“被除数和除数必须是整数。”);

调用异常对象的方法输出异常信息
toString ( )方法,显示异常的类名和产生异常的原因
void printStackTrace() 输出异常的堆栈信息
String getMessage()返回异常信息描述字符串,是printStackTrace()输出信息的一部分

继续向上抛出异常
throw e
这里写图片描述

try-catch-finally

在try-catch块后加入finally块,可以确保无论是否发生异常,finally块中的代码总能被执行
无异常 try-finally
有异常 try-catch-finally
通常在finally中关闭程序块已打开的资源,比如:文件流、释放数据库连接等。

finally块中语句不执行的唯一情况
异常处理代码中执行System.exit(1)退出Java虚拟机
Finally块的具体执行过程
执行try或catch中代码
遇到return/throw,先执行finally中语句块
执行return/throw

多重catch

一段代码可能会引发多种类型的异常
当引发异常时,会按顺序来查看每个 catch 语句,并执行第一个与异常类型匹配的catch语句
执行其中一条 catch 语句后,其后 catch 语句将被忽略

在安排catch语句的顺序时,首先应该捕获最特殊的异常, 然后再逐渐一般化,即先子类后父类

抛出或声明异常
声明异常throws

当Checked Exception产生时,不一定立刻处理它,可以再把异常Throws出去

如果一个方法抛出多个已检查异常,就必须在方法的首部列出所有的异常,之间以逗号隔开

子类声明的异常范围不能超过父类声明范围
父类没有声明异常,子类也不能
不可抛出原有方法抛出异常类的父类或上层类

手动抛出异常throw

Java异常类对象除在程序执行过程中出现异常时由系统自动生成并抛出,也可根据需要手工创建并抛出。

在捕获一个异常前,必须有一段代码先生成异常对象并把它抛出。这个过程我们可以手工做,也可以由JRE来实现,但是他们调用的都是throw子句。

注意抛出运行时异常和Checked异常的区别
抛出Checked异常,该throw语句要么处于try块中,要么方法签名中石油throws抛出
抛出运行时异常,没有以上要求

自定义异常

在程序中,可能会遇到任何标准异常类都没有充分的描述清楚的问题,这种情况下可以创建自己的异常类

从Exception类或者它的子类派生一个子类即可

习惯上,定义的类应该包含2个构造器:一个是默认构造器,另一个是带有详细信息的构造器
例子:

//自定义异常(检查类的性别异常)
@SuppressWarnings("serial")
public class GenderException extends Exception{
    public GenderException() {
        super("性别只能设置为男或者女");
    }
    /*public GenderException(String message) {
        super(message);
    }*/
    @Override
    public String getMessage() {
        return super.getMessage();
    }
}

测试:
学生


public class Student {
    private String name;
    private int age;
    private String  gender;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getGender() {
        return gender;
    }
    public void setGender(String gender) throws GenderException {
        if(gender.equals("男") || gender.equals("女")){
            this.gender = gender;
        }else{
            throw new GenderException();
        }
    }

}

测试类:

/**
 * 自定义异常
 * 自定义异常类   extends  Exception{
 * }
 * 自定义异常类   extends  RuntimeException{
 * }
 * 
 * @author Administrator
 *
 */
public class Test1 {

    public static void main(String[] args) {
        Student student = new Student();
        try {
            student.setGender("不男不女");
        } catch (GenderException e) {
            System.out.println(e.getMessage());
            System.out.println(e.getLocalizedMessage());
        }
    }

}
异常链

使用场合举例
在分层结构中,将底层原始异常直接传递给用户是一种不负责的表现
对于普通用户,底层异常专业性强,不友好,对他们没有什么帮助
对于恶意用户,可以利用抛出的异常信息作为破坏的线索

解决方案:异常转译
使用catch块捕获异常,并throw一个新的更友好的业务异常
可以保证底层的异常信息不扩散到用户界面,避免暴露更多的实现细节

异常转译也称为异常链

  • 需求:
    • 输入被除数、除数、求商,并打印结果
    • 问题1:输入类型不匹配的时候,直接抛出异常( java.util.InputMismatchException)
    • 提示问题过于专业
    • 问题2:0不能作为除数( java.lang.ArithmeticException: / by zero)
    • 提示专业

      • v1.3 使用异常解决问题,多个catch

      • 多个catch之间有顺序要求: 子类在前,父类在后
    • 一个catch可以存在多个异常 InputMismatchException | IndexOutOfBoundsException e
public class TestException4 {

    public static void main(String[] args) {
        int a,b,c = 0;//a:被除数  b:除数  c:商
        Scanner scanner = new Scanner(System.in);
        try {
            System.out.println("请输入被除数");
            a = scanner.nextInt();
            System.out.println("请输入除数");
            b = scanner.nextInt();
            //求商
            c = a / b;
            System.out.println("商为:"+c);
        }catch (ArithmeticException e) {
            System.out.println("0不能做除数");   
            //终止虚拟机(finally中的代码,不会被执行)
            //System.exit(1);
            return;
        }
        catch (InputMismatchException | IndexOutOfBoundsException e) {
            System.out.println("输入类型不匹配");
            return;
        } 
        catch (Exception e) {
            System.out.println("其他异常");
            System.out.println(e.getMessage());//获取错误信息
            return;
        }finally {
            //finally中  扫描器的关闭,流的关闭,数据的关闭,socket的关闭
            scanner.close();    
            System.out.println("谢谢使用");
            //在方法结束前执行
        }
    }
}

小结

异常类型
一张图

异常处理
五个关键字(try, catch, finally, throws, throw)
先逮小的,再逮大的
自定义异常

注意
try-finally也可以呀
遇到了return和throw还会执行finally语句;遇到System.exit()就不会执行finally语句了
throw了运行时异常,则方法声明中不需要throws

如果在编程中写的东西有异常,1,可以用try catch 捕获异常,弹出友好提示
2,可以把异常抛出,也就是用throws声明,throw抛出,不处理,告诉别人这个方法有异常,让别人用的时候处理。

编码题:
1、编写程序接收用户输入分数信息,如果分数在0—100之间,输出成绩。如果成绩不在该范围内,抛出异常信息,提示分数必须在0—100之间。
要求:使用自定义异常实现

/**
 * 分数范围异常类型
 * @author Administrator
 *
 */
public class ScoreScopeException extends RuntimeException{
    public ScoreScopeException() {
        super();
    }
    public ScoreScopeException(String message) {
        super(message);
    }   
}

import java.util.Scanner;
public class Test {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        try {
            System.out.print("请输入分数:");
            int score = scanner.nextInt();
            if (score < 0 || score > 100) {
                throw new ScoreScopeException("分数必须在0-100之间");
            }
            System.out.println("分数为:" + score);
        } catch (ScoreScopeException e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
    }
}

2、写一个方法void isTriangle(int a,int b,int c),判断三个参数是否能构成一个三角形, 如果不能则抛出异常IllegalArgumentException,显示异常信息 “a,b,c不能构成三角形”,如果可以构成则显示三角形三个边长,在主方法中得到命令行输入的三个整数, 调用此方法,并捕获异常。

public class Test {
    public static void main(String[] args) {
        //输入三条边
        System.out.println("请输入三条边长");
        Scanner reader = new Scanner(System.in);
        int a = reader.nextInt();
        int b = reader.nextInt();
        int c = reader.nextInt();
        //判断是否是三角形
        isTriangle(a, b, c);
    }
    private static void isTriangle(int a, int b, int c) {
        //三条边都不能是负数
        if (a < 0 || b < 0 || c < 0) {
            throw new IllegalArgumentException("三条边不能是负数");
        }
        //判断是否构成三角形
        if (a + b > c && a + c > b && b + c > a) {
System.out.println("三角形的边长分别为" + "a=" + a + " " + 
"b=" + b + " "  + "c=" + " " + c);
        } else {
            throw new IllegalArgumentException(a + "," + b + "," + c
                    + "不能构成三角形!");
        }
    }
}       
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值