Java学习day19-异常

今日目标

  • 了解异常
  • 捕获异常
  • 自定义异常

一. 什么是异常

异常机制:

​ 异常机制是指当程序出现错误后,程序如何处理。具体来说,异常机制提供了程序退出的安全通道。当出现错误后,程序执行的流程发生改变,程序的控制权转移到异常处理器。

通俗地说:为了让程序继续执行下去,而不至于中断。

程序错误:

​ 程序错误分为三种:1.编译错误;2.运行时错误;3.逻辑错误。
(1)编译错误:是因为程序没有遵循语法规则,编译程序能够自己发现并且提示我们错误的原因和位置。
(2)运行时错误:是因为程序在执行时,运行环境发现了不能执行的操作。
(3)逻辑错误:是因为程序没有按照预期的逻辑顺序执行。

异常也就是指程序运行时发生错误,而异常处理就是对这些错误进行处理和控制。

虚拟机对异常的两种处理方式

  1. 捕获异常

  2. 抛出异常

1.1.异常结构

在这里插入图片描述

1.2.异常收集
序号异常名称异常描述
1java.lang.NullPointerException空指针异常:对象为空,并且调用相应方法。
2java.lang.ClassNotFoundException找不到指定类,常出现在反射中
3java.lang.ArrayIndexOutOfBoundsException数组下标越界
4java.lang.NumberFormatException:数字格式化异常
5java.lang.ArithmeticException:数学运算异常
6java.lang.StackOverflowError内存空间溢出错误,方法递归调用中,经常发生
7java.lang.ClassCastException类型转换异常,向下转型中经常发生
8java.text.ParseException时间格式化异常,SimpleDateFormart中经常发生
9java.util.InputMismatchException输入类型不匹配异常

二.捕获异常

1.try-catch
try:尝试着执行可能会出现异常的代码
catch:如果try中的代码在执行过程中,出现了异常,捕获该异常,如果没有异常,就不执行。
public static void main(String[] args) {
        int c=0;
        try{
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入第1个数字:");
            int a = sc.nextInt();
            System.out.println("请输入第2个数字:");
            int b = sc.nextInt();
            c=a/b;
            c=66;
        }catch (Exception e){
            e.printStackTrace();//如果注释这句话则不会出现下方红色的字体
            System.out.println("出现了异常");
        }
        System.out.println(c);
    }

在这里插入图片描述
在这里插入图片描述

  • 引入案例
使用Scanner录入5名学员的成绩,当输入第2名学员的成绩时,输入的不是数字,此时会出现异常,使用try-catch捕获该异常,并在catch中输出提示信息,从而不让程序中断,可以继续录入后续学员成绩。
//异常收集
public class ExceptionColl {
    @Test
    public void test4(){
        for (int i = 0; i < 5; i++) {
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入第"+i+"个学员的成绩:");
            try{

                double score = sc.nextDouble();
                //break;//结束循环
                //return;//结束方法
                //System.exit(0);//整个程序终止执行,可以防止finally执行

            }catch (Exception e){
                //e.printStackTrace();
                System.exit(0);//整个程序终止执行,可以防止finally执行
                System.out.println("出现异常");
            }finally {
                System.err.println("finally代码块,最终都会执行,不管是否有异常");
            }
        }
    }
    /*使用Scanner录入5名学员的成绩,当输入第2名学员的成绩时,
    输入的不是数字,此时会出现异常,使用try-catch捕获该异常,并在catch中输出提示信息,
    从而不让程序中断,可以继续录入后续学员成绩。*/
    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入第"+i+"个学员的成绩:");
            try{
                double score = sc.nextDouble();
            }catch (InputMismatchException e1){
                e1.printStackTrace();
                System.out.println("输入不匹配异常");
            }catch (Exception e2){

                e2.printStackTrace();
            }
        }

        System.out.println("输入结束");
    }
    @Test
    public void test3(){
        Scanner sc = new Scanner(System.in);
        for (int i = 0; i < 5; i++) {
            System.out.println("请输入第"+i+"个学员的成绩:");
            try{
                double score = sc.nextDouble();
            }catch (InputMismatchException e){
                System.out.println("输入不匹配异常");
            }catch (NullPointerException e){
                System.out.println("空指针异常");
            }catch (Exception e){
                System.out.println("异常的爷爷");
            }
        }

        System.out.println("输入结束");
    }
    @Test //内存溢出错误 OutOfMemoryError: Java heap space
    public void test1(){
        ArrayList list = new ArrayList();
        list.add("貂蝉");
        for (int i = 0; i < list.size(); i++) {
            list.add("吕布");
        }
    }
    @Test //堆栈溢出错误 StackOverflowError
    public void test2(){
        test2();
    }

}
  • 单个try-catch
