一次搞懂Java异常处理(超详细!!!)!

目录

一. 异常概述、体系

什么是异常?

为什么要学习异常?

如何处理异常?

假设我们有一个接收String参数的方法,方法中会对该参数进行一些逻辑处理,正常的业务流程要求不允许null值出现,可如果调用者传递了一个null值进来,此时我们该怎么做呢?

二. 常见运行时异常

三. 常见编译时异常

 java.util.concurrent.BrokenBarrierException {CyclicBarrier.await()}

java.util.concurrent.ExecutionException

NoSuchMethodException{反射}

四. 异常的默认处理流程

五. 编译时异常的处理机制

​编辑

六.Throwable类常用方法有哪些?try-catch-finally如何使用?

String getMessage(): 返回异常发生时的简要描述

String toString(): 返回异常发生时的详细信息

void printStackTrace(): 在控制台上打印 Throwable 对象封装的异常信息

try-catch-finally 如何使用?

finally 中的代码一定会执行吗?

如何使用 try-with-resources 代替try-catch-finally?

throw和throws的区别: 

七. 运行时异常的处理机制

七. 异常处理使代码更稳健的案例

八. 自定义异常

补充:

1. try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?

2. try-catch-finally 中哪个部分可以省略?

3. 主线程可以捕获到子线程的异常吗?

4. final、finally、finalize 有什么区别?


一. 异常概述、体系

什么是异常?

  • 异常是程序在“编译”或者“执行”的过程中可能出现的错误 / 问题,而不是语法问题导致的编译错误,语法错误不算在异常体系中,语法错误是自己的水平问题引起的。
  • 比如:数组索引越界异常、空指针异常、日期格式化异常,等....

为什么要学习异常?

  • 异常一旦出现了,如果没有提前处理,程序就会退出JVM虚拟机而终止。
  • 学习异常不是让我们以后不出异常,而是程序出了异常之后,该如何处理。体现的是程序的安全,健壮性。
  • Error:错误Error是一种特殊的类(java.lang.Error)与普通的Exception异常类不同,Error是程序无法处理的错误,Error类及其子类是指我们程序处理不了或者说不该由程序处理的错误,这类错误往往代表JVM在运行过程中出了问题, Error不应该由应用程序捕获和处理,而是由虚拟机自己处理,通常代表着虚拟机和系统级别的问题。
  • 一些常见的Error比如:
  1. Virtual MachineError:Java 虚拟机运行错误  => 内存溢出(OutOfMemoryError --- 堆内存溢出StackOverflowError --- 栈内存溢出)
  2. java.lang.NoClassDefFoundError:当虚拟机无法找到(找不到)要加载的类时抛出的错误。
  3. LinkageError:当类加载过程出现链接错误时抛出的错误。

一次搞懂Java异常处理(超详细!!!)!_第1张图片

一次搞懂Java异常处理(超详细!!!)!_第2张图片 Java 异常类层次结构图
一次搞懂Java异常处理(超详细!!!)!_第3张图片 异常继承关系图
  • Java中的所有异常都来⾃顶级⽗类Throwable,Throwable下有两个⼦类Exception和Error。
  • Throwable类,是所有异常类的根类,Java异常的顶层父类,所有的异常类都是由它继承。
  • Exception:异常,程序本身可以处理的异常。
  • Java中异常继承的根类是:ThrowableThrowable是根类,不是异常类。
  • Exception才是异常类,当程序出现Exception时,是可以靠程序⾃⼰来解决的,它才是开发中代码在编译或者执行的过程中可能出现的错误,它是需要提前处理的,以便程序更健壮!
  • 异常体系的最上层父类是Exception。
  • Exception的⼦类通常⼜可以分为RuntimeException和⾮RuntimeException两类
  • 异常分为两类:编译时异常(受检异常,必须处理)、运行时异常(非受检异常)。
  • 受检异常:就是程序必须手动处理的异常,如果不手动处理,则会编译失败。
  • 非受检异常:不强制程序处理的异常,不强制你手动处理,无需try...catch...,也无需throws,代码也能编译成功。
  • Error也属于非受检异常。
  • 编译时异常{受检异常-Checked Exception}:没有继承RuntimeException的异常,直接继承于Exception。编译阶段就会错误提示 / 报错必须要手动处理(如果受检查异常没有被 catch或者throws 关键字处理的话,就没办法通过编译),否则代码报错不通过。编译时异常是为了提醒程序员,比如:IOException、ClassNotFoundException、ParseException、SQLException、java.io.FileNotFoundException...
  • 运行时异常{非受检异常-Unchecked Exception}:继承了RuntimeExceptionRuntimeException本身和子类。编译阶段不会报错 / 出现异常提醒,运行时出现的异常。运行时异常是代码出错而导致程序出现的问题。

