当前位置: 首页 > news >正文

JAVA学习*异常

什么是异常

在 Java 里,异常是指程序运行期间出现的不正常状况,它会中断程序的正常执行流程。

异常的分类

Java 中的异常是对象,这些对象都继承自 Throwable类。Throwable类有两个主要的子类:Error 和 Exception。
Error类表示严重的系统级错误。
Exception类代表程序中可以被捕获和处理的异常情况。Exception类又分为两类:受查异常(编译时异常)和运行时异常。
在这里插入图片描述

异常的处理

对于异常的处理有5个关键字:try catch finally throw throws

throw关键字

用于在方法内部抛出异常。

throw new XXXXException("产生异常的原因");

代码展示:

public static void func(int a) throws ArithmeticException{
    if(a == 0) {
        throw new ArithmeticException("除数为零,算数异常");
    }
    int b = 40 / a;
    System.out.println(b);
    int[] array = null;
    if(array == null) {
        throw new NullPointerException("空指针异常");
    }
    System.out.println(array[1]);
}
public static void main(String[] args) {
    int a = 0;
    func(a);
}

在这里插入图片描述

代码解释:

1、为什么要抛出异常?是为了将错误信息告知程序员。
2、throw用于抛出异常,必须在方法内部使用。
3、用throw只是单纯抛出问题,并没有解决异常。对于抛出的是RunTimeException 或者 RunTimeException 的子类是,则可以不用处理,直接交给JVM处理。
4、异常一旦抛出后面的代码将不再执行。像上述代码就不会输出b的值,也不会爆出空指针异常。
当我们将a == 2时,输出b的值,爆出空指针异常。**也就是说同一时刻只能抛出一个异常!**不会同时抛出多个异常。
在这里插入图片描述
5、对于抛出编译时异常,需要用throws在方法声明中声明可能抛出的异常。

throws关键字

用于在方法声明中声明可能抛出的异常。

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

代码展示:

1、对于刚才的代码,我们也可以声明可能发生的异常。

public static void func(int a) throws ArithmeticException,NullPointerException{
    if(a == 0) {
        throw new ArithmeticException("除数为零,算数异常");
    }
    int b = 40 / a;
    System.out.println(b);
    int[] array = null;
    if(array == null) {
        throw new NullPointerException("空指针异常");
    }
    System.out.println(array[1]);
}
public static void main(String[] args) {
    int a = 2;
    func(a);
}

2、在学习Cloneable接口时,有出现throws关键字。