try{
    
}catch(){
    
}
  • 多个catch
try{
    
}catch(){
    
}catch(){
    
}
//多个catch在捕获异常时,子类异常catch块在前面,父类异常catch块在后面
2.try-catch-finally
try{
    
}catch(){
    
}finally{
    //通常用来释放资源
}

break,return,System.exit(1)语句在异常处理中的作用

3.深入认识异常
  • java中的小括号中可以写什么
1.判断条件 if() while()
2.形参列表 方法声明时
3.传递实参 方法调用时
4.异常捕获声明 catch(异常类 e)
5.强制类型转换或向下转型
  • 在出现异常时,谁给e实例化的呢?
思考:
如果让你来设计java,程序出错了之后,如何让程序员知晓呢,有效的表述方式是什么呢?

java的异常机制:
1.建立大量的用于表述某种异常的类,组成一个以Throwable为首的异常家族。
2.当程序执行出现异常时,立即创建相应异常类的对象。
3.使用catch(异常类型 e)捕获创建的异常对象。

三.声明和抛出异常

1.使用throws声明异常

​ 运用于方法声明之上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常

//声明--暂时先不捕获,留给调用者
public void fun1() throws ParseException {
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    Date date = format.parse("2020-10-12");
}

或者

  //捕获
    public void fun1()  {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            Date date = format.parse("2020-10-12 00:00:00");
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
2.使用throw抛出异常

主动抛出一个异常,一定要处理吗?-- 运行时异常(继承RuntimeException),不用处理。非运行时异常(直接继承Exception),必须要处理

  private static void fun3()  {
       throw new NullPointerException();
    }

​ throw用在方法内,用来抛出一个异常对象,将这个异常对象传递到调用者处,并结束当前方法的执行。

public void fun2() {
     throw new NullPointerException("空指针异常");  
     System.out.println("hello world");//会报红,提示unreachable statement,该语句不可能被执行
}
  • 扩展1–嵌套try-catch
@Test
public void fun2()  {
    try {
        throw new Exception("非运行时异常,哈哈哈");
    } catch (Exception e) {
        e.printStackTrace();
        try {
            throw new ParseException("解析异常,哈哈哈",0);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }finally {
        try {
            throw new TimeoutException("超时异常,哈哈哈");
        } catch (TimeoutException e) {
            e.printStackTrace();
            try {
                throw new SQLException("SQL异常");
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }
    }
}
  • 扩展2–代替返回语句
public int  funR1(){
        try {
            return 1;
        }catch (Exception e){
           throw new RuntimeException();
        }
    }
public int  funR2(){
    if(true) {
        return 1;
    }else{
        throw new RuntimeException();
    }
}

四.自定义异常

​ JDK中定义了大量的异常类,可以描述编程时出现的大部分异常情况,但对于一些特殊情景下的异常,我们可以自己去定义。

创建步骤:

  • 创建一个异常类
  • 加入异常家族中(继承某个异常父类)
public class HeroNotExistException extends RuntimeException {
   private String m;

   public String getM() {
       return m;
   }

   public void setM(String m) {
       this.m = m;
   }
//两个参数的有参构造,一个传递给父类Throwable,一个自己用
   public HeroNotExistException(String message, String m){
      super(message);
      this.m=m;
   }

   public static void main(String[] args) {
       Scanner sc=new Scanner(System.in);
       System.out.println("请输入您最欣赏的历史人物:");
       String name = sc.next();
       if(name.equals("孙悟空")){
           try{
               throw new HeroNotExistException("英雄人物不存在","哈哈");
           }catch (HeroNotExistException e){
               e.printStackTrace();
               System.out.println(e.getM());
           }
       }
   }
   
}

总结

1、java中异常分为两大类:
   checked exception (非运行时异常)
   unchecked exception (运行时异常)

2、java中所有的异常类都会直接或间接地继承自Exception。

3、RuntimeException类也是直接继承Exception类,它叫运行时异常,换句话说:java中所有的运行时异常都会直接或间接继承自RuntimeException。

4、java中凡是继承自Exception而不是继承自RuntimeException的类都是非运行时异常。对于非运行时异常,必须要对其进行处理,处理方式有两种:
   使用try...catch捕获处理
   在所在方法声明 throws Exception
   
5、对于运行时异常,我们可以不对其处理,推荐不对其处理

6、空指针异常,出现该异常时原因市在于某个引用为null,但是还使用它调用方法。

7、自定义异常,通常就是定义了一个继承自Exception类的子类,那么这个类就是一个自定义异常类。通常情况下,我们都会直接继承自Exception,一般不会继承某个运行时异常类。

8、我们可以使用多个catch块来捕获异常,这时需要将父类型catch块放到子类型catch之后,这样才能保证后续的catch可能被执行,否则子类型的catch将永远无法到达,java编译器会编译报错。

11、如果try块中存在return语句,那么首先也需要将finally块中的代码执行完毕,然后方法再返回。

12、如果try块中存在System.exit(0),会终止当前运行的java虚拟机,程序会强制性结束执行。

作业

1.向一个长度为5的整型数组中,使用死循环不断录入整数,当出现数组下标越界异常时,使用try-catch精准捕获该异常,输出数组已满的提示,并跳出循环,在循环外输出:数据录入结束。

2.在person类中,年龄的范围是0-120岁,性别只能是男或女。自定义年龄异常类和性别异常类,输出相应异常提示信息。编写测试类,给人物的年龄和性别赋值,如果不符合要求,抛出自定义异常类的异常提示信息。

public class SexException extends Exception{
    public SexException() {
    }

    public SexException(String message) {
        super(message);
    }
}
public class AgeException extends Exception {
    public AgeException() {
    }

    public AgeException(String message) {
        super(message);
    }
}
public class Person {
    private int age;
    private String sex;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if (age>=0&&age<=120){
            this.age = age;
        }else {
            try {
                throw new AgeException("年龄超出范围");
            } catch (AgeException e) {
                System.out.println(e.getMessage());
                e.printStackTrace();
            }
        }
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
       if (sex.equals("男")||sex.equals("女")){
           this.sex = sex;
       }else {
           try {
               throw new SexException("输入不正确");
           } catch (SexException e) {
               System.out.println(e.getMessage());
               e.printStackTrace();
           }
       }

    }
}
public class TestPerson {
    public static void main(String[] args) {
        Person p = new Person();
        //p.setAge(130);
        p.setSex("中");
    }
}

在这里插入图片描述

在这里插入图片描述

3.定义一个信用卡类(账户,额度),定义一个People类,属性有:姓名,年龄,信用卡;方法有:刷信用卡。在测试类中实现:杨光,22岁,有一张信用卡,账户:123456789000 额度:2000 。 他现在想刷信用卡给女朋友买一个包包,价值3000. 自定义异常, 当额度超支时,抛出提示“信用额度不足,请理性消费!”。

public class CardOutOfLimitException extends Exception {
    public CardOutOfLimitException(String s){
        super(s);
    }
}
public class CredictCard {
    private String id;
    private double limit;
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public double getLimit() {
        return limit;
    }
    public void setLimit(double limit) {
        this.limit = limit;
    }
}
public class People {
    private String name;
    private int age;
    private CredictCard  card;

    public void cusume(double m){
        if(m<this.card.getLimit()){
            this.card.setLimit(this.card.getLimit()-m);
        }else {
            try {
                throw new CardOutOfLimitException("信用卡额度超支,请理性消费!");
            } catch (CardOutOfLimitException e) {
                e.printStackTrace();
                System.out.println(e.getMessage());
            }
        }
    }
    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 CredictCard getCard() {
        return card;
    }

    public void setCard(CredictCard card) {
        this.card = card;
    }
}
public class TestCard {
    public static void main(String[] args) {
        People p = new People();
        p.setName("海哥");
        p.setAge(22);
        CredictCard c = new CredictCard();
        c.setId("666888");
        c.setLimit(2000);
        p.setCard(c);//关联人物

        p.cusume(3000);

    }
}

在这里插入图片描述
Java学习顺序

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值