一次搞懂Java异常处理(超详细!!!)!_第4张图片

package com.gch.d3_exception;

/**
    目标:异常的概念和体系。
 */
public class ExceptionDemo {
    public static void main(String[] args) {
        int[] arr = {10, 20, 40};
        System.out.println(arr[0]);
        System.out.println(arr[1]);
        System.out.println(arr[2]);
        System.out.println(arr[3]); // ArrayIndexOutOfBoundsException
        System.out.println("-----------程序截止---------");
    }
}

一次搞懂Java异常处理(超详细!!!)!_第5张图片

一次搞懂Java异常处理(超详细!!!)!_第6张图片

package com.gch.d3_exception;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class ExceptionDemo1 {
    public static void main(String[] args) throws ParseException {

        // 编译时异常(在编译阶段,必须要手动处理,否则代码报错)
        String time = "2030年1月1日";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
        Date date = sdf.parse(time);
        System.out.println(date); // Tue Jan 01 00:00:00 CST 2030

        // 运行时报错(在编译阶段是不需要处理的,是代码运行时出现的异常)
        int[] arr = {1, 2, 3, 4, 5};
        System.out.println(arr[10]); // ArrayIndexOutOfBoundsException
    }
}
如何处理异常?

在Java中有两个处理异常的方式,一个是try...catch...,一个是throws。

try...catch:

  • try...catch{捕获异常}:将可能发生异常的代码放到try代码块中,然后使用catch来捕获对应的异常。
  • 如果try代码块正常执行,那catch就不会生效如果发生了指定的异常,则会执行对应的catch代码块,然后继续往下执行,如此一来,我们就能避免异常影响到我们的正常逻辑。
  • 捕获异常时还可以接上finally代码块,无论有没有发生异常,finally代码块都会执行。
一次搞懂Java异常处理(超详细!!!)!_第7张图片 try代码块不能单独使用,应当搭配catch或finally代码块
package com.gch.exceptiondemo;

import java.io.IOException;

/**
   try捕获异常,catch处理异常
 */
public class ExceptionDemo {
    public static void main(String[] args) throws Exception {
        // 可以catch一个也可以catch多个异常
        try{
            // 可能会发生异常的逻辑
            throw new Exception();
        }catch(IOException e){
            // 发生IOException时,执行此代码块
            System.out.println(e);
        }catch(ClassNotFoundException e){
            // 发生ClassNotFoundException,执行此代码块
            System.out.println(e);
        }catch(Exception e){
            // 发生其它异常时,执行此代码块
            // 父类异常应放在子类异常后面,否则子类不会被捕获
        }finally{
            // 无论是否发生异常,都会执行
            // 如果没有加catch处理异常,finally虽会执行,但异常还是会影响正常逻辑
        }
    }
}

throws{抛出异常}:在方法上使用throws关键字可以声明该方法可能会抛出的异常。

  • 当我们调用一个方法时,如果这个方法用throws关键字声明了受检异常,此时我们就必须得手动处理它声明的异常,否则就会编译失败{要么你就try...catch...,要么你就在当前方法使用throws声明同样的或其父类异常}。
package com.gch.exceptiondemo;

import java.io.IOException;

/**
   try捕获异常,catch处理异常
 */
public class ExceptionDemo {
    public static void main(String[] args) throws Exception {
        // 可以catch一个也可以catch多个异常
        try{
            // 可能会发生异常的逻辑
            throw new Exception();
        }catch(IOException e){
            // 发生IOException时,执行此代码块
            System.out.println(e);
        }catch(ClassNotFoundException e){
            // 发生ClassNotFoundException,执行此代码块
            System.out.println(e);
        }catch(Exception e){
            // 发生其它异常时,执行此代码块
            // 父类异常应放在子类异常后面,否则子类不会被捕获
        }finally{
            // 无论是否发生异常,都会执行
            // 如果没有加catch处理异常,finally虽会执行,但异常还是会影响正常逻辑
        }
    }

