当前位置:首页 > Java技术 > Java异常(超详细!)

Java异常(超详细!)

2022年08月04日 19:05:56Java技术4

1、什么是异常,java提供异常处理机制有什么用?

  • 什么是异常:程序执行过程中的不正常情况。
  • 异常的作用:增强程序的 健壮性

eg.

public class ExceptionTest01 {
     
    public static void main(String[] args) {
     
        int a = 10;
        int b = 0;
        // 实际上JVM在执行到此处的时候,会new异常对象:new ArithmeticException("/ by zero");
        // 并且JVM将new的异常对象抛出,打印输出信息到控制台了。
        int c = a / b;
        System.out.println(a + "/" + b + "=" + c);

        // 此处运行也会创建一个:ArithmeticException类型的异常对象。
        System.out.println(100 / 0);
    }
}

2、java语言中异常是以什么形式存在的呢?

异常在java中以 的形式存在,每一个 异常类 都可以创建 异常对象

eg.

public class ExceptionTest02 {
     
    public static void main(String[] args) {
     
        // 通过“异常类”实例化“异常对象”
        NumberFormatException nfe = new NumberFormatException("数字格式化异常!");
        
        // java.lang.NumberFormatException: 数字格式化异常!
        System.out.println(nfe);
    }
}

3、异常继承结构图

Java异常(超详细!) _ JavaClub全栈架构师技术笔记

  • Exception的直接子类:编译时异常(要求程序员在编写程序阶段必须预先对这些异常进行处理,如果不处理编译器报错,因此得名编译时异常。)。
  • RuntimeException:运行时异常。(在编写程序阶段程序员可以预先处理,也可以不管,都行。)

4、异常的分类

异常分为 编译时异常运行时异常

所有异常都是在 运行阶段 发生的。因为只有程序运行阶段才可以 new对象。

因为异常的发生就是 new异常对象

4.1编译时异常因为什么而得名?

因为编译时异常必须在编译(编写)阶段预先处理,如果不处理编译器报错,因此得名。

4.2 编译时异常和运行时异常的区别?

  • 编译时异常一般发生的概率 比较高
  • 运行时异常一般发生的概率 比较低
  • 编译时异常发生概率较高,需要在运行之前对其进行 预处理
  • 运行时异常发生概率较低,没必要提前进行预处理。

4.3编译时异常和运行时异常别称

  • 编译时异常
  1. 受检异常:CheckedException
  2. 受控异常
  • 运行时异常
  1. 未受检异常:UnCheckedException
  2. 非受控异常

1、补充:

public class ExceptionTest03 {
     
    public static void main(String[] args) {
     
        System.out.println(100 / 0);

        // 这里的HelloWorld没有输出,没有执行。
        System.out.println("Hello World!");
    }
}

程序执行到System.out.println(100 / 0);
此处发生了 ArithmeticException 异常,底层 new 了一个ArithmeticException异常对象,然后抛出了。
由于是 main方法 调用了100 / 0,所以这个异常ArithmeticException抛给了main方法
main方法没有处理,将这个异常自动抛给了 JVMJVM最终终止程序的执行

此时System.out.println("Hello World!");并不会执行。

注意:
ArithmeticException 继承 RuntimeException,属于 运行时异常。在编写程序阶段不需要对这种异常进行预先的处理。


eg.

public class ExceptionTest04 {
     
    public static void main(String[] args) {
     
        // main方法中调用doSome()方法
        // 因为doSome()方法声明位置上有:throws ClassNotFoundException
        // 我们在调用doSome()方法的时候必须对这种异常进行预先的处理。
        // 如果不处理,编译器就报错。
        //编译器报错信息: Unhandled exception: java.lang.ClassNotFoundException
        doSome();
    }

    /**
     * doSome方法在方法声明的位置上使用了:throws ClassNotFoundException
     * 这个代码表示doSome()方法在执行过程中,有可能会出现ClassNotFoundException异常。
     * 叫做类没找到异常。这个异常直接父类是:Exception,所以ClassNotFoundException属于编译时异常。
     * @throws ClassNotFoundException
     */
    public static void doSome() throws ClassNotFoundException{
     
        System.out.println("doSome!!!!");
    }
}

解决方法一、throws上报给方法调用者(推卸责任:调用者知道)

public class ExceptionTest04 {
     
