今天复习一下异常

1 异常的概述和分类
     异常的概述  ( 异常就是Java程序在运行过程中出现的错误)
 异常的继承体系
     Throwable
          Error ( 服务器宕机,数据库崩溃等 比较严重的错误,不在本次学习范围内)
          Exception (重点 )
                RuntimeException (重点 运行时异常)

2 JVM默认是如何处理异常的
     main函数收到这个问题时,有两种处理方式:
     a:自己将该问题处理,然后继续运行
     b:自己没有针对的处理方式,只有交给调用main的jvm来处理
     jvm有一个默认的异常处理机制,就将该异常进行处理.
     并将该异常的名称,异常的信息.异常出现的位置打印在了控制台上,同时将程序停止运行
2.1 小实例

public class Damo1 {
    public static void main(String[] args) {
        //调用除数方法将返回结果给x 出现异常 x处理不了 上抛异常交给调用main的jvm处理 jvm处理该异常 并将异常信息打印在控制台 程序停止运行
        int x = div(10, 0);
        System.out.println(x);
    }
    public static int div(int a,int b) {      //a = 10,b = 0
        //被除数是10,除数是0 当除数是0的时候违背了算数运算法则,抛出异常返回new ArithmeticException("/ by zero");
        return a / b;

    }
}

3 处理异常的基本格式  (  try…catch…finally)
        try:用来检测异常的
        catch:用来捕获异常的
        finally:不管有没有异常都会执行 通常用来释放资源
        当通过tryc atch将问题处理了,程序会继续执行

3.1 注意事项

    try后面如果跟多个catch,那么小的异常放前面,大的异常放后面,根据多态的原理如果大的放前面,就会将所有的子类对象接收后面的catch就没有意义了

3.2 jdk7 新特性

 try{}  catch (ArithmeticException | ArrayIndexOutOfBoundsException e) {}可用这种语法在一个catch里写入多个异常  

     不过开发不常用这种语法 通常直接一个try{} catch (Exception e){} 捕获多个异常

3.3 异常处理小实例

public class Damo2 {
    public static void main(String[] args) {
        try {
            int x = 10/0; // 1 将计算结果给x出现异常 x处理不了 上抛异常被catch捕获
            System.out.println(x);
        } catch (ArithmeticException a) { // 2 捕获异常 ArithmeticException a = new ArithmeticException();
            System.out.println("捕获异常");
        }
        finally { // 3 finally不管有没有捕获异常都会执行
            System.out.println("执行最终finally");
        }
    }
}

4 编译期异常和运行期异常的区别
     Java中的异常被分为两大类:编译时异常和运行时异常。
     所有的RuntimeException类及其子类的实例被称为运行时异常,其他的异常就是编译时异常

     运行时异常
         就是程序员所犯得错误,需要回来修改代码  无需显示处理,但也可以和编译时异常一样处理
     编译时异常
         在编译某个程序的时候,有可能会有这样那样的事情发生,比如文件找不到,这样的异常就必须在编译的时候处理 如果不处理编译通不过
  

4.1 常见编译时异常 (XXXX.text 这个文件很有可能是不存在的 所以需要处理这个异常)

public static void main(String[] args) {
    FileInputStream fis = new FileInputStream("XXXX.text");
}

4.1.1 处理方式