    /** 可以throws声明一个或多个异常 */
    /**
     * 可以throws声明一个或多个异常
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public static void process() throws IOException,ClassNotFoundException{
        // 可能会发生异常的逻辑
    }

    public static void f1() {
        // 编译失败,编译器直接报错,因为没有手动处理受检异常{try...catch... / throws}
        process();
    }

    public static void f2() {
        // 编译成功,因为try...catch处理异常了
//        try {
//            process();
//        } catch (IOException e) {
//            throw new RuntimeException(e);
//        } catch (ClassNotFoundException e) {
//            throw new RuntimeException(e);
//        }
        try{
            process();
        }catch(IOException | ClassNotFoundException e){
            // ...
        }
    }

    public static void f3() throws IOException, ClassNotFoundException {
        // 编译成功,因为throws往外抛异常了
        process();
    }

    public static void f4(){
        // 因为方法f2()已经try...catch...处理异常了,所以不用再手动处理了
        f2();
    }

}
  • 这里其实就可以体现出throws的作用了:那就是我不想处理这个异常时,我可以把这个问题往外抛,谁调用我谁就来处理,就好像在工作中出现了一个问题,你可以选择将这个问题自行解决,也可以选择将这个问题丢给你的上级解决,那你的上级碰到问题时,也会面临同样的选择,要么他自己解决,那么他就将问题抛给更上级。
  • 如果一个问题或者说一个异常发生了后就一直往上抛,到最顶层的main方法了,都没人去try...catch...解决,那程序就会终止运行。

一次搞懂Java异常处理(超详细!!!)!_第8张图片

什么时候该try...catch...,什么时候该throws呢?

  • 有一个很简单的原则就是:当前方法需要继续运行下去,就肯定得用try...catch...当前方法不需要继续运行,就可以选择throws。
  • 建议尽量选择捕获异常。

一次搞懂Java异常处理(超详细!!!)!_第9张图片

假设我们有一个接收String参数的方法,方法中会对该参数进行一些逻辑处理,正常的业务流程要求不允许null值出现,可如果调用者传递了一个null值进来,此时我们该怎么做呢?
  • 第一种做法就是给参数设置一个默认值,然后继续执行后续逻辑:
   /**
     * @param arg 参数不允许为null
     */
    public static void method(String arg){
        if(arg == null){
            arg = "默认值";
        }
        // 继续执行业务逻辑...
    }
  • 第二种做法就是直接结束方法,不执行后面逻辑。{这里还可以返回不同的值,来表达方法执行的结果}
   /**
     * @param arg 参数不能为null
     * @return 参数如果为null则返回false,否则为true
     */
    public static boolean method(String arg) {
        if(arg == null){
            return false;
        }
        // 业务逻辑...
        return true;
    }
  • 第三种做法就是抛出异常
   /**
     * @param arg 参数不能为null
     */
    public static void method3(String arg) {
        if(arg == null){
            throw new RuntimeException();
        }
        // 业务逻辑...
    }

总结: 如果碰到了会影响正常逻辑的情况,基本就这三大类处理方式 =>

一次搞懂Java异常处理(超详细!!!)!_第10张图片

二. 常见运行时异常

运行时异常的概念:
       
     继承自RuntimeException的异常或者其子类,
             编译阶段是不会出错的,它是在运行时阶段可能出现的错误,
             运行时异常编译阶段可以处理也可以不处理,代码编译都能通过!!

  1. 数组索引越界异常: ArrayIndexOutOfBoundsException。
  2. 空指针异常 : NullPointerException。直接输出没有问题。但是调用空指针的变量的功能就会报错!!
  3. 类型转换异常:ClassCastException。
  4. 迭代器遍历没有此元素异常:NoSuchElementException。
  5. 算术异常:ArithmeticException。
  6. 数字转换异常:NumberFormatException(字符串转换为数字格式错误,IllegalArgumentException的子类)。
  7. 非法线程状态异常:llegalThreadStateException
  8. 并发修改异常:java.util.ConcurrentModificationException(多线程下集合操作元素)