    public static void main(String[] args) throws ClassNotFoundException {
     
        doSome();
    }
    public static void doSome() throws ClassNotFoundException{
     
        System.out.println("doSome!!!!");
    }
}

解决方法二、try…catch捕捉,处理(调用者是不知道)

public class ExceptionTest04 {
     
    public static void main(String[] args) {
     
        try {
     
            doSome();
        } catch (ClassNotFoundException e) {
     
            e.printStackTrace();
        }
    }
    
    public static void doSome() throws ClassNotFoundException{
     
        System.out.println("doSome!!!!");
    }
}

5、异常的处理方式

5.1 throws

在方法声明的位置上使用 throws 关键字抛出,谁调用我这个方法,我就抛给谁。抛给 调用者 来处理。

这种处理异常的态度:上报

5.2 try…catch

这个异常不会上报,自己把这个事儿处理了。
异常抛到此处为止,不再上抛了。

注意:

  • 只要异常没有捕捉,采用上报的方式,此方法的 后续代码不会执行
  • try语句块中的某一行出现异常,该行 后面的代码不会执行
  • try…catch捕捉异常之后,后续代码可以执行。

eg.

private static void m1() throws FileNotFoundException {
     
    System.out.println("m1 begin");
    m2();
    // 以上代码出异常,这里是无法执行的。
    System.out.println("m1 over");
}
try {
     
    m1();
    // m1方法出异常,下面代码不执行。
    System.out.println("hello world!");//不执行
} catch (FileNotFoundException e){
      
	//异常处理
    System.out.println("出异常了!!");
    System.out.println(e); 
}
System.out.println("hello world"); //会执行

注意:

  • 异常发生之后,如果我选择了上抛,抛给了我的调用者,调用者需要对这个异常继续处理,那么调用者处理这个异常同样有两种处理方式。
  • 一般不建议在main方法上使用throws,因为这个异常如果真正的发生了,一定会抛给JVM。JVM只有终止。
  • 一般main方法中的异常建议使用try…catch进行捕捉。

注意:

try {
     
    
} catch (ClassNotFoundException e) {
     
    e.printStackTrace();
}

这个分支中可以使用e引用,e引用 保存的内存地址是那个new出来 异常对象的内存地址


6、在以后开发中,处理编译时异常,应该上报还是捕捉呢?

  • 如果希望调用者来处理,选择throws上报。
  • 其它情况使用捕捉的方式。

7、深入try…catch

  1. catch后面的小括号中的类型可以是 具体的异常类型,也可以是该异常类型的 父类型
  2. catch可以写多个。建议catch的时候,精确的一个一个处理。这样有利于程序的调试。
  3. catch写多个的时候,从上到下,必须遵守 从小到大

eg.

try {
     
	FileInputStream fis = new FileInputStream("D:\\Download\\Javabean-addperson案例解析.docx");
} catch(FileNotFoundException e) {
     
	System.out.println("文件不存在!");
}

等同于

try {
     
	FileInputStream fis = new FileInputStream("D:\\Download\\Javabean-addperson案例解析.docx");
} catch(Exception e) {
     // 多态:Exception e = new FileNotFoundException();
	System.out.println("文件不存在!");
}
try {
     
    FileInputStream fis = new FileInputStream("D:\\Download\\Javabean-addperson案例解析.docx");
    fis.read();
} catch(IOException e){
     
    System.out.println("读文件报错了!");
} catch(FileNotFoundException e) {
     
    System.out.println("文件不存在!");
}
  1. JDK8的新特性:
    catch() 异常间可以自小到大| 分割

eg.

try {
     
    //创建输入流
    FileInputStream fis = new FileInputStream("D:\\Download\\Javabean-addperson案例解析.docx");
    // 进行数学运算
    System.out.println(100 / 0); // 这个异常是运行时异常,编写程序时可以处理,也可以不处理。
} catch(FileNotFoundException | ArithmeticException | NullPointerException e) {
     
    System.out.println("文件不存在?数学异常?空指针异常?都有可能!");
}

8、异常两个重要方法

方法名 作用
String getMessage() 返回异常的详细消息字符串
void printStackTrace() 追踪堆栈异常信息(采用异步线程)

9、finally字句

在finally子句中的代码是最后执行的,并且是 一定会执行 的,即使try语句块中的代码出现了异常。

