Java笔记07——异常

什么是异常?

java
什么是异常?java提供异常程序有什么用?
以下程序执行过程中出现了不正常情况,而这种不正常情况叫做异常
java是很完善的语言,提供了异常的处理方式,程序执行过程中出现了不正常情况,
java把信息打印到控制台上,程序员看到了可以修改

什么是异常? 程序运行中不正常的情况
java提供的异常程序有什么用? 增加程序的茁壮性

java中异常以什么方式存在呢?
异常在java中以类和对象的形式存在,每一个异常类都可以创建异常对象

UML图

什么是UML?有什么用?

UML是一种统一建模语言。

一种图标式的语言(画图的)。只要是面向对象的编程语言,都有UML。

一般画UML图的都是软件架构师或者说是系统分析师这些级别的人使用的,软件设计人员使用UML

在UML图中可以描述类和类之间的关系,程序执行的流程,对象的状态等。

在java软件开发当中,软件分析书/设计师设计好了软件

异常继承图

Object

Object下有两个分支:

  • Error(不可处理,直接退出JVM)和
  • Exception(可处理的)

Exception下有两个分支:

  • Exception的直接子类:编译时异常(要求程序员在编写程序阶段必须 预先对这些一场进行处理,如果不处理编译器报错,因此得名编译时异常)
  • RuntimeException:运行时异常(在编写程序阶段程序员可以须预先处理,也可以先不管,都行)

异常的分类

  1. 编译时异常和运行时异常,都是在发生在运行阶段,编译阶段异常是不会发生的,编译时异常因为什么而得名?
    因为编译时异常必须在编译(编写)阶段预先处理,如果不处理编译器报错,因此得名。所有异常都是在运行阶段发生的。因为只有程序运行阶段才可以new对象

  2. 编译时异常和运行时异常的区别?

    编译时异常一般发生的概率比较高

    运行时异常一般发生的概率比较低

对于一些发生率较高的异常,需要在运行之前对他进行预处理

在这里插入图片描述

  1. 假设java中没有对异常进行划分,没有分为编译时异常和运行时异常,假设所有异常都需要在编写程序阶段对其进行预处理,将是怎样的效果?

​ 这样写的话,程序将会绝对的安全,但是是程序员会十分累,代 码到处都是处理异常的代码

  1. 编译时异常又被称为受检异常,还有叫做受控异常

  2. 运行时异常又被称作未受检异常,还有叫做未受控异常

  3. 再次强调:所以一场都是发生在运行阶段的

  4. Java语言中对异常的处理包括两种方式:

    • 第一种:在方法声明的位置上,使用throws关键字(抛给上一级) 谁调用我,我就抛给谁,抛给上一级

    • 第二种:使用try…catch语句进行异常的捕捉

      这件事发生了,谁也不知道,因为我给抓住了

    思考:

    异常发生之后,如果我选择了上抛,跑黑了我的调用者,调用者需要对这个异常继续处理,那么调用者处理这个异常同样有两种方式。

  5. Java如果异常发生之后一直上抛,最终抛给了main方法main方法继续向上抛,抛给了调用者JVM,JVM知道了这个异常发生,只有一个结果,终止java程序的执行

public static void main(String[] args) {
   /*
   程序执行到此处抛出了ArithmeticException异常
   底层new出了一个ArithmeticException异常对象
   然后跑出了,由于是main方法调用了100/0,
   所以这个异常ArithmeticException抛给了main方法,
   main方法没有处理,自动将这个异常抛给了JVM
   JVm最终终止了程序的执行
    */

    /*
    ArithmeticException异常继承RuntimeException,属于运行时异常,
    在编写程序阶段不需要对这种异常进行预先处理
     */
    System.out.println(100/0);
    //HelloWorld没有执行
    System.out.println("HelloWorld");
}

