【一步一步了解Java系列】:认识异常类

简介: 【一步一步了解Java系列】:认识异常类

看到这句话的时候证明:此刻你我都在努力

加油陌生人 2.png

异常类的概念及其层次结构


Java中存在异常类,那么何为异常类呢?那么我们必须先了解一下它的概念:Java异常处理是Java语言中非常重要的一部分,它允许程序在遇到错误时能够优雅地处理问题而不是直接崩溃。Java异常类主要分为两大类:检查型异常(Checked Exceptions)和非检查型异常(Unchecked Exceptions)。

检查型异常/编译时异常(Checked Exceptions):

这些异常通常是由于编程错误导致的,比如FileNotFoundException或SQLException。

它们必须在方法签名中声明抛出,或者在方法内部被处理(通常是通过try-catch块)。

在运行前编译器就已经报出警告了:

  1. 非检查型异常/运行时异常(Unchecked Exceptions)
  • 这些异常通常是由于运行时错误导致的,比如NullPointerException或ArithmeticException。
  • 它们不需要在方法签名中声明,也不强制要求必须被捕获处理。
  • 如图在运行前编译器是不会提示错误的:

Java中的异常就像我们生活中人生病一样,我们的程序也会生病,我们可以把计算机的病就叫做“异常”。


那么下面就给大家解析一下其层次结构:

Java异常类的层次结构从__java.lang__包中的__Throwable__类开始,它有两个主要的子类:Exception__和__Error


Throwable:

Java异常类的根类。

有两个重要的子类:Exception和Error。

Exception:

表示程序本身可以处理的异常情况。

进一步分为IOException、SQLException等。

RuntimeException:

Exception的一个子类,表示在Java程序运行时发生的异常。

包括NullPointerException、IndexOutOfBoundsException等。

Error:

表示JVM无法处理的错误,比如OutOfMemoryError或StackOverflowError。

通常不需要程序去捕获这些错误

有关处理异常的关键词

在Java中处理异常我们有这么几个常用的关键词 :throw、try、catch、finally、throws。

  1. ** throw 抛出异常 **


如下是一个简单的异常抛出,我们在一个方法中要执行一条语句时,如果其可能会发生异常,如:null,分母为0,数组访问越界,我们都可以自己抛出异常,如下为一个空指针异常

package demo1;

public class Test {

    public static void testExceptinon(int[] arr){
        if(arr==null){
        throw new ArithmeticException();
    }
    }


    public static void main(String[] args) {
        int[] arr=null;
        testExceptinon(arr);
    }

}


所谓抛出异常其实就是抛出一个Exception或Exception的子类。

注意事项:


抛出异常类其必须是Exception或Exception的子类。

抛出异常必须在方法内部

如果抛出的是 RunTimeException 或者 RunTimeException 的子类,则可以不用处理,直接交给JVM来处理

** 如果抛出的是编译时异常,用户必须处理,否则无法通过编译**

** 异常一旦抛出,其后的代码就不会执**

异常声明throws

throws一个用来声明异常的关键词,是用在方法上的,具体格式为

** 修饰符 返回值类型 方法名(参数列表) throws 异常类型1,异常类型2…{ } **

注意throws只是起到警示作用,就是给程序员知道用这个方法可能会抛出异常。不会解决异常。

public class Test {

    public static final void test1 ()throws RuntimeException{
        int a=10;
        int c=0;
        System.out.println(a/c);

    }



}
  1. ** try-catch捕获并处理 **

解决异常还得用到try-catch语句,这是我们常用处理异常的关键词,当然还有finally关键词,稍后我也会提到。

import com.sun.security.jgss.GSSUtil;

public class Test {

    public static final void test1 ()throws ArithmeticException{
        int a=10;
        int c=0;
        System.out.println(a/c);

    }

    public static void main(String[] args) {

        int q=10;
        int p=100;
        String s="hello world";
        System.out.println(q+p);
        try{
            test1();              //try的花括号内是放入可能会抛出异常的语句
                                  //如果里面的语句没有抛出异常则会跳出try-catch语句


        }catch (ArithmeticException e){   //小括号里是放入可能会捕捉到的异常类 e

            System.out.println("处理异常");  //catch花括号内是我们自行处理异常的方法

        }finally {
            System.out.println("无论是否捕捉到异常都一定会执行的代码");   //finally里的语句无论是否检测到异常都会执行的语句
        }

        System.out.println("处理完异常后的代码执行");  //这是处理异常后才会执行的语句
                                                 // 当异常被捕获到时,异常就被处理了,这里的后序代码一定会执行
                                               //如果捕获了,由于捕获时类型不对,那就没有捕获到,这里的代码就不会被执行


    }



}