finally子句必须和try一起出现,不能单独编写。

9.1 finally语句通常使用在哪些情况下呢?

通常在finally语句块中完成 资源的释放/关闭

eg.

public class ExceptionTest10 {
     
    public static void main(String[] args) {
     
        FileInputStream fis = null; // 声明位置放到try外面。这样在finally中才能用。
        try {
     
            fis = new FileInputStream("D:\\Download\\Javabean-addperson案例解析.docx");
            String s = null;
            // 这里一定会出现空指针异常!
            s.toString();
            System.out.println("hello world!");

            // 流使用完需要关闭,因为流是占用资源的。
            // 即使以上程序出现异常,流也必须要关闭!
            // 放在这里有可能流关不了。
            //fis.close();
        } catch (FileNotFoundException e) {
     
            e.printStackTrace();
        } catch(IOException e){
     
            e.printStackTrace();
        } catch(NullPointerException e) {
     
            e.printStackTrace();
        } finally {
     
            System.out.println("hello 浩克!");
            // 流的关闭放在这里比较保险。
            // finally中的代码是一定会执行的。
            // 即使try中出现了异常!
            if (fis != null) {
      // 避免空指针异常!
                try {
     
                    // close()方法有异常,采用捕捉的方式。
                    fis.close();
                } catch (IOException e) {
     
                    e.printStackTrace();
                }
            }
        }
    }
}

9.2try和finally联用,没有catch

eg.

public class ExceptionTest11 {
     
    public static void main(String[] args) {
     
    	try {
     
            System.out.println("try...");
            return;
        } finally {
     
            System.out.println("finally...");
        }

        // 这里不能写语句,因为这个代码是无法执行到的。
        //System.out.println("Hello World!");
    }
}

以下代码的执行顺序:

  1. 先执行try…
  2. 再执行finally…
  3. 最后执行 return (return语句只要执行方法必然结束。)

注意:

  • try不能单独使用。
  • try finally可以联合使用。
  • 放在finally语句块中的代码是一定会执行的

9.3 finally子句失效

System.exit(0); 只有这个可以治finally。

public class ExceptionTest12 {
     
    public static void main(String[] args) {
     
        try {
     
            System.out.println("try...");
            // 退出JVM
            System.exit(0); // 退出JVM之后,finally语句中的代码就不执行了!
        } finally {
     
            System.out.println("finally...");
        }
    }
}

9.4 finally面试题

public class ExceptionTest13 {
     
    public static void main(String[] args) {
     
        int result = m();
        System.out.println(result); //100
    }

    /*
    java语法规则(有一些规则是不能破坏的,一旦这么说了,就必须这么做!):
        java中有一条这样的规则:
            方法体中的代码必须遵循自上而下顺序依次逐行执行(亘古不变的语法!)
        java中海油一条语法规则:
            return语句一旦执行,整个方法必须结束(亘古不变的语法!)
     */
    public static int m(){
     
        int i = 100;
        try {
     
            // 这行代码出现在int i = 100;的下面,所以最终结果必须是返回100
            // return语句还必须保证是最后执行的。一旦执行,整个方法结束。
            return i;
        } finally {
     
            i++;
        }
    }
}

反编译之后的效果:

public static int m(){
     
    int i = 100;
    int j = i;
    i++;
    return j;
}

9.5 final finally finalize有什么区别?

  • final 关键字
  1. final修饰的无法继承
  2. final修饰的方法无法覆盖
  3. final修饰的变量不能重新赋值
  • finally 关键字
  1. finally 和try一起联合使用。
  2. finally语句块中的代码是必须执行的。
  • finalize 标识符
  1. 是一个Object类中的方法名。
  2. 这个方法是由垃圾回收器GC负责调用的

10、自定义异常(开发中常用)

10.1前言

SUN提供的JDK内置的异常肯定是不够的用的。在实际的开发中,有很多业务,这些业务出现异常之后,JDK中都是没有的。和业务挂钩的。因此需要自定义异常。

10.2自定义异常步骤

  1. 第一步:编写一个类继承 Exception 或者 RuntimeException.
  2. 第二步:提供两个 构造方法,一个无参数的,一个带有String参数的。

eg.

//栈操作异常:自定义异常!
public class StackOperationException extends Exception{
      // 编译时异常!
    public MyStackOperationException(){
     

    }