  9. IllegalArgumentException:参数错误(比如方法入参类型错误)

  10. SecurityException:安全错误(比如权限不够)

  11. UnsupportedOperationException:不支持的操作错误(比如重复创建同一用户)

  12. ArrayStoreException:数据存储异常(操作数组时类型不一致)

  13. java.lang.IllegalStateException{Queue full依然add()添加元素}

  14. FileSizeLimitExceededException:在SpringBoot中,文件上传时默认单个文件最大大小为1M,当上传一个较大的文件(超出1M)时,运行和后端程序报错

  15. NoSuchBeanDefinitionException:表示在应用程序中没有找到指定的Bean的定义!在Spring容器ApplicationContext中调用getBean()获取bean对象时,bean的名称填错,就会报改错,或者就跟着没有该Bean对象!

  16. UnsupportedClassVersionError:比如在JDK8上面运行JDK11环境下的程序!

  17. java.lang.UnsupportedOperationException异常:使用Collections.unmodifiableCollection(Collection c)方法来创建一个只读集合,这样改变集合的任何操作都会抛出该异常~!

一次搞懂Java异常处理(超详细!!!)!_第11张图片

一次搞懂Java异常处理(超详细!!!)!_第12张图片

package com.gch.d4_exception_runtimeException;
/**
    拓展: 常见的运行时异常。(面试题)
         运行时异常的概念:
             继承自RuntimeException的异常或者其子类,
             编译阶段是不会出错的,它是在运行时阶段可能出现的错误,
             运行时异常编译阶段可以处理也可以不处理,代码编译都能通过!!

             1.数组索引越界异常: ArrayIndexOutOfBoundsException。
             2.空指针异常 : NullPointerException。
               直接输出没有问题。但是调用空指针的变量的功能就会报错!!
             3.类型转换异常:ClassCastException。
             4.迭代器遍历没有此元素异常:NoSuchElementException。
             5.算术异常:ArithmeticException。
             6.数字转换异常:NumberFormatException。

    小结:
        运行时异常继承了RuntimeException ,编译阶段不报错,运行时才可能会出现错误!
 */
public class ExceptionDemo {
    public static void main(String[] args) {
        System.out.println("程序开始。。。。。。");
        /** 1.数组索引越界异常: ArrayIndexOutOfBoundsException。*/
        int[] arr = {1, 2, 3};
        System.out.println(arr[2]);
        // System.out.println(arr[3]); // 运行出错,程序终止

        /** 2.空指针异常 : NullPointerException。直接输出没有问题。但是调用空指针的变量的功能就会报错!! */
        String name = null;
        System.out.println(name); // null
        // System.out.println(name.length()); // 运行出错,程序终止

        /** 3.类型转换异常:ClassCastException。 */
        Object o = 23;
        // String s = (String) o;  // 运行出错,程序终止

        /** 5.数学操作 / 算术异常:ArithmeticException。 */
        //int c = 10 / 0;

        /** 6.数字转换异常: NumberFormatException。 */
        //String number = "23";
        String number = "23aabbc";
        Integer it = Integer.valueOf(number); // 运行出错,程序终止
        System.out.println(it + 1);

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

三. 常见编译时异常

当调用一个抛出异常的方法的时候,调用者必须处理这个异常(try...catch...或者throws),如果不处理,编译失败!

一次搞懂Java异常处理(超详细!!!)!_第13张图片

  1. IOException
  2. ClassNotFoundException
  3. ParseException
  4. SQLException
  5. FileNotFoundException
  6. java.lang.InterruptedException
  7. CloneNotSupportedException、
  8. java.util.concurrent.ExecutionException
  9.  java.util.concurrent.TimeoutException
  10.  java.util.concurrent.BrokenBarrierException {CyclicBarrier.await()}
  11. java.util.concurrent.ExecutionException

  12. NoSuchMethodException{反射}
  13. ServletException
package com.gch.d5_exception_javac;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
    目标:常见的编译时异常认识。

    编译时异常:继承自Exception的异常或者其子类,没有继承RuntimeException
         "编译时异常是编译阶段就会报错",
         必须程序员编译阶段就处理的。否则代码编译就报错!!

    编译时异常的作用是什么:
         是担心程序员的技术不行,在编译阶段就爆出一个错误, 目的在于提醒!
         提醒程序员这里很可能出错,请检查并注意不要出bug。
         编译时异常是可遇不可求。遇到了就遇到了呗。

    了解: 
 */
public class ExceptionDemo {                     // 解析异常
    public static void main(String[] args) throws ParseException {
        String date = "2015-01-12 10:23:21";
        // 创建一个简单日期格式化类:
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // 解析字符串时间成为日期对象
        Date d = sdf.parse(date);
        System.out.println(d); // Mon Jan 12 10:23:21 CST 2015
    }
}

四. 异常的默认处理流程

一次搞懂Java异常处理(超详细!!!)!_第14张图片

一次搞懂Java异常处理(超详细!!!)!_第15张图片

一次搞懂Java异常处理(超详细!!!)!_第16张图片

五. 编译时异常的处理机制

一次搞懂Java异常处理(超详细!!!)!_第17张图片

一次搞懂Java异常处理(超详细!!!)!_第18张图片

 一次搞懂Java异常处理(超详细!!!)!_第19张图片

 一次搞懂Java异常处理(超详细!!!)!_第20张图片

一次搞懂Java异常处理(超详细!!!)!_第21张图片

六.Throwable类常用方法有哪些?try-catch-finally如何使用?

Throwable类常用方法:

  • String getMessage(): 返回异常发生时的简要描述
  • String toString(): 返回异常发生时的详细信息
  • void printStackTrace(): 在控制台上打印 Throwable 对象封装的异常信息
  • public synchronized Throwable getCause():获取实际的异常原因
    

一次搞懂Java异常处理(超详细!!!)!_第22张图片

try-catch-finally 如何使用?

  • try块:用于捕获异常。其后可接零个或多个 catch 块,如果没有 catch 块,则必须跟一个 finally 块。
  • catch块:用于处理 try 捕获到的异常。
  • finally 块:无论是否捕获或处理异常,finally 块里的语句都会被执行。当在 try 块或 catch 块中遇到 return 语句时,finally 语句块将在方法返回之前被执行。可以在finally代码块中进行资源的释放!

注意:不要在 finally 语句块中使用 return!

  • 当 try 语句和 finally 语句中都有 return 语句时,try 语句块中的 return 语句会被忽略。
  • 这是因为 try 语句中的 return 返回值会先被暂存在一个本地变量中,当执行到 finally 语句中的 return 之后,这个本地变量的值就变为了 finally 语句中的 return 返回值。

jvm 官方文档open in new windowicon-default.png?t=N7T8https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.10.2.5JVM官方文档中有明确提到:

一次搞懂Java异常处理(超详细!!!)!_第23张图片

代码示例: 

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

public static int f(int value) {
    try {
        return value * value;
    } finally {
        if (value == 2) {
            return 0;
        }
    }
}

一次搞懂Java异常处理(超详细!!!)!_第24张图片

finally 中的代码一定会执行吗?

  • 不一定的!在某些情况下,finally 中的代码不会被执行。
  • 比如说 finally 之前虚拟机被终止运行的话,finally 中的代码就不会被执行。
try {
    System.out.println("Try to do something");
    throw new RuntimeException("RuntimeException");
} catch (Exception e) {
    System.out.println("Catch Exception -> " + e.getMessage());
    // 终止当前正在运行的Java虚拟机
    System.exit(1);
} finally {
    System.out.println("Finally");
}

一次搞懂Java异常处理(超详细!!!)!_第25张图片

另外,在以下几种特殊情况下,finally 块的代码也不会被执行:

一次搞懂Java异常处理(超详细!!!)!_第26张图片

如何使用 try-with-resources 代替try-catch-finally

  1. 适用范围(资源的定义): 任何实现 java.lang.AutoCloseable或者 java.io.Closeable 接口的类对象才能定义为资源。
  2. 关闭资源:try(定义资源{流}对象:资源1;资源2)=>用完会自动调用资源对象的close方法关闭资源,即使出现异常也会做关闭操作,无需再在finally代码块中手动调用资源的close方法进行资源的关闭。

throw和throws的区别: 

thow

  • 用在方法体内,跟的是异常对象名 => new
  • 只能抛出一个异常对象名
  • throw是用来主动制造并抛出异常,由方法体内的语句处理
  • throw是抛出了异常,执行throw则一定抛出了某种异常
  • 关键字  throw  后面,写异常类的对象=>new

throws

  • throws关键字用/写在方法的声明上,不是方法内部
  • throws后面跟的是异常类名,不是对象 => new
  • throws是声明方法可能会发生的异常,throws表示抛出异常,由该方法的调用者来处理,处理方式:调用者可以throws继续向上抛出或者在方法内部使用try...catch...
  • throws表示出现异常的一种可能性,并不一定会发生这些异常

注意:如果main方法里面单独开启了一条线程,并且调用了抛出异常的方法,则只能在方法内部进行try...catch处理,因为方法内部不能使用throws抛出异常类! 

一次搞懂Java异常处理(超详细!!!)!_第27张图片

七. 运行时异常的处理机制

一次搞懂Java异常处理(超详细!!!)!_第28张图片

七. 异常处理使代码更稳健的案例

一次搞懂Java异常处理(超详细!!!)!_第29张图片

package com.gch.d8_handle_runtime;

import java.sql.SQLOutput;
import java.util.Scanner;

/**
   需求:需要输入一个合法的价格为止  要求价格大于0
 */
public class Test2 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while(true){
            try {
                System.out.println("请您输入价格:");
                String priceStr = sc.nextLine();
                // 转换成Double类型的价格
                double price = Double.valueOf(priceStr);

                // 判断价格是否大于0
                if(price > 0){
                    System.out.println("定价:" + price);
                    break;
                }else{
                    System.out.println("价格必须是正数~~~");
                }
            } catch (NumberFormatException e) {
                System.out.println("程序有误!");
//                throw new RuntimeException(e);
            }
        }
    }
}

八. 自定义异常

Java标准库中提供了非常多表的异常类型,用来表达各种异常情况,然而在真实开发中,这些异常并不能完全满足我们的需求,因为标准库的异常往往表达的是技术层面,而不是业务层面,像账号密码错误这种情况,用标准库的异常就不太合适,所以在开发中我们会自定义异常类型,来表达符合我们业务的异常情况。

只要继承异常类,就可以定义我们自己的异常,强烈建议大家继承RuntimeException,在自定义异常时,应当照着父类学习,提供多个构造方法,因为这样就能传递错误信息和堆栈信息。

一次搞懂Java异常处理(超详细!!!)!_第30张图片 自定义异常

异常定义好后,我们就可以new出异常对象,并用throw关键字来主动抛出异常。 

一次搞懂Java异常处理(超详细!!!)!_第31张图片

一次搞懂Java异常处理(超详细!!!)!_第32张图片