class Student implements Cloneable{
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class Test2 {
    public static void main(String[] args) throws CloneNotSupportedException{
        Student student = new Student();
        Student student1 = (Student) student.clone();
    }
}

代码解释:

1、throws告诉调用者这个方法可能存会抛出异常,调用者需要处理这个异常。使用throws实际上是将处理代码的责任转移给了调用改方法的代码。

像上述代码:重写的clone()方法声明了CloneNotSupportedException异常。当main方法调用了clone()方法,需要去处理这个异常。但是,main方法也声明了CloneNotSupportedException异常,此时将由JVM去处理。

2、throws必须跟在方法的参数列表之后。
3、如果抛出的多个异常存在父子关系,可以声明父类。

try和catch关键字

try是用于包含可能会抛出异常的代码块。
catch是用于捕获并处理try块中抛出的异常。

try {
    可能会抛出异常的代码块
} catch (异常1 e) {
    throw new RuntimeException(e);
} catch (异常2 e) {
    throw new RuntimeException(e);
}

代码展示:

代码案例1:

public static void func(int a) {
    int b = 40 / a;
    System.out.println(b);
    int[] array = null;
    System.out.println(array[1]);
}
public static void main(String[] args) {
    int a = 0;
    try {
        func(a);
        System.out.println("try内部的代码被执行了");
    } catch (ArithmeticException e) {
        e.printStackTrace();
        System.out.println("捕捉到算数异常");
    } catch (NullPointerException e) {
        e.printStackTrace();
        System.out.println("捕捉到空指针异常");
    }
    System.out.println("try-catch后面的代码被执行了");
}

输出:
在这里插入图片描述

代码案例2:

public static void func(int a) {
    int b = 40 / a;
    System.out.println(b);
    int[] array = null;
    System.out.println(array[1]);
}
public static void main(String[] args) {
    int a = 0;
    try {
        func(a);
        System.out.println("try内部的代码被执行了");
    } catch (IndexOutOfBoundsException e) {
        e.printStackTrace();
        System.out.println("捕捉到下标越界异常");
    } catch (NullPointerException e) {
        e.printStackTrace();
        System.out.println("捕捉到空指针异常");
    }
    System.out.println("try-catch后面的代码被执行了");
}

输出:
在这里插入图片描述
代码案例3:

class Student implements Cloneable {
    public int age;
    public String name;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException{
        Student student = new Student();
        Student student1 = (Student) student.clone();
    }
}
public class Test {
    public static void main(String[] args) {
        try {
            test1();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
    public static void test1() throws CloneNotSupportedException{
            throw new CloneNotSupportedException();
        }
}
public class Test {
    public static void main(String[] args) {
            test1();
    }
    public static void test1() {
        try {
            throw new CloneNotSupportedException();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

代码解释:

1、 try内不是一定要有异常的。
2、 在代码案例1中:我们发现func(a);后面的代码没有被执行。说明在捕获到了异常后,try包裹的后面的代码就不会被执行(这是为了考虑到安全性)。会执行捕获到的catch中的代码(案例中也就是e.printStackTrace();System.out.println("捕捉到算数异常");)。当捕获到异常后,try-catch后面的代码仍会被执行。
3、 在代码案例1中:我们发现当存在多个异常时,只会捕捉一个异常,这个异常是,try中最先发生的异常在catch中匹配成功的第一个异常(注意:并不是第一catch的异常)。(当然,前提是抛出的异常类型和catch中的异常匹配的时候)
4、 在代码案例2中:我们发现当抛出的异常类型和catch中的异常不匹配时,抛出的异常不会被处理,此时就会交给JVM处理,JVM处理就会终止程序,输出异常信息,将不会再执行后面语句了。
5、 在代码案例3中:对于编译时异常我们可以将不断抛出,最终交给JVM处理;

就是第一个代码,我们再学习接口的时候就有见过。由于重写的clone方法声明了CloneNotSupportedException异常,此时我们需要去对这个异常进行处理,当时我们选择的是对异常进行抛出给调用者(main方法),main方法继续抛出给JVM处理。

也可以自己使用try-catch进行处理。

第二个和第三个代码都使用了try-catch来处理异常,只是在处理异常的地方不一样,本质上是一样的。

6、 由于异常之间是存在继承关系的,在根据第3点知识,我们可以知道catch中的第一个异常不能是Exception!因为Exception是所有异常的父类。catch(Exception e){}虽然不能放在第一个,但是可以放在最后一个,进行一个兜底的作用。防止有些异常没有被我们捕捉到。也是就是如果异常之间具有父子关系,一定是子类异常在前catch,父类异常在后catch,否则语法错误!
7、 当要捕捉的异常较多的时候,可以catch合并起来写。

catch(ArithmeticException | NullPointerException e) {}

但不推荐这么写,会造成分不清具体发生的是什么异常。当然也不允许只写个Exception。

finally关键字

finally关键字通常和try-catch语句搭配使用。

作用:

finally块常用于确保资源(如文件、网络连接、数据库连接等)被正确关闭,避免资源泄漏。

代码案例:

代码案例1:

public class Test2 {
    public static void main(String[] args) {
        try {
            int result = 10 / 0; // 这里会抛出ArithmeticException异常
            System.out.println("结果: " + result);
        } catch (ArithmeticException e) {
            e.printStackTrace();
            System.out.println("捕获到算数异常");
        } finally {
            System.out.println("finally块中的代码一定会被执行");
        }
    }
}

在这里插入图片描述
代码案例2:

import java.util.InputMismatchException;
import java.util.Scanner;

public class TestFinally {
    public static int getNum() {
        Scanner scanner = null;
        try {
            scanner = new Scanner(System.in);
            int data = scanner.nextInt();
            return data;
        } catch (InputMismatchException e) {
            e.printStackTrace();
        } finally {
            System.out.println("finally内代码被执行了");
        }
        System.out.println("finally后面代码被执行了");
        if(scanner != null) {
            scanner.close();
        }
        return 0;
    }
    public static void main(String[] args) {
        int data = getNum();
        System.out.println(data);
    }
}

在 Java 里,InputMismatchException是RuntimeException的子类。当程序借助Scanner类从输入源(像键盘、文件等)读取数据,而输入的数据类型和程序所期望的数据类型不相符时,就会抛出此异常。

当输入数字时:
在这里插入图片描述
当输入的不是数字时:
在这里插入图片描述

代码案例3:

public class Test3 {
    public static void main(String[] args) {
        int test = test();
        System.out.println(test);
    }
    public static int test() {
        int a = 0;
        try {
            int b = 40/a;
            return 1;
        } catch (ArithmeticException e) {
            return 0;
        } finally {
            return -1;
        }
    }
}

输出:-1

代码解释:

1、 在代码案例1中:无论try块里的代码是否抛出异常,finally块中的代码都会被执行。
2、 在代码案例2中:
当输入数字时,并没有产生异常,所以遇到了try中的return,返回输入的数字。但代码并没有走关闭Scanner的代码,导致资源泄露。(但finally中的代码一定会被执行。)
当输入非数字时,产生异常,此时异常被捕获,try中的return语句就不会被执行。走完catch和finally后,会进入if语句,返回0。
3、 在代码案例3中:当try和finally中都有return语句,此时一定会执行finally中的return语句。(一定要记住:finally中的代码是一定会被执行的!)
4、 对于快速使用try-catch-finally的快捷键:选中代码块,ctrl + Alt + t
在这里插入图片描述

异常处理流程总结

1、 对于运行时异常,可以使用try-catch-finally;也可以使用if语句进行判断,其中使用throw手动抛出异常。对于使用throws来说,只是起到了一个声明存在可能发生的异常,可以用可以不用。
2、 对于编译时异常,可以使用try-catch-finally;也可以使用throws交给调用者处理,最终会交给JVM处理。

1、程序执行try中的代码
2、当try中没有发生异常,程序就会正常执行;当发生异常,就会看和catch中的异常是否匹配。
3、匹配成功,执行当中catch的语句;否则交给调用者处理,当调用者始终没有真正处理,就会交给JVM处理,此时程序就会终止。
4、finally中的代码始终被执行!

自定义异常

代码案例:

public class LogIn {
    private String username = "admin";
    private String password = "123";

    public LogIn(String username, String passeword) {
        this.username = username;
        this.password = passeword;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public LogIn() {
    }

    public void login() throws PasswordException {
        if (!this.username.equals("admin")) {
            throw new UsernameException("用户名错误或不存在");
        }
        if (!this.password.equals("123")) {
            throw new PasswordException("密码错误");
        }
        System.out.println("登录成功!");
    }
}
public class UsernameException extends RuntimeException{
    public UsernameException(String message) {
        super(message);
    }
    public UsernameException() {
        super();
    }
}
public class PasswordException extends Exception{
    public PasswordException() {
        super();
    }
    public PasswordException(String message) {
        super(message);
    }
}
import java.util.Scanner;

public class CustomExceptionTest {
    public static void main(String[] args) {
        Scanner scanner = null;
        int count = 3;
        scanner = new Scanner(System.in);
        do {
            LogIn logIn = new LogIn();
            System.out.println("请输入用户名:");
            logIn.setUsername(scanner.nextLine());
            System.out.println("请输入密码:");
            logIn.setPassword(scanner.nextLine());
            try {
                logIn.login();
            } catch (UsernameException e) {
                e.printStackTrace();
            } catch (PasswordException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if(scanner != null && count == 0) {
                    scanner.close();
                }
                count--;
                if(count != 0) {
                    System.out.println("你还有" + count + "次机会!");
                }else if(count == 0) {
                    System.out.println("请1分钟后在试");
                }
            }
        } while (count != 0);
    }
}

代码解释:

1、对于自定义异常,需要继承异常类。一般是Exception或者RuntimeException。
2、继承Exception默认被定义为受查异常。继承RuntimeException默认被定义为运行时异常。
3、对于自定义异常可以重写构造方法。

http://www.dtcms.com/a/96998.html

相关文章:

  • CSS-BFC(块级格式化上下文)
  • 主流大模型采用的架构、注意力机制、位置编码等汇总表
  • 【SECS】初识SECS协议
  • MiniRAG检索流程详细图解
  • #VCS# 关于 +incdir+xxx 编译选项的注意点
  • #前端js发异步请求的几种方式
  • 【AI语音】edge-tts实现文本转语音,免费且音质不错
  • 指针 --1
  • RS232转Profinet网关技术,检漏仪新篇章!
  • 深度融合华为鸿蒙生态,嘀嗒出行重构顺风车出行新体验
  • 「HTML5+Canvas实战」星际空战游戏开发 - 纯前端实现 源码即开即用【附演示视频】
  • 18-背景渐变与阴影(CSS3)
  • C++ | constexpr
  • Linux服务器怎样根据端口找到对应启动的服务
  • TCSVT审稿学习笔记
  • 3.28-2 jmeter读取mysql
  • spring @SpringBootApplication 注解详解
  • 使用AURIX ADS部署tensorflow lite到Tricore TC2XX/TC3XX
  • EMC知识学习三
  • ecovadis评估有什么流程?对企业发展的重要意义
  • HTML应用指南:利用GET请求获取全国无印良品门店位置信息
  • 19726 星际旅行
  • 【SDMs分析1】基于ENMTools R包的生态位分化分析和图像绘制(identity.test())
  • <wbr>标签的用途,在处理长文本换行时如何发挥作用?
  • 算法 | 河马优化算法原理,公式,应用,算法改进及研究综述,matlab代码
  • Android WLAN offload Data Supplementary Service
  • Centos8 系統Lnmp服務器環境搭建
  • 高效加盖骑缝章:PDF文件处理的实用解决方案
  • 跨境TRS投资操作指南与系统解决方案
  • EspressoSample深度解析:在CircleCI上高效运行Android UI测试