    public MyStackOperationException(String s){
     
        super(s);
    }
}

11、方法覆盖,时遗留的问题

  • 重写之后的方法不能比重写之前的方法抛出更多(更宽泛)的异常,可以更少。方法覆盖
class Animal {
     
    public void doSome(){
     

    }

    public void doOther() throws Exception{
     

    }
}

class Cat extends Animal {
     

    // 编译正常。
    public void doSome() throws RuntimeException{
     

    }

    // 编译报错。
    /*public void doSome() throws Exception{

    }*/

    // 编译正常。
    /*public void doOther() {

    }*/

    // 编译正常。
    /*public void doOther() throws Exception{

    }*/

    // 编译正常。
    public void doOther() throws NullPointerException{
     

    }
}

注意:
一般不会这样考虑,方法覆盖复制一份,然后重写就好了。

12、总结异常中的关键字

  • 异常捕捉:
  1. try
  2. catch
  3. finally
  • throws 在方法声明位置上使用,表示上报异常信息调用者
  • throw 手动抛出异常

eg.

    public void pop() throws StackOperationException {
     
        if(index < 0){
     
            throw new MyStackOperationException("弹栈失败,栈已空!");//手动抛出异常
        }
    }

该方法index < 0时手动抛出异常,然后在方法里没有处理,上报给调用者,让调用者处理!

作者:一个快乐的野指针~
来源链接:https://blog.csdn.net/qq_44715943/article/details/116375510

版权声明:
1、JavaClub(https://www.javaclub.cn)以学习交流为目的,由作者投稿、网友推荐和小编整理收藏优秀的IT技术及相关内容,包括但不限于文字、图片、音频、视频、软件、程序等,其均来自互联网,本站不享有版权,版权归原作者所有。

2、本站提供的内容仅用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯相关权利人及本网站的合法权利。
3、本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站(javaclubcn@163.com),我们将第一时间核实后及时予以删除。


本文链接:https://www.javaclub.cn/java/17465.html

标签: Exception
分享给朋友:

“Java异常(超详细!)” 的相关文章

java 异常处理

java 异常处理

一:什么是异常  异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的。  比如说,你的代码少了一个分号,那么运行出来结果是提示是错误 java.lang.Error;如果你用System.out.println(11/0),那么你是因为你用0做了...

java异常处理中的返回值

java异常处理中的返回值

项目github地址:bitcarmanlee easy-algorithm-interview-and-practice 欢迎大家star,留言,一起学习进步 1.try-catch中的返回值 java代码中,有各种各样的try-catch...

Java异常处理和设计

Java异常处理和设计

#cnblogs_post_body h2 { background: rgba(64, 108, 164, 1) !important; margin: 15px 0 !important; padding: 5px 0 5px 20px; border-radius: 4px !i...

Mybatis异常处理之MySQL Connector Java] will not be managed by Spring

Mybatis异常处理之MySQL Connector Java] will not be managed by Spring

很长时间没写后台代码有点生疏了,这不今天又出点小插曲,写个文章记录下。 由于要上传点数据到后台,顺手整了个mybatis+springmvc。在保存数据时出现了异常。 Creating a new SqlSession SqlSession [org.apache...

深入理解java异常处理

深入理解java异常处理

文章目录 一.异常的介绍 二.分类...

java mybatis org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException: ### Error qu...

Java中的异常处理:何时抛出异常,何时捕获异常,何时处理异常?

Java中的异常处理:何时抛出异常,何时捕获异常,何时处理异常?

1.具体明确(异常类型) 2.提早抛出(1抛更具体的异常类型,2 更好的定位) 3.延迟捕获 (在能处理的时候捕获,而不是把它‘吃掉’ Java中的异常处理:何时抛出异常,何时捕获异常? 2017-06-07   1 异常分类...

SSM

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or...

Java中处理异常throw和throws

Java中处理异常throw和throws

Java中处理异常throw和throws 1.首先我们来了解什么是异常呢?      异常阻止当前方法或作用域继续执行的问题。 2.处理异常    说到处理异常,我们当然会想到 try&n...

Java线程池异常处理机制

原文链接:https://my.oschina.net/lifany/blog/884002 一、前言       线程池技术是服务器端开发中常用的技术。不论是直接还是间接,各种服务器端功能的执行总是离不开线程池的调度...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。