代码:(重点,仔细看

public static void main(String[] args) {
   /*
   main方法中使用doSome()方法
   因为doSome()方法的声明位置上有:throws ClassNotFoundException
   所以我们在调用这个方法的时候必须对这种异常进行预先的处理
   如果不处理,编译器就报错
   编译器报错的信息:Unhandled exception: java.lang.ClassNotFoundException
    */
    doSome();
}

/**
 * doSome方法在方法声明的位置上使用了 throws ClassNotFoundException
 * 这个代码表示doSome()方法在执行过程中,可能会抛出ClassNotFoundException异常。
 * 叫做类没有找到异常,这个异常的直接父类是:Exceptio,所以ClassNotFoundException属于编辑时异常
 * @throws ClassNotFoundException
 */
public static void doSome() throws ClassNotFoundException{

}
  • 处理异常的第一种方式:

    在方法声明位置上使用throws关键字抛出,谁调用这个方法,我就跑给谁。跑给调用者来处理。

  • 处理异常的第二种方式:

    使用try…catch语句对异常进行捕捉

    这个异常不会上报,自己把这个事儿给处理了

    异常抛到此处为止,不会再上抛了

  • 一般不建议在main方法上使用throws,因为这个异常如果真正发生了,一定会抛给JVM,JVM只有终止。

  • 异常处理机制的作用就是增强程序的奖状行。怎么能做到,异常发生了也不影响他的执行,所以一般main方法中的异常建议使用try…catch进行捕捉,就不要再上抛了。

try…catch

只要异常没有捕捉,采用上报的方式,此方法的后续代码不会执行,另外要注意,try语句块中的某一行出现异常,该行后面的代码不会执行,try…catch代码捕捉之后,后面的代码可以执行

一个方法体当中的代码出现异常后,如果上报的话,此方法结束。

在以后的开发中处理编译时异常,应该上报还是捕捉呢,怎么选?

如果希望调用者来处理,选择throws上报

/*深入try ... catch
*  1.catch小括号里面可以写具体的异常类型,也可以写父类型
* 2.catch可以写多个.建议catch的时候,精确的一个一个处理,这样有利于程序的调试
* 3.catch写多个的时候,从上到下,必须遵守从小到大.
* 4.catch里面可以使用或,
* */
public class Test04 {
    public static void main(String[] args) {
      /*  try {
            FileInputStream fls = new FileInputStream("C:\\Users\\14505\\Desktop\\1.txt");
            System.out.println("以上出现问题,不执行");
        } catch (FileNotFoundException e) {
            System.out.println("文件不存在");
        }*/
        try {
            FileInputStream fls = new FileInputStream("C:\\Users\\14505\\Desktop\\1.txt");
            System.out.println("以上出现问题,不执行");
        } catch (Exception e) {//多态:Exception e = new FileNotFoundException ;
            System.out.println("文件不存在");
        }
    }

异常常用的两个方法

  1. String msg = new exception.getMessage();

  2. exception.printStackTrace();

/*
异常对象有两个非常重要的方法:
            获取异常简单的描述信息:
  String msg = new exception.getMessage();
            打印异常追踪的堆栈信息:
       exception.printStackTrace();
 */
public class Test05 {
    public static void main(String[] args) {
        //这里只是测试getMessage()方法和printStackTrace()方法
        //这里只是new了异常对象,但是没有将异常对象抛出,JVM会认为这只是一个普通的java对象
        NullPointerException e = new NullPointerException("空指针异常");
        //获取异常简单描述信息:这个信息实际上就是构造方法上面String方法参数
       String s =  e.getMessage();
        System.out.println(s);

        e.printStackTrace();//打印异常堆栈信息
        System.out.println("HelloWorld");
    }
}

使用exception.printStackTrace();打印出的异常的信息,我们应该怎样看才能快速调试?

异常信息追踪信息:从上往下一行一行的看

需要注意的是:SUN公司给的信息就不用看了(看包名就知道是自己的还是SUN公司的)。主要的问题出现在自己的代码上

在实际开发中,catch中要加上e.printStackTrace();,不然出问题也不知道

finally语句

关于try…catch中的finally子句:

  1. 在finally子句中的代码是最后执行的,并且是一定会执行的,即使try语句块中出现了异常。且finally子句必须与try一起出现,不能单独编写。

  2. finally语句通常使用在哪些情况下呢?

    通常finally语句块中完成资源的释放/关闭

    因为finally中的代码比较有保障

    即使try语句中的代码出现异常,finally中的代码也会正常执行

    try{
        return;
    }finally{
        //finally中的语句会执行,能够执行到
    }
    //这里的语句无法执行到,不能写
    

    以上代码执行顺序:

    ​ 先执行finally

    ​ 在执行finally

    ​ 最后执行return(return语句只要执行,方法必然结束)

    一旦推出JVM就不会执行了

    面试题代码:

    public static void main(String[] args) {
        System.out.println(test());
    }
    /*
    java语法规则(有一些规则是不能破坏的,一旦这么说了,就必须这么做)
           java中有一条这样的语法规则:
                方法体中用的代码必须遵循自上而下的顺序依次执行
           java中另一条语法规则:
                return语句一旦执行,整个方法必须结束
     */
    public static int test(){
        int i =100;
       try {
           //这条代码出现在int i=100下面,所以最终结果必须是返回100
           //return语句必须保证是最后执行的。一旦执行,整个方法必然结束
           return i;
       }finally {
           i++;
       }
    }
    

final、finally、finalize()有什么区别?

  • final是一个关键字,表示最终的,不变的

    final修饰的类无法继承,final修饰的方法无法覆盖

  • finally也是一个关键字,和try联合使用,使用在异常处理机制中

    finally语句块中的代码是必须执行的

  • finalize()是Object中的一个方法,作为方法名出现,所以finalize是标识符,这个方法由垃圾回收器调用

自定义异常

定义:

/*
1.SUN公司提供的异常肯定是不够用的,在实际的开发中有很多业务,这些业务出现异常后,
JDK中都是没有的,和业务挂钩的。那么异常类我们程序员可以自定义吗?
        可以

2.Java中怎样自定义类呢?
      两步:
            第一步:编写一个类继承Exception或者RuntimeException。
            第二部:提供两个构造方法,一个无参数的,一个有参数的。
      死记硬背
 */
public class Test07 extends Exception{//编译时异常
public Test07(){

}
public Test07(String s){
    super(s);
}
}

使用:

public static void main(String[] args) {
    //创建异常对象
    Test07 e= new Test07("用户名不能为空");
    //打印异常堆栈信息
    e.printStackTrace();
    //获取简单描述信息
    System.out.println(e.getMessage());
}

PS:用throw可以抛出异常

重写之后的方法不能比重写之前的方法抛出更多(更宽泛)的异常,可以更少。

总结异常中的关键字:

  • try

  • catch

  • finally

  • throws 在方法生命位置上使用,表示上报异常信息给调用者

  • throw 手动抛出异常!

异常作业

在这里插入图片描述

首先定义一个异常类:

public class MyException extends Exception {
    public MyException(){}
    public MyException(String s){
        super(s);
    }
}

用户名信息类:

public class UserService {
    public static void get(String userName) throws MyException {
        /*
        userName==null不如写成 null==userName   ,免得手欠少写一个=
         */
        if(userName==null||userName.length()<6||userName.length()>14||userName==null){
             throw new MyException("用户名长度不符");
        }
        //程序能够执行到此处,说明用户名合法
        System.out.println("欢迎"+userName);
    }
}

最后测试类:

public class Application {
    public static void main(String[] args) {
        UserService u = new UserService();
        Scanner s = new Scanner(System.in);
        System.out.println("请输入用户名");
        String userName= s.next();
        try {
             u.get(userName);   //这里可能会产生异常
            System.out.println("请输入密码");
            String userPassword= s.next();
            System.out.println("注册成功!");
            System.out.println(userName.length());
        } catch (MyException e) {
            System.out.println(e.getMessage());
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值