public static void main(String[] args) {
    try {
        FileInputStream fis = new FileInputStream("XXXX.text");
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
}

5 异常Throwable的几个常见方法
Throwable的几个常见方法
    getMessage()  获取异常信息,返回字符串。
    toString()  获取异常类名和异常信息,返回字符串。
    printStackTrace() 获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void。
5.1 Throwable的几个常见方法的基本使用

public class Damo4 {
    public static void main(String[] args) {
        try {
            System.out.println(1/0);
        } catch (Exception e) { //捕获异常 Exception e = new ArithmeticException("/ by zero");
            System.out.println(e.getMessage()); //获取异常信息
            System.out.println("==============");
            System.out.println(e); //默认自动调用toString方法,打印异常类名和异常信息
            System.out.println("==============");
            e.printStackTrace(); //获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void jvm默认使用这种方式处理异常
        }
    }
}

6 throws的方式处理异常
     定义功能方法时,需要把出现的问题暴露出来让调用者去处理 那么就通过throws在方法上标识。

6.1 throws和throw的区别
   throws
        用在方法声明后面,跟的是异常类名
        可以跟多个异常类名,用逗号隔开
        表示抛出异常,由该方法的调用者来处理
   throw
        用在方法体内,跟的是异常对象名
        只能抛出一个异常对象名
        表示抛出异常,由方法体内的语句处理
6.2  举例分别演示编译时异常和运行时异常的抛出 ( 编译时异常的抛出必须对其进行处理 运行时异常的抛出可以处理也可以不处理,因为这是逻辑错误,需要修改代码的)

编译时异常抛出

public class Damo5 {
    public static void main(String[] args) throws Exception { // 3 继续上抛异常交给jvm处理
    Person p = new Person();
    p.setAge(-11); // 因Person类的setAge()方法声明并上抛异常 所以这里main方法要继续上抛异常
    }
}
class Person{
    private String name;
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) throws Exception { // 2 上抛异常
        if(age >0 && age <= 150) {
            this.age = age;
        }else {
            throw new Exception("年龄非法"); // 1 声明异常

        }
    }
}

运行时异常的抛出

public class Damo5 {
    public static void main(String[] args)  {
    Person p = new Person();
    p.setAge(-11);
    }
}
class Person{
    private String name;
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) { 
        if(age >0 && age <= 150) {
            this.age = age;
        }else {
            // 方法中抛出一个运行时异常 方法上不用做处理
            throw new RuntimeException("年龄非法");
        }
    }
}

7 finally关键字的特点及作用
finally的特点
     被finally控制的语句体一定会执行
     特殊情况:在执行到finally之前jvm退出了(比如System.exit(0))
finally的作用
    用于释放资源,在IO流操作和数据库操作中会见到
    finally关键字小实例

public class Damo6 {
    public static void main(String[] args) {
        try {
            System.out.println(10 / 0);
        } catch (Exception e) {
            System.out.println("除数为零了");
            //System.exit(0);      //提前退出jvm虚拟机那么finally语句块不会执行
            //return语句相当于是方法结束时的最后一口气,那么在它即将结束之前会看一看有没有finally帮其完成遗愿,如果有就将finally执后在彻底返回
            return;
        } finally {
            System.out.println("看看我执行了吗");
        }
    }
}

常见面试题题
           7.1 final,finally和finalize的区别
             final 可以修饰类,不能被继承 修饰方法,不能被重写修饰变量,只能赋值一次
           
             finally 是try语句中的一个语句体,不能单独使用,用来释放资源
           
             finalize 是一个方法,当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。

          7.2 如果catch里面有return语句,请问finally的代码还会执行吗?如果会,请问是在return前还是return后。

         答: finally会执行,在return前。 return会先建立返回路径,然后去执行finally语句块的内容,最后再彻底返回

小练习

public class Damo7 {
    // 测试 x 的值
    public static void main(String[] args) {
        Demo d = new Demo();
        System.out.println(d.method());// 输出30
    }

}
class Demo {
    public int method() {
        int x = 10; // 1 x =10
        try {
            x = 20; // 2 x = 20
            System.out.println(1 / 0); // 3 发现异常 被catch捕获
            return x;
        } catch (Exception e) {
            x = 30; // 4 x = 30
            return x; // 5 建立返回路径 将x=30暂时存起来 查看finally语句块后 将暂存内容返回
        } finally {
            x = 40; // 6 虽然这里对 x 进行了赋值 可是catch只会返回暂存的内容所以这句话是没有意义的
            //return x;    千万不要在finally里面写返回语句,因为finally的作用是为了释放资源,是肯定会执行的
            //如果在这里面写返回语句,那么try和catch的结果都会被改变,所以这么写就是犯罪
        }
    }
}

8 自定义异常

       为什么需要自定义异常( 通过名字区分到底是什么异常,有针对的解决办法,有利于我们排错)
8.1 小实例 自定义Exception 异常类 继承Exception

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

    // 重写构造方法 可以传入指定的异常信息
    // message 异常信息是Throwable类的字符串变量detailMessage
    //当调用getMessage()方法时 返回的就是字符串变量detailMessage
    public AgeOutOfBoundsException(String message) {
        super(message);
    }

}

