【JavaSE】异常

一、概述

  • Java中异常继承的根类是 Throwable,Throwable 是根类,但不是异常类。
  • Error 是严重的错误。
  • Exception 才是异常类,它是是编译或执行过程中可能会出现的问题,应该尽量提前避免。

异常的分类:

  • 编译时异常:继承自 Exception 的异常或其子类,编译阶段就会报错。
  • 运行时异常:继承自 RuntimeException 的异常或其子类,编译阶段不会报错,它是在运行是阶段才可能出现,建议提前处理。

在这里插入图片描述
异常一旦出现,程序就会终止。所以需要避免异常,处理异常。

二、运行时异常

  • 运行时异常继承自 RuntimeException 的异常或其子类。
  • 编译阶段不会报错,它是在运行是阶段才可能出现。运行时异常在编译阶段无论是否处理,代码编译都能通过。

常见的运行时异常:

  1. ArrayIndexOutOfBoundsException:数组索引越界异常。
int[] arr = {1,2,3};
System.out.println(arr[3); // 异常
  1. NullPonterException:空指针异常。
Student stu = null;
System.out.println(stu); // 输出 null
System.out.println(stu.getName); // 异常
  1. ClassCastException:类型转换异常。
Object obj = "Java";
Integer integer = (Integer) obj; // 异常
  1. NoSuchElementException:迭代器遍历没有此元素异常。
Collection<String> books= new ArraysList<>();
books.add("JavaSE");
books.add("JavaWeb");
Iterator<String> iterator = books.iterator();

System.out.println(iterator.next());
System.out.println(iterator.next());
System.out.println(iterator.next()); // 异常
  1. ArithmeticException:数学操作异常。
int num = 10 / 0; // 异常
  1. NumberFormatException:数据转换异常。
String num = "123a";
Integer integer = Integer.valueOf(num); // 异常

三、编译时异常

  • 编译时异常:继承自 Exception 的异常或其子类,编译阶段就会报错,必须处理。

四、 默认处理机制

  1. 在运行阶段,某个方法中的某行代码出现,产生异常对象,抛给该方法。
  2. 该方法再抛出给该方法的调用者,最终抛给main方法。
  3. main方法最终抛给 JVM,
  4. JVM 收到异常,输出信息,终止程序。之后的代码不会被执行。
public static void main(String[] args) {
    System.out.println("程序开始");
    test(10,0);
    System.out.println("程序结束");
}

public static void test(int a, int b){
    System.out.println("计算" + a + "/" + b);
    int c = a /b;
    System.out.println("结果为:" + c);
}

输出:

程序开始
计算10/0
Exception in thread "main" java.lang.ArithmeticException: / by zero
	at test.MyException.test(MyException.java:13)
	at test.MyException.main(MyException.java:7)

默认的异常处理机制并不好,一旦出现异常,程序立即终止死亡。

五、 编译时异常处理

5.1 抛出异常 throws

  • 产生的异常依次向上抛,最终由mian方法抛给 JVM。与默认异常处理机制相同。
  • 即使会产生多个异常,但是只会抛出一个异常。因为产生了一个异常之后,程序就会终止。
public static void main(String[] args) throws FileNotFoundException {
    System.out.println("程序开始");
    test();
    System.out.println("程序结束");
}

public static void test() throws FileNotFoundException {
    InputStream is = new FileInputStream("./logo.jpg");
}
程序开始
Exception in thread "main" java.io.FileNotFoundException: .\logo.jpg (系统找不到指定的文件。)

5.2 try…catch…

  • try 块中发生异常,catch 块捕获并打印异常信息。
  • try 块中发生异常处之后的代码不会被执行,但是 try 外的代码照常执行。
  • 可以处理异常,并且出现异常后程序不会终止。但这种方法不是最好的,上层调用者不知道执行情况。
public static void main(String[] args) {
   System.out.println("程序开始");
    test();
    System.out.println("程序结束");
}

public static void test() {
    System.out.println("开始寻找文件");

    try {
        InputStream is = new FileInputStream("./logo.jpg");
        System.out.println("出现异常后,这里不会被执行");
    } catch (Exception e) {
        e.printStackTrace();
    }

    System.out.println("文件寻找完毕");
}

输出:

程序开始
开始寻找文件
文件寻找完毕
程序结束
java.io.FileNotFoundException: .\logo.jpg (系统找不到指定的文件。)

5.3 抛出给最外层(规范)

  • 出现的异常依次抛出给最完成调用者。由最外层调用者集中捕获处理。
  • 抛出异常的方法中,产生异常处之后的代码不会被执行。最外层 try 块中 产生异常处之后的代码也不会被执行。
  • 这种方式最外层调用者知道底层的执行情况,并且出现异常后程序不会终止。
 public static void main(String[] args) {
  System.out.println("程序开始");

    try {
        test();
        System.out.println("出现异常,这里不会被执行");
    } catch (Exception e) {
        e.printStackTrace();
    }

    System.out.println("程序结束");
}

public static void test() throws Exception {
    System.out.println("开始寻找文件");

    InputStream is = new FileInputStream("./logo.jpg");
    
    System.out.println("文件寻找完毕");
}

输出:

程序开始
开始寻找文件
程序结束
java.io.FileNotFoundException: .\logo.jpg (系统找不到指定的文件。)

六、运行时异常处理

运行时异常会自动向上抛出,只需要在最外层捕获即可。

public static void main(String[] args) {
	System.out.println("程序开始");

    try {
        test(10,0);
    } catch (Exception e) {
        e.printStackTrace();
    }
    
    System.out.println("程序结束");
}

public static void test(int a, int b){
    System.out.println("计算" + a + "/" + b);
    int c = a /b;
    System.out.println("结果为:" + c);
}

七、finally

  • finally 关键字用在捕获异常格式中,放在最后面。无论是否出现异常,这里的代码都会被执行。

try…catch…finally 存在个数:

  • try:1 次。
  • catch:0~n 次(有 finally,可以不需要 catch ) 。
  • finally:0~1 次

7.1 关闭资源

  • 可在代码执行完毕后,进行资源的释放操作。
  • 资源就是实现了 Closeable 接口的,都自带 close()方法。
public static void main(String[] args) {
    test();
}

public static void test() {

    InputStream is = null;

    try {
        int a = 10 / 0;
        is = new FileInputStream("./logo.jpg");
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } finally {
        try {
	        if (is != null) is.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

7.2 延迟 return

  • 若 try 和 catch 中有 return,则会延迟到 finally 执行完毕后执行。
  • 若 finally 中有return,则会覆盖前面所有的 return。
  • 特别注意 System.exit(0);,在任何地点都可以直接关闭虚拟机。

(1)无异常,try 中的 return 延迟

public static void main(String[] args) {
    System.out.println(test());
}

public static int test() {
    try {
        int a = 10 / 2;
        return a;
    } catch (Exception e) {
        e.printStackTrace();
        return -1;
    } finally {
        System.out.println("finally 执行了");
    }
}
finally 执行了
5

(2)有异常,catch 中的 return 延迟

 public static void main(String[] args) {
        System.out.println(test());
    }

    public static int test() {
        try {
            int a = 10 / 0;
            return a;
        } catch (Exception e) {
            e.printStackTrace();
            return -1;
        } finally {
            System.out.println("finally 执行了");
        }
    }
java.lang.ArithmeticException: / by zero
finally 执行了
-1

(3)finally 中 return,无论是否有异常,都只会返回这里的 return

public static void main(String[] args) {
    System.out.println(test());
}

public static int test() {
    try {
        int a = 10 / 0;
        return a;
    } catch (Exception e) {
        e.printStackTrace();
        return -1;
    } finally {
        System.out.println("finally 执行了");
        return 999;
    }
}
java.lang.ArithmeticException: / by zero
finally 执行了
999

八、自定义异常

  • throws:用在方法上,用于抛出方法中的异常。
  • throw:用在出现异常的地方,用于创建异常对象,并立即在此处抛出。

8.1 自定义编译时异常

  1. 自定义一个异常类,继承 Exception,并重写构造器。
/**
 * 自定义编译时异常:年龄非法异常
 */
public class AgeIllegalException extends Exception{
    public AgeIllegalException() {
    }

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

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

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

    public AgeIllegalException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}
  1. 出现异常的地方,抛出自定义异常对象。
public static void main(String[] args) {
    try {
        checkAge(1000);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public static void checkAge(int age) throws AgeIllegalException {
    if (age < 0 || age > 150){
        throw new AgeIllegalException("age is illegal");
    }else {
        System.out.println("年龄为:" + age);
    }
}

8.2 自定义运行时异常

  1. 自定义一个异常类,继承 RuntimeException,并重写构造器。
/**
 * 自定义运行时异常:年龄非法异常
 */
public class AgeIllegalRuntimeException extends RuntimeException{
    public AgeIllegalRuntimeException() {
    }

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

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

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

    public AgeIllegalRuntimeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}
  1. 出现异常的地方,抛出自定义异常对象。
public static void main(String[] args) {
    checkAge(10);
}

public static void checkAge(int age) throws AgeIllegalRuntimeException {
    if (age < 0 || age > 150){
        throw new AgeIllegalRuntimeException("age is illegal");
    }else {
        System.out.println("年龄为:" + age);
    }
}

九、异常的作用

  • 可以处理代码问题,防止程序出现异常后的死亡。
  • 提高了程序的健壮性和安全性。
public static void main(String[] args) {
    while (true){
        try {
            Scanner scanner = new Scanner(System.in);
            System.out.println("请输入年龄:");
            int age = scanner.nextInt();
            System.out.println("今年" + age + "岁");
            break;
        }catch (Exception e){
            System.err.println("输入错误");
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值