Java速通8:异常

199 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天,点击查看活动详情

异常 Exception

java中所有的异常最终都继承自java.lang.Throwable

9-1.png

1.检查异常(Checked Excecption)

  1. 这类异常一般难避免,编译器会进行检查(若开发者未处理这类异常,编译器会报错。即受编译器检查的异常)
  2. 哪些异常是检查型异常?(除Error、RuntimeException以外的异常,即直接继承Exception的异常)

2.非检查异常(Unchecked Excecption)

  1. 这类异常一般可避免,编译器不会进行检查(若开发者未处理这类异常,编译器不报错)
  2. 哪些异常是检查型异常?(Error、RuntimeException)

3.常见检查型异常

// java.io.FileNotFoundException  文件不存在
FileOutputStream fos = new FileOutputStream("F:/123.txt");

// java.lang.InterruptedException 
Thread.sleep(1000);

// java.lang.ClassNotFoundException,类不存在
Class cls = Class.forName("Dog");

// java.lang.IllegalAccessException,无权限访问构造方法
// java.lang.InstantiationException,没无参构造方法
Dog dog = (Dog)cls.newInstance();

4.常见非检查型异常 - Error

// 内存不够
for(int i = 0; i < 200; i++){
    // java.lang.OutOfMemoryError,内存不够
    long[] arr = new long[10_0000_0000];
}



// 栈溢出
public static void test(){
    test();
}

public static void main(String[] args){
    // java.lang.StackOverflowError,栈内存溢出
    test();
}

5.常见非检查型异常 - RuntimeException

// java.lang.NullPointerException,空指针异常
StringBuilder sb = null;
sb.append("abc");

// java.lang.NumberFormatException,数字的格式不对
Integer i = new Integer("abc");

// java.lang.ArrayIndexOutOfBoundsException,数组索引越界
int[] arr = {11, 22, 33};
arr[4] = 44;

// java.lang.ClassCastException,类型不匹配
Object obj = "123.4";
Double d = (Double)obj; // 123.4无法强转成Double类型

6.异常处理

不管程序抛出的是检查型异常,还是非检查型异常,只要程序员未主动处理,都会导致程序停止运行。
处理异常有两种方式:(都可用来处理 检查/非检查型异常)

  1. try-cath 捕获异常
try{
    // 代码1
    // 代码2(这段代码可能会抛出异常)
    // 代码3
}catch (异常A e){
    // 当抛出【异常A】类型的异常,会进入这个代码块
}catch (异常B e){
    // 当未抛出【异常A】类型
    // 但抛出【异常B】类型的异常,会进入这个代码块
}catch (异常C e){
    // 当未抛出【异常A】、【异常B】类型
    // 但抛出【异常C】类型的异常,会进入这个代码块
}finally {
    // 不管有没有捕获到异常,这里都会执行
    // 一般用来释放资源的操作(关闭数据库链接等)
}

// 1.若在执行try或catch时,JVM退出或当前线程被中断、杀死。fianlly可能不会执行。
// 2.若try或catch中使用了return、break、continue等 提前结束了语句。
//   finally会在return、break、continue之前执行。

//finally举例
PrintWriter out = null;
        
try{
    out = new PrintWriter("F:/abc.txt");
    out.print("ABCDE");

}catch (FileNotFoundException e){
    e.printStackTrace();
}finally {
    if(out != null){
        out.close();
    }
}


// java7开始 单个catch可捕获多种类型的异常
// 若并列的几个异常类型之间存在父子关系,保留父类型即可
// 这里的变量e 是隐式final的
//(因为e的类型不确定,非final的话,会出现赋值错误的情况)
try{
    
}catch(异常A | 异常B | 异常C e){
    // 当抛出 A 或B 或C类型的异常,会进入这个代码块
}