使用自定义异常AgeOutOfBoundsException

public class Damo5 {
    public static void main(String[] args) throws AgeOutOfBoundsException { //上抛异常 jvm做处理
    Person p = new Person();
    p.setAge(-11); //因为Person类的setAge()方法抛出了一个异常 所以这里要处理 我们选择main方法继续上抛
    }
}
class Person{
    private String name;
    private int age;
    public void setAge(int age) throws AgeOutOfBoundsException { //上抛异常
        if(age >0 && age <= 150) {
            this.age = age;
        }else {
            // 使用自定义异常AgeOutOfBoundsException() 异常方法中抛出Exception编译时异常 方法要进行处理
            throw new AgeOutOfBoundsException("年龄非法");
        }
    }
}

8.2 小实例 自定义RuntimeException 异常类 继承自RuntimeException 

public class AgeOutOfBoundsException extends RuntimeException  {
    public AgeOutOfBoundsException() {
    }
    // 重写构造方法 可以传入指定的异常信息
    // message异常信息是Throwable类的字符串变量detailMessage
    //当调用getMessage()方法时 返回的就是字符串变量detailMessage
    public AgeOutOfBoundsException(String message) {
        super(message);
    }
}

使用自定义异常AgeOutOfBoundsException (因为是RuntimeException  所以不用 throws 抛出异常也可以)

public class Damo5 {
    public static void main(String[] args) {
    Person p = new Person();
    p.setAge(-11);
    }
}
class Person{
    private String name;
    private int age;
    public void setAge(int age) {
        if(age >0 && age <= 150) {
            this.age = age;
        }else {
            // 方法中抛出一个运行时异常 方法上不用做处理
            throw new AgeOutOfBoundsException("年龄非法");
        }
    }
}

9 异常注意事项
   子类重写父类方法时,子类的方法必须抛出相同的异常或父类异常的子类。(父亲坏了,儿子不能比父亲更坏)
    如果父类抛出了多个异常,子类重写父类时,只能抛出相同的异常或者是他的子集,子类不能抛出父类没有的异常
    如果被重写的方法没有异常抛出,那么子类的方法绝对不可以抛出异常,如果子类方法内有异常发生,那么子类只能try,不能throws
如何使用异常处理
     原则:如果该功能内部可以将问题处理,用try,如果处理不了,交由调用者处理,这是用throws
     区别:
        后续程序需要继续运行就try
         后续程序不需要继续运行就throws
  如果JDK没有提供对应的异常,需要自定义异常。

小练习

键盘录入一个int类型的整数,对其求二进制表现形式
      如果录入的整数过大,给予提示,录入的整数过大请重新录入一个整数BigInteger
      如果录入的是小数,给予提示,录入的是小数,请重新录入一个整数
      如果录入的是其他字符,给予提示,录入的是非法字符,请重新录入一个整数

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Scanner;
public class Damo8 {
    public static void main(String[] args) {
        System.out.println("请输入一个整数:");
        // 1 创建键盘录入对象
        Scanner sc = new Scanner(System.in);
        while (true) { //死循环
            // 2 将键盘录入的结果存储在String字符串中,存储int如果有不符合条件的结果会直接报错,无法进行后续判断
            String str = sc.nextLine();
            try {
                int num = Integer.parseInt(str);//如果字符串正常将字符转换为整数 不正常抛出异常
                System.out.println(Integer.toBinaryString(num));//将字符转换为二进制数并输出
                break;//正确则跳出循环
            } catch (Exception e1) {
                try {
                    new BigInteger(str); //能放在BigInteger 证明是一个过大的整数 放不进则继续抛出异常
                    System.out.println("录入错误,你输入的是一个过大的整数,请重新输入");
                } catch (Exception e2) {
                    try {
                        new BigDecimal(str);//能放在BigDecimal 证明是一个小数 放不进则继续抛出异常
                        System.out.println("录入错误你输入的是一个小数,请重新输入");
                    } catch (Exception e3) {//直接抛异常 死循环继续
                        System.out.println("录入错误你输入的是非法字符,请重新输入");
                    }
                }
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/a13085/article/details/81430164
今日推荐