try的花括号内是放入可能会抛出异常的语句, 如果里面的语句没有抛出异常则会跳出try-catch语句

catch的小括号里是放入可能会捕捉到的异常类 e,catch花括号内是我们自行处理异常的方法

catch-catch-finally外的语句:当异常被捕获到时,异常就被处理了,这里的后序代码一定会执行,如果捕获了,由于捕获时类型不对,那就没有捕获到,这里的代码就不会被执行

** finally **

配合try-catch语句用的,但是其不是一定要加上去的,而try-catch一定是一起出现的。

在写程序时,有些特定的代码,不论程序是否发生异常,都需要执行,比如程序中打开的资源:网络连接、数据库 连接、IO流等,在程序正常或者异常退出时,必须要对资源进进行回收。另外,因为异常会引发程序的跳转,可能 导致有些语句执行不到,finally就是用来解决这个问题的。

public static int getData() {
    Scanner sc = null;
    try {
        sc = new Scanner(System.in);
        int data = sc.nextInt();
        return data;
    } catch (InputMismatchException e) {
        e.printStackTrace();
    } finally {
        System.out.println("finally中代码");
    }
    System.out.println("try-catch-finally之后代码");
    if (null != sc) {
        sc.close();
    }


    return 0;
}

public static void main(String[] args) {
    int data = getData();
    System.out.println(data);
}

上述程序,如果正常输入,成功接收输入后程序就返回了,try-catch-finally之后的代码根本就没有执行,即输入流 就没有被释放,造成资源泄漏。


自定义异常类

使用的较多的异常类往往是我们自己定义的比较多,那么如何自定义异常类呢,下面我们就来讲讲如何自定义异常类。

class textException extends RuntimeException{

    public textException() {
    }

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




public class Test1 {

    public static void main(String[] args) {
        int a=0;
        if(a==0){
            throw new textException();
        }
    }

}


如上我们只需让自己创建出的类继承Exception或其它异常类即可,这样这个类也是一个异常类了。

然后我们在需要抛出异常时,抛出自己定义的异常即可。

也可以用try-catch进行使用解决自己定义的异常。


注意事项:

  • ** 自定义异常通常会继承自 Exception 或者 RuntimeException **
  • **继承自 Exception 的异常默认是受查异常 **
  • **继承自 RuntimeException 的异常默认是非受查异常 **


异常的处理流程


关于 “调用栈” 方法之间是存在相互调用关系的, 这种调用关系我们可以用 “调用栈” 来描述. 在 JVM 中有一块内存空间称为 “虚拟机栈” 专门存储方法之间的调用关系. 当代码中出现异常的时候, 我们就可以使用 e.printStackTrace(); 的 方式查看出现异常代码的调用栈. 如果本方法中没有合适的处理异常的方式, **就会沿着调用栈向上传递 **

public class Test {


    public static final void func1(){

        int[] a={1,2,3,4,5};
        a[10] = 100;



    }

    public static void main(String[] args) {
        try {
           func1();
            System.out.println("hello world");
        }catch (ArrayIndexOutOfBoundsException e){
            e.printStackTrace();
            System.out.println("没能合适解决异常");

        }

    }
}

如上图:在func1中如果没进行处理,堆栈就会延栈调用,也就是图中又看mian方法中是否能够处理好异常,一直向上传递如果都无法解决,一旦交给JVM处理那么程序将会终止,就不会进行之后的代码。


异常类与if的区别

首先我们来说说if在应对程序的应用是怎样的?

if语句:

比如:下面代码我们的if就是在检测到b==0时,就不让程序继续进行下面的计算。

这属于一种事先防卫型,就是避免错误发生。在发生之前就将程序阻断。

package demo1;

import java.util.Scanner;

public class Test {

    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int a=sc.nextInt();
        int b=sc.nextInt();
        
        if(b==0){
            System.out.println("分母为0,数字不合法");
        }else {
            System.out.println("a/c= "+a/b);
        }
        
        
    }
}


异常类:

如下:异常类相比于if更像是先斩后奏型,事后处理型,在程序发现问题时在进行处理问题,如下代码将可能有异常的语句放到try括号中,如果出现异常在进行解决:

package demo1;

public class Test1 {

    public static void main(String[] args) {
        int a=10;
        int b=0;
        try{
            System.out.println("a/c= "+a/b);
        }catch (ArithmeticException e){
            System.out.println("捕捉到异常并解决异常的方法");
        }
    }
}