 一次搞懂Java异常处理(超详细!!!)!_第33张图片

补充:

1. try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?

  • finally 一定会执行,即使是 catch 中 return 了,catch 中的 return 会等 finally 中的代码执行完之后,才会执行。

2. try-catch-finally 中哪个部分可以省略?

  • try-catch-finally 其中 catch 和 finally 都可以被省略,但是不能同时省略,也就是说有 try 的时
    候,必须后面跟一个 catch 或者 finally。

3. 主线程可以捕获到子线程的异常吗?

  • 正常情况下,如果不做特殊的处理,在主线程中是不能够捕获到子线程中的异常的。

4. final、finally、finalize 有什么区别?

  • final可以修饰类、变量、方法,修饰类表示该类不能被继承、修饰方法表示该方法不能被重写、修饰变量表示该变量是一个常量不能被重新赋值。
  • finally一般作用在try-catch代码块中,在处理异常的时候,通常我们将一定要执行的代码方法放入finally代码块中,表示不管是否出现异常,该代码块都会执行,一般用来存放一些关闭资源的代码。
  • finalize是一个方法,属于Object类的一个方法,而Object类是所有类的父类,该方法一般由垃圾回收器来调用,当我们调用System的gc()方法的时候,由垃圾回收器调用finalize()方法来回收垃圾。

你可能感兴趣的:(JavaSE,java,servlet,jvm)