Java 的异常类

异常的体系

  • Throwable
    • Error
    • Exception
      • RuntimeException

如果程序没有处理异常, JVM 自行处理, 把异常的名称和信息, 打印在控制台上.

异常的2种处理方式

  • try catch finally
    • try catch
    • try catch finally
    • try finally
  • throws
public class Demo1_Exception {
    public static void main(String[] args) {
        Demo1 demo1 = new Demo1();
        int x;
        try{
            x = demo1.div(10,0);
        } catch (ArithmeticException e){
            System.out.println(e.getClass());
            System.out.println("test");
        }finally {
            System.out.println("最后执行了吗");
        }
    }
}
class Demo1 {
    public int div (int a, int b){
        return a/b;
    }
}
public class Demo2_Exception {
    public static void main(String[] args) {
        int a = 0;
        int b = 10;
        int[] arr = {1, 2, 3};
        int x ;
        arr = null;
        try {
//            x = b / a;
            System.out.println(arr[10]);
        } catch (ArithmeticException e){
            System.out.println(e.getClass());
        } catch (IndexOutOfBoundsException e){
            System.out.println(e.getClass());
        } catch (Exception e){
            System.out.println("有异常");
        }
    }
}
public class Demo3_Exception {
    public static void main(String[] args) {
        try {
            System.out.println(10/0);
        } catch (ArithmeticException | IndexOutOfBoundsException  e){
            System.out.println("Exception");
        }
    }
}

异常throwable 的方法

  • String getMessage() 获取异常信息
  • String toString() 获取异常类和异常信息
  • void printStackTrace() 获取异常类和异常信息, 异常在程序出现的位置
public class Demo3_Exception {
    public static void main(String[] args) {
        try {
            System.out.println(10/0);
        } catch (ArithmeticException | IndexOutOfBoundsException  e){
            System.out.println(e.getMessage());
            System.out.println(e.toString());
            e.printStackTrace();
        }
    }
}

方法上的2种异常

  • RuntimeException 运行时异常, 不需要在方法向上抛出, 使用的时候也不需要在使用的方法上向上抛出
  • 非RuntimeException 的异常, 必须在方法上向上抛出, 使用方法时也必须向上抛出异常
import lombok.Getter;
import lombok.Setter;

public class Person {
    public Person(){}
    public Person(String name, int age){
        this.name = name;
        this.age = age;
    }
    @Getter
    @Setter
    private String name;
    @Getter
    private int age;

    public void setAge(int age)  {
        if(age < 1 || age > 150){
            throw new RuntimeException ("年龄非法");
        }
        this.age = age;
    }
}
import lombok.Getter;
import lombok.Setter;

public class Person {
    public Person(){}
    public Person(String name, int age){
        this.name = name;
        this.age = age;
    }
    @Getter
    @Setter
    private String name;
    @Getter
    private int age;

    public void setAge(int age)  throws Exception{
        if(age < 1 || age > 150){
            throw new Exception ("年龄非法");
        }
        this.age = age;
    }
}
public class Demo4_Exception {
    public static void main(String[] args) throws Exception{
        Person p = new Person();
        p.setAge(-12);
        System.out.println("MM");
    }
}

throws 和 throw 区别

  • throws
    • 用在方法声明后, 跟的是异常类名
    • 跟以跟多个类名, 用逗号隔开
    • 表示抛出异常, 由该方法的调用者处理
  • throw
    • 用在方法内, 跟的是异常对象名
    • 只能抛出一个异常对象名
    • 表示抛出异常, 由方法体内的语句处理

finally

  • finally 的特点
    • 被finally 控制的语句一定会执行
    • 特殊情况: 在执行finally 前 JVM 退出了(如System.exit(0))
  • finally 的作用
    • 用于释放资源, 在IO 操作和数据库操作中会见到
  • return 的区别 return 执行后, 如果有finally 则执行finally 类
public class Demo5_Exception {
    public static void main(String[] args) {
        try {
            System.out.println(1/0);
        } catch (Exception e){
            System.out.println("异常");
        } finally {
            System.out.println("最后一定执行");
        }
    }
}

final finally finalize 区别

  • final
    • final 可以修饰类, 但不能被继承
    • 修饰方法不能被重写
    • 修饰变量只能赋值一次
  • finally
    • try catch finally 体系中的一个语句, 不能单独使用
  • finalize
    • 当垃圾回收器确定不存在该对象的更多引用时, 对象回收器则调用此方法
public class Demo6_Exception {
    public static void main(String[] args) {
        System.out.println(demo1());
    }
    public static int demo1(){
        int x = 10;
        try {
            x = 20;
            System.out.println(1/0);
            return x;
        } catch (Exception e){
            x = 30;
            return x;
        } finally {
            x = 40;
        }
    }
}

x 会返回30, return 把x=30装箱返回回去

自定义异常

  • 为什么需要定义异常类
    • 可通过异常类名字即可知道错误在哪
  • 异常使用
    • 自定义异常类, 继承Exception
    • 在方法中使用异常类
    • 调用方法时处理异常类(try catch finally)或直接抛出
public class OutOfAgeException extends Exception {
    public OutOfAgeException() {
        super();
    }

    public OutOfAgeException(String message) {
        super(message);
    }

    public OutOfAgeException(String message, Throwable cause) {
        super(message, cause);
    }

    public OutOfAgeException(Throwable cause) {
        super(cause);
    }

    protected OutOfAgeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}
import com.lizicai.exception.OutOfAgeException;
import lombok.Getter;
import lombok.Setter;

public class Person {
    public Person(){}
    public Person(String name, int age){
        this.name = name;
        this.age = age;
    }
    @Getter
    @Setter
    private String name;
    @Getter
    private int age;

    public void setAge(int age)  throws Exception{
        if(age < 1 || age > 150){
            throw new OutOfAgeException("年龄异常");
        }
        this.age = age;
    }
}
public class Demo7_Exception {
    public static void main(String[] args) throws Exception {
        Person p = new Person();
        p.setAge(-10);
    }
}

异常

  • 子类重写父类方法时, 子类的方法必须抛出相同的异常或父类异常的子类( 子类不能比父类坏的更多 )
  • 如果父类抛出多个异常, 子类重写父类时, 只能抛出相同的异常或异常的子类, 子类不能抛出父类没有的异常
  • 如果重写方法没有异常抛出, 那么子类的方法绝对不可以抛出异常, 如果子类方法内有异常发生, 那么子类能try catch,不能throws

练习

  • 输入一个整数
  • 超出整数范围则提示过大, 重新输入整数
  • 输入小数则提示小数, 重新输入整数
  • 输入字符等, 则提示非法字符, 请重新输入整数
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Scanner;

public class Demo8_Exception {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String str = null;
        BigInteger bigInteger = null;
        BigDecimal bigDecimal = null;
        int scInt = 0;
        System.out.println("请输入一个整数:");
        while (sc.hasNext()){
            str = sc.nextLine();
            try {
                scInt = Integer.parseInt(str);
                System.out.println(Integer.toBinaryString(scInt));
                break;
            } catch (Exception e){
                try {
                    bigInteger = new BigInteger(str);
                    System.out.println("过大的整数, 请重新输入整数");
                } catch (NumberFormatException e2){
                    try{
                        bigDecimal =  new BigDecimal(str);
                        System.out.println("输入的小数, 请重新输入整数");
                    } catch (Exception e3){
                        System.out.println("输入的非法字符, 请重新输入整数");
                    }
                }
            }
        }
    }
}