// 下列代码输出结果是什么?(1,2,4,5,6)
public static void main(String[] args){
    System.out.println(1);
    try{
        System.out.println(2);
        Integer it = new Integer("abc");
        System.out.println(3);

    }catch (NumberFormatException e){
        e.printStackTrace();
        System.out.println(4);
    }finally {
        System.out.println(5);
    }
    System.out.println(6);
}
  1. throws:将异常抛给上层方法

9-2.png

/*
    1.当父类中某个方法无throws异常:子类的重写方法也不能throws异常。
    2.当父类中某个方法有throws异常,子类的重写方法可以:
        1.不throws异常
        2.throws跟父类一样的异常
        3.throws父类异常的子异常
*/
public class Persion {
    public void test1() {}
    public void test2() throws IOException {}
    public void test3() throws IOException {}
    public void test4() throws IOException {}
}


public class Student extends Persion {
    @Override
    public void test1() {}

    @Override
    public void test2() {}

    @Override
    public void test3() throws IOException {}

    @Override
    public void test4() throws FileNotFoundException {}
}
  1. throw:抛出新建的异常
   public class Persion {
       private int age;
   
       // throws Exception 是为了告诉外界此方法可能会产生异常
       public void setAge(int age) throws Exception {
           if(age <= 0){
               throw new Exception("age必须大于0");
           }else {
               this.age = age;
           }
       }
   }

throw 和 throws 的区别?

  1. throws是用来声明一个方法可能抛出的所有异常信息,
  2. throws是将异常声明但是不处理,而是将异常往上传,谁调用我就交给谁处理。
  3. throw则是指抛出的一个具体的异常类型。

7.自定义异常

9-3.png

// 自定义一个检查age的异常类
public class WrongAgeException extends RuntimeException {
    public WrongAgeException(int age) {
        super("wrong age: " + age + "age不能小于0");
    }
}


// 调用
public void setAge(int age){
    if(age <= 0){
        throw new WrongAgeException(age);
    }else {
        this.age = age;
    }
}

8.使用异常的好处

  1. 将错误处理代码与普通代码区分开
try{
    // 正常的逻辑代码
}catch(){
    // 错误处理代码
}
  1. 能将错误信息传播到调用堆栈中
  2. 能对错误类型进行区分和分组

9.编写一个断言类

// 假设自己写了一个算法,如何测试算法的正确性
public static int sum(int a, int b){
	return a + b;
}


// 编写一个断言类
public class Asserts {
	public static void test(boolean flag){
        if(flag == true){
            return;
        }

        // falg == false 抛出非检查型异常
        throw new IllegalArgumentException("条件不成立");
    }
}


// 调用断言类 来测试算法
public static void main(String[] args) {
    // 这里可以批量写大量测试语句 来看执行结果 
    // 从而可知哪些数据存在问题
    Asserts.test(sum(10, 20) == 30);
    Asserts.test(sum(1, 20) == 21);
}

10.常见异常

异常描述
NullPointerException空指针异常
SQLException提供关于数据库访问错误或其他错误信息的异常
IndexOutOfBoundsException数组下标越界
NumberFormatException当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常
FileNotFoundException当试图打开指定路径名表示的文件失败时,抛出此异常
IOException当发生某种I/O异常时,抛出此异常。此类是失败或中断的I/O操作生成的异常的通用类
ClassCastException当试图将对象强制转换为不是实例的子类时,抛出该异常
ArrayStoreException试图将错误类型的对象存储到一个对象数组时抛出的异常
IllegalArgumentException抛出的异常表明向方法传递了一个不合法或不正确的参数
ArithmeticException当出现异常的运算条件时,抛出此异常。例如,一个整数“除以零”时,抛出此类的一个实例
NegativeArraySizeException如果应用程序试图创建大小为负的数组,则抛出该异常
NoSuchMethodException无法找到某一特定方法时,抛出该异常
SecurityException由安全管理器抛出的异常,指示存在安全风险
UnsupportedOperationException当不支持请求的操作时,抛出该异常
RuntimeExceptionRuntimeException是那些可能在Java虚拟机正常运行期间抛出的异常的超类