目录
相关文章
|
4月前
|
Java
在 Java 中捕获和处理自定义异常的代码示例
本文提供了一个 Java 代码示例,展示了如何捕获和处理自定义异常。通过创建自定义异常类并使用 try-catch 语句,可以更灵活地处理程序中的错误情况。
125 1
|
4月前
|
Java API 调度
如何避免 Java 中的 TimeoutException 异常
在Java中,`TimeoutException`通常发生在执行操作超过预设时间时。要避免此异常,可以优化代码逻辑,减少不必要的等待;合理设置超时时间,确保其足够完成正常操作;使用异步处理或线程池管理任务,提高程序响应性。
232 13
|
4月前
|
Java
在 Java 中,如何自定义`NumberFormatException`异常
在Java中,自定义`NumberFormatException`异常可以通过继承`IllegalArgumentException`类并重写其构造方法来实现。自定义异常类可以添加额外的错误信息或行为,以便更精确地处理特定的数字格式转换错误。
68 1
|
5天前
|
Java
课时14:Java数据类型划分(初见String类)
课时14介绍Java数据类型,重点初见String类。通过三个范例讲解:观察String型变量、"+"操作符的使用问题及转义字符的应用。String不是基本数据类型而是引用类型,但使用方式类似基本类型。课程涵盖字符串连接、数学运算与字符串混合使用时的注意事项以及常用转义字符的用法。
|
5天前
|
存储 Java 编译器
课时11:综合实战:简单Java类
本次分享的主题是综合实战:简单 Java 类。主要分为两个部分: 1.简单 Java 类的含义 2.简单 Java 类的开发
|
6天前
|
传感器 监控 Java
Java代码结构解析:类、方法、主函数(1分钟解剖室)
### Java代码结构简介 掌握Java代码结构如同拥有程序世界的建筑蓝图,类、方法和主函数构成“黄金三角”。类是独立的容器,承载成员变量和方法;方法实现特定功能,参数控制输入环境;主函数是程序入口。常见错误包括类名与文件名不匹配、忘记static修饰符和花括号未闭合。通过实战案例学习电商系统、游戏角色控制和物联网设备监控,理解类的作用、方法类型和主函数任务,避免典型错误,逐步提升编程能力。 **脑图速记法**:类如太空站,方法即舱段;main是发射台,static不能换;文件名对仗,括号要成双;参数是坐标,void不返航。
26 5
|
5天前
|
Oracle Java 关系型数据库
课时37:综合实战:数据表与简单Java类映射转换
今天我分享的是数据表与简单 Java 类映射转换,主要分为以下四部分。 1. 映射关系基础 2. 映射步骤方法 3. 项目对象配置 4. 数据获取与调试
|
24天前
|
Java 程序员 开发者
Java社招面试题:一个线程运行时发生异常会怎样?
大家好,我是小米。今天分享一个经典的 Java 面试题:线程运行时发生异常,程序会怎样处理?此问题考察 Java 线程和异常处理机制的理解。线程发生异常,默认会导致线程终止,但可以通过 try-catch 捕获并处理,避免影响其他线程。未捕获的异常可通过 Thread.UncaughtExceptionHandler 处理。线程池中的异常会被自动处理,不影响任务执行。希望这篇文章能帮助你深入理解 Java 线程异常处理机制,为面试做好准备。如果你觉得有帮助,欢迎收藏、转发!
97 14
|
27天前
|
缓存 Java 应用服务中间件
java语言后台管理若依框架-登录提示404-接口异常-系统接口404异常如何处理-登录验证码不显示prod-api/captchaImage 404 (Not Found) 如何处理-解决方案优雅草卓伊凡
java语言后台管理若依框架-登录提示404-接口异常-系统接口404异常如何处理-登录验证码不显示prod-api/captchaImage 404 (Not Found) 如何处理-解决方案优雅草卓伊凡
107 5
|
1月前
|
安全 Java 编译器
JAVA泛型类的使用(二)
接上一篇继续介绍Java泛型的高级特性。3. **编译时类型检查**:尽管运行时发生类型擦除,编译器会在编译阶段进行严格类型检查,并允许通过`extends`关键字对类型参数进行约束,确保类型安全。4. **桥方法**:为保证多态性,编译器会生成桥方法以处理类型擦除带来的问题。5. **运行时获取泛型信息**:虽然泛型信息在运行时被擦除,但可通过反射机制部分恢复这些信息,例如使用`ParameterizedType`来获取泛型参数的实际类型。

热门文章

最新文章