Java异常处理--异常处理的方式2:throws

文章目录

  • 一、方式2:声明抛出异常类型(throws)
  • 二、throws基本格式
  • 三、 throws 使用举例
    • (1)针对于编译时异常
      • 1、案例1
      • 2、案例2
    • (2)针对于运行时异常
  • 四、 方法重写中throws的要求
    • (1)说明
    • (2)举例1
    • (3)举例2
  • 五、 两种异常处理方式的选择

一、方式2:声明抛出异常类型(throws)

  • 如果在编写方法体的代码时,某句代码可能发生某个编译时异常,不处理编译不通过,但是在当前方法体中可能不适合处理无法给出合理的处理方式,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。

image.png

  • 具体方式:在方法声明中用throws语句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。

二、throws基本格式

声明异常格式:在方法的声明处,使用"throws 异常类型1,异常类型2,..."

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

在throws后面可以写多个异常类型,用逗号隔开。

【举例1】

public void test() throws 异常类型1,异常类型2,.. {
    //可能存在编译时异常 (运行时异常不用管它)
}

【举例2】

public void readFile(String file)  throws FileNotFoundException,IOException {
	...
	// 读文件的操作可能产生FileNotFoundException或IOException类型的异常
	FileInputStream fis = new FileInputStream(file);
    //...
}

三、 throws 使用举例

(1)针对于编译时异常

1、案例1

以如下代码为例:

public class ThrowsTest {
    public void method1() {
        File file = new File("D:\\hello.txt");

        //可能报FileNotFoundException 文件找不到异常
        FileInputStream fis = new FileInputStream(file);  //流直接操作文件

        //把文件内容直接读到内存中输出
        int data = fis.read();    //可能报IOException 输入输出异常
        while (data != -1) {    //data为-1的时候退出,就是读完了
            System.out.print((char) data);
            data = fis.read();  //可能报IOException 输入输出异常
        }

        //资源关闭
        fis.close();  //可能报IOException 输入输出异常
    }
}

方法method1()中,是一段可能有异常的代码。

此时是编译时异常,必须要进行处理。

image.png

☕处理

在方法小括号后面加上throws,然后根据可能出现异常的类型,比如这里可能出现FileNotFoundExceptionIOException,那么就将它们写在throws后面即可,用逗号隔开。如下:

public class ThrowsTest {
    public void method1() throws FileNotFoundException, IOException {
        //...  ...
    }
}

可以看到现在编译器不报红了,这意味着已经将可能出现的异常处理了。

如下:
image.png


现在针对于method1()方法来说,已经处理了。

若是现在method1()方法在另一个方法method2()里面被调用了,发现此时报红了。如下:

image.png

这里相当于把异常抛给method1()的调用者了。

所以method2()需要处理一下:

public void method2() throws FileNotFoundException, IOException{
    method1();
}

可以看见,不报红了:

image.png

此时method2()又在method3()里面调用了,此时method3()也面临刚才同样的问题:

image.png

此时method3()觉得可以搞定这个问题,它就可以去解决啦:

public void method3() {
    try {
        method2();
    }catch (FileNotFoundException e){
        e.printStackTrace();
    }catch (IOException e){
        e.printStackTrace();
    }
}

若此时method3()在其他方法中也被调用了,比如在main方法中被调用了,此时不会出现异常,因为在method3()中将异常干掉了。
image.png

就相当于method1()那里面有一只狼,method1解决不了,就抛出来,向method2求助,method2也不行,就向method3求助,method3将狼干掉了。

所以main方法里面不再提示有异常要处理。

但是,若此时在main方法里面调用的是method2(),还是需要处理一下这个异常的,因为method2()抛出了异常。

image.png

到main方法就相当于到头了,此时最好不要再抛出去了,下面的代码处理方式就不可取:

public static void main(String[] args) throws FileNotFoundException, IOException{
    method3();
    method2();
}

此时就是将问题抛给虚拟机了,虚拟机也没有方案,程序就会挂掉。整个进程就停掉了。

所以实在不行,就只能这样处理了:

public static void main(String[] args){
    method3();
    try {
        method2();
    }catch (FileNotFoundException e){
        e.printStackTrace();
    }catch (IOException e){
        e.printStackTrace();
    }
}

不要在main方法里面写throws。

🌱代码

package yuyi02;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

/**
 * ClassName: ThrowsTest
 * Package: yuyi02
 * Description:
 * 以编译时异常举例,运行时异常基本不做处理,直接改代码即可
 *
 * @Author 雨翼轻尘
 * @Create 2024/1/13 0013 7:52
 */
public class ThrowsTest {
    public static void main(String[] args){
        method3();
        try {
            method2();
        }catch (FileNotFoundException e){
            e.printStackTrace();
        }catch (IOException e){
            e.printStackTrace();
        }
    }

    public static void method3() {
        try {
            method2();
        }catch (FileNotFoundException e){
            e.printStackTrace();
        }catch (IOException e){
            e.printStackTrace();
        }
    }

    public static void method2() throws FileNotFoundException, IOException{
        method1();
    }

    public static void method1() throws FileNotFoundException, IOException {
        File file = new File("D:\\hello.txt");

        //可能报FileNotFoundException 文件找不到异常
        FileInputStream fis = new FileInputStream(file);  //流直接操作文件

        //把文件内容直接读到内存中输出
        int data = fis.read();    //可能报IOException 输入输出异常
        while (data != -1) {    //data为-1的时候退出,就是读完了
            System.out.print((char) data);
            data = fis.read();  //可能报IOException 输入输出异常
        }

        //资源关闭
        fis.close();  //可能报IOException 输入输出异常
    }
}

🎲问:是否真正处理了异常?

  • 编译是否能通过的角度看,看成是给出了异常万一要是出现时候的解决方案。此方案就是,继续向上抛出(throws)。
  • 但是,此throws的方式,仅是将可能出现的异常抛给了此方法的调用者。此调用者仍然需要考虑如何处理相关异常。从这个角度来看,throws的方式不算是真正意义上处理了异常。

2、案例2

package com.atguigu.keyword;

public class TestThrowsCheckedException {
    public static void main(String[] args) {
        System.out.println("上课.....");
        try {
            afterClass();//换到这里处理异常
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("准备提前上课");
        }
        System.out.println("上课.....");
    }

    public static void afterClass() throws InterruptedException {
        for(int i=10; i>=1; i--){
            Thread.sleep(1000);//本来应该在这里处理异常
            System.out.println("距离上课还有:" + i + "分钟");
        }
    }
}

(2)针对于运行时异常

throws后面也可以写运行时异常类型,只是运行时异常类型,写或不写对于编译器和程序执行来说都没有任何区别。如果写了,唯一的区别就是调用者调用该方法后,使用try…catch结构时,IDEA可以获得更多的信息,需要添加哪种catch分支。

package com.atguigu.keyword;

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

public class TestThrowsRuntimeException {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        try {
            System.out.print("请输入第一个整数:");
            int a = input.nextInt();
            System.out.print("请输入第二个整数:");
            int b = input.nextInt();
            int result = divide(a,b);
            System.out.println(a + "/" + b +"=" + result);
        } catch (ArithmeticException | InputMismatchException e) {
            e.printStackTrace();
        } finally {
            input.close();
        }
    }

    public static int divide(int a, int b)throws ArithmeticException{
        return a/b;
    }
}

四、 方法重写中throws的要求

(1)说明

方法重写时,对于方法签名是有严格要求的。复习:

1)方法名必须相同
(2)形参列表必须相同
(3)返回值类型
- 基本数据类型和void:必须相同
- 引用数据类型:<=4)权限修饰符:>=,而且要求父类被重写方法在子类中是可见的
(5)不能是staticfinal修饰的方法

当时说到方法的声明格式

权限修饰符 返回值类型 方法名(形参列表) [throws 异常类型] {
	//方法体 
}

方法在声明的时候,可能会抛出异常,关于父类被重写的方法和子类重写的方法,这里其实是有一个要求的:
子类重写的方法抛出的异常类型可以与父类被重写的方法抛出的异常类型相同,或是父类被重写的方法抛出的异常类型的子类


方法的重写的要求:(针对于编译时异常来说的)

子类重写的方法抛出的异常类型可以与父类被重写的方法抛出的异常类型相同,或是父类被重写的方法抛出的异常类型的子类

此外,对于throws异常列表要求:

  • 如果父类被重写方法的方法签名后面没有 “throws  编译时异常类型”,那么重写方法时,方法签名后面也不能出现“throws  编译时异常类型”。
  • 如果父类被重写方法的方法签名后面有 “throws 编译时异常类型”,那么重写方法时,throws的编译时异常类型必须 <= 被重写方法throws的编译时异常类型,或者不throws编译时异常。
  • 方法重写,对于“throws 运行时异常类型”没有要求。
package com.atguigu.keyword;

import java.io.IOException;

class Father{
    public void method()throws Exception{
        System.out.println("Father.method");
    }
}
class Son extends Father{
    @Override
    public void method() throws IOException,ClassCastException {
        System.out.println("Son.method");
    }
}

(2)举例1

比如现在Son是Father的子类:

public class OverrideTest {

}

class Father{
    public void method1(){

    }
}

class Son extends Father{
    @Override
    public void method1() {

    }
}

假设父类Father中抛出了一个IOException的异常。对于子类Son来说,也可以抛出和父类被重写方法一样的异常。如下:

public class OverrideTest {

}

class Father{
    public void method1() throws IOException {

    }
}

class Son extends Father{
    @Override
    public void method1() throws IOException{

    }
}

一般开发中,都这样写成一样的。

其实,子类Son中,还可以抛一个IOException子类,比如FileNotFoundException。如下:

public class OverrideTest {

}

class Father{
    public void method1() throws IOException {

    }
}

class Son extends Father{
    @Override
    public void method1() throws FileNotFoundException {

    }
}

子类能抛出父类重写方法的异常的子类,而不能是父类重写方法的异常的父类。

image.png


🎲为什么会有上面那样的规则呢?

前面说过一个知识点叫做“多态性”,在多态性的场景下,比如现在声明一个变量f,在右边new了一个子类的对象,如下:

public class OverrideTest {
    public static void main(String[] args) {
        Father f=new Son();
    }
}

然后通过f来调用method1(),此时method1()可能存在编译时异常,需要处理。

image.png

这时候,我们加一个try,将有可能出现异常的代码放入try中:

public static void main(String[] args) {
    Father f=new Son();
    try {
        f.method1();
    }
}

然后要在catch中写上可能出现的异常,这时候要看父类中的可能异常,因为编译的时候它认为调用的是父类的方法。所以此时要看父类中的IOException

如下:

package yuyi02;

import java.io.FileNotFoundException;
import java.io.IOException;

/**
 * ClassName: OverrideTest
 * Package: yuyi02
 * Description:
 *
 * @Author 雨翼轻尘
 * @Create 2024/1/13 0013 15:02
 */
public class OverrideTest {
    public static void main(String[] args) {
        Father f=new Son();
        try {
            f.method1();
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

class Father{
    public void method1() throws IOException {

    }
}

class Son extends Father{
    @Override
    public void method1() throws FileNotFoundException {

    }
}

真正运行的时候,实际调用的是子类的方法。调用了子类重写的method1()之后,抛出的异常不能比父类的大,要不然catch不了。
子类的方法在执行的时候抛出的异常父类异常的子类,那么子类的异常对象是可以进入try-catch中的,这其实也体现了多态性。

image.png

相当于实打实地new了一个FileNotFoundException的实例,这里认为是IOException,相当于赋给了IOException,也是多态。

所以子类最大抛出的异常要与父类的异常一样,也可以是父类异常的子类,但不能是父类异常的父类。

多态,编译看左边,运行看右边,但是想要调用子类独有的方法,需要将父类强转成子类才可以调用,俗称“向下转型”。

(3)举例2

若此时父类Father中有一个method2(),并没有声明throws异常。

然后子类Son要重写这个方法,里面有编译时异常,如下:

package yuyi02;

public class OverrideTest {
    public static void main(String[] args) {
        Father f=new Son();
        try {
            f.method1();
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

class Father{
    public void method2(){

    }
}

class Son extends Father{
    @Override
    public void method2() {

    }
}

这时候可以用throws吗?

不可以

因为在父类Father里面,它没有抛异常,或者是抛出的无穷小异常。所以子类里面也只能抛无穷小的异常,小到没有。

若此时试图去抛一个异常,就不可以,如下:

image.png

父类没有抛,子类就不能抛

若子类里面有异常,但是父类里面没有抛,此时子类就不可以抛异常出去,需要用try-catch-finally来解决。

🚗

以后会看到这样的场景,一个接口里面写了抽象方法,这个抽象方法后面还throws抛出了异常。既然抽象方法没有方法体,那怎么会有异常呢?

这是为了,当这个方法要被重写的时候,实现类重写这个方法可能要抛异常。

为了实现类可以抛异常,所以接口的抽象方法就抛了一个异常。

子类的异常不能大于父类的异常,父类没有抛异常子类就不能抛。


🍻补充1

现在说的异常都是编译器异常,父类没有抛,子类可以抛吗?

按道理是不能的。

但是,看下面的代码:

package yuyi02;

import java.io.FileNotFoundException;
import java.io.IOException;

class Father{
    public void method3(){

    }
}

class Son extends Father{
    @Override
    public void method3() throws RuntimeException{

    }
}

可以发现并没有报错:

image.png

因为对于“运行时异常”,写不写RuntimeException都无所谓。只有在运行的时候才会调用子类的方法。

编译时异常要是不处理,就会报错,比如:

image.png

所以需要处理一下这个编译时异常。若是代码中有运行时异常,在这里不会显示,不显示的话就不用处理。


🍻补充2

之前说“重写”的时候,提到过返回值类型,回顾一下:

关于返回值类型

  • 父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型必须是void。
  • 父类被重写的方法的返回值类型是基本数据类型,则子类重写的方法的返回值类型必须与被重写的方法的返回值类型相同。
  • 父类被重写的方法的返回值类型是引用数据类型(比如类),则子类重写的方法的返回值类型可以与被重写的方法的返回值类型相同 或 是被重写的方法的返回值类型的子类。

比如,此时父类的返回值是Number,就是包装类里面数值类型的父类,如下:

class Father{
    public Number method4(){
        return null;
    }
}

子类的返回值,可以是Number,也可以是Number的子类,比如Integer,如下:

class Son extends Father{
    @Override
    public Integer method4() {
        return null;
    }
}

此时用f调用method4,对于父类的方法来讲,返回的是Number,所以接收的时候用Number类型的来接收。实际执行的时候,却是子类重写的方法,这个方法可能返回的是方法子类的对象。

这里只是以一个多态的方式接收而已。(重写的方法里面不能是Number的父类,要不然接收不了)

如下:

public class OverrideTest {
    public static void main(String[] args) {
        Number n=f.method4();
    }
}

五、 两种异常处理方式的选择

前提:对于异常,使用相应的处理方式。此时的异常,主要指的是编译时异常。

🎲开发中,如何选择异常处理的两种方式?(重要、经验之谈)

  • 如果程序代码中,涉及到资源的调用(流、数据库连接、网络连接等),则必须考虑使用try-catch-finally来处理,保证不出现内存泄漏。
  • 如果父类被重写的方法没有throws异常类型,则子类重写的方法中如果出现异常,只能考虑使用try-catch-finally进行处理,不能throws。(父类没有throws,子类也不能throws)
  • 开发中,方法a中依次调用了方法b,c,d等方法,方法b,c,d之间是递进关系。此时,如果方法b,c,d中有异常,我们通常选择使用throws,而方法a中通常选择使用try-catch-finally

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/325411.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

当代大学生是怎么被废掉的?

中式教育以应试为核心&#xff0c;强调知识的灌输和学生被动接受。随着社会的发展&#xff0c;中式教育的短板逐渐显现&#xff0c;创新能力的缺乏、对记忆的过度依赖、忽视个体差异等问题日益突出。 建议所有大学生都能去看看《上海交通大学生存手册》&#xff0c;它道出了中…

AbstractHttpMessageConverter + easyexcell优雅下载附件

介绍 AbstractHttpMessageConverter 是 Spring 框架中用于处理 HTTP 消息转换的抽象基类。它用于处理来自 HTTP 请求的消息,并将其转换为特定的 Java 对象,或者将 Java 对象转换为 HTTP 响应消息。 这个抽象类允许开发人员创建自定义的 HTTP 消息转换器,以便在 Spring MVC…

如何提高发电机组带载能力

发电机组的带载能力是指其在一定时间内能够稳定运行的最大负载。提高发电机组的带载能力&#xff0c;不仅可以提高其工作效率&#xff0c;还可以延长其使用寿命。 优化发电机组的设计&#xff1a;通过改进发电机组的设计&#xff0c;可以提高其带载能力。例如&#xff0c;可以采…

MongoDB面试系列-01

1. MongoDB 是什么&#xff1f; MongoDB是由C语言编写的&#xff0c;是一个基于分布式文件存储的开源数据库系统。再高负载的情况下&#xff0c;添加更多的节点&#xff0c;可以保证服务器性能。MongoDB旨在给Web应用提供可扩展的高性能数据存储解决方案。 MongoDB将数据存储…

手把手教你学会接口自动化系列十五-如何用python操作excel的单元格自动化测试之前的准备工作

接上篇,我们都知道可以读取到sheet页了,下来就是读取sheet页下面的单元格数据 我们实践起来吧。 第一种方式是通过坐标的方式,比如我要取下面这个单元格的数据,如下: 这个数据位于Excel的B列第8行,所以对于excel来说就是坐标为B8。 代码如下: # !/usr/bin/env pytho…

LLM:Scaling Laws for Neural Language Models (中)

核心结论 1&#xff1a;LLM模型的性能主要与计算量C&#xff0c;模型参数量N和数据大小D三者相关&#xff0c;而与模型的具体结构 (层数/深度/宽度) 基本无关。三者满足: C ≈ 6ND 2. 为了提升模型性能&#xff0c;模型参数量N和数据大小D需要同步放大&#xff0c;但模型和数…

【生态适配】亚信安慧AntDB数据库与契约锁完成兼容互认

日前&#xff0c;亚信安慧AntDB数据库与上海亘岩网络科技有限公司&#xff08;简称:契约锁&#xff09;研发的契约锁电子签章产品完成兼容互认。经过双方团队的严格测试&#xff0c;亚信安慧AntDB数据库与契约锁&#xff08;V4&#xff09;完全兼容&#xff0c;整体运行稳定高效…

一天吃透Spring面试八股文

目录&#xff1a; Spring的优点Spring 用到了哪些设计模式&#xff1f;什么是AOP&#xff1f;AOP有哪些实现方式&#xff1f;Spring AOP的实现原理JDK动态代理和CGLIB动态代理的区别&#xff1f;Spring AOP相关术语Spring通知有哪些类型&#xff1f;什么是IOC&#xff1f;IOC的…

L1-027 出租(Java)

下面是新浪微博上曾经很火的一张图&#xff1a; 一时间网上一片求救声&#xff0c;急问这个怎么破。其实这段代码很简单&#xff0c;index数组就是arr数组的下标&#xff0c;index[0]2 对应 arr[2]1&#xff0c;index[1]0 对应 arr[0]8&#xff0c;index[2]3 对应 arr[3]0&…

鸿蒙开发之手势Pan

Entry Component struct OfficialPanGesturePage {State message: string 默认只左右移动State offsetX: number 0State offsetY: number 0State positionX: number 0State positionY: number 0//默认pan的参数&#xff0c;1根手指&#xff0c;左右方向private panOption:…

什么是泛域名证书?有免费的吗?

泛域名证书&#xff08;Wildcard SSL Certificate&#xff09;是一种用于加密多个子域名的SSL证书。与传统的SSL证书只能覆盖单个域名或特定子域不同&#xff0c;泛域名证书具有更广泛的适用性&#xff0c;可以涵盖一个域名下的所有子域。 泛域名证书的主要特点是通配符&#x…

华为数通方向HCIP-DataCom H12-831题库(判断题:1-20)

第01题 为了加快IS-IS网络中链路故障的感知速度,可以将IS-IS与BFD联动 正确 错误 答案:正确 解析: OSPF和IS-IS都可以设置与BFD联动加速链路故障检测 ,使用BFD时,可以实现毫秒级别的链路切换,所以使用IS–IS与BFD联动,可以加快IS–IS的感知速度 第02题 在OSPF中ABR会将…

关于整型提升与截断的一道题目

关于整型提升与截断&#xff0c;可以看我的博客 C语言&#xff1a;整型提升_c语言整形提升-CSDN博客 C语言&#xff1a;截断整型提升算数转换练习_c语言unsigned-CSDN博客 一、题目 二、题解 char a101截断 由于101是整型数据&#xff0c;需要32比特位存储空间&#xff0c;…

1.12号网络

1 网络发展历史 1.1 APRAnet阶段 阿帕网&#xff0c;是Interne的最早雏形 不能互联不同类型的计算机和不同类型的操作系统 没有纠错功能 1.2 TCP/IP两个协议阶段 什么是协议 在计算机网络中&#xff0c;要做到有条不紊的交换数据&#xff0c;需要遵循一些事先约定好的规则…

Java多线程并发篇----第十六篇

系列文章目录 文章目录 系列文章目录前言一、线程等待(wait)二、线程睡眠(sleep)三、线程让步(yield)四、线程中断(interrupt)五、Join 等待其他线程终止前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这…

【java八股文】之JVM基础篇

【java八股文】之JVM基础篇-CSDN博客 【java八股文】之MYSQL基础篇-CSDN博客 【java八股文】之Redis基础篇-CSDN博客 【java八股文】之Spring系列篇-CSDN博客 【java八股文】之分布式系列篇-CSDN博客 【java八股文】之多线程篇-CSDN博客 【java八股文】之JVM基础篇-CSDN博…

CentOS7安装MySQL 错误:软件包:akonadi-mysql-1.9.2-4.el7.x86_64 (@anaconda)

问题如图所示 运行一下命令解决 yum -y remove mariadb-libsyum install mysql-community-server

Linux知识(未完成)

一、Linux 1.1 Linux 的应用领域 1.1.1 个人桌面领域的应用 此领域是 Linux 比较薄弱的环节但是随着发展&#xff0c;近几年 linux 在个人桌面领域的占有率在逐渐提高 1.1.2 服务器领域 linux 在服务器领域的应用是最高的 linux 免费、稳定、高效等特点在这里得到了很好的…

Python读取modbus数据(WTVB01-485振动传感器)

Python读取modbus数据&#xff08;WTVB01-485振动传感器&#xff09; 实物如下图&#xff1a; 参考手册上获取到的部分信息&#xff1a; 接下来开始操作&#xff1a; 1.将485转USB口连接到计算机&#xff0c;然后使用&#xff1a;Modbus Poll这个软件与实物通讯。这里注意&a…

防泄密之巅,厨电安全无忧:迅软DSE引领科技保密新潮流

客户简要介绍 某股份有限公司从创立至今一直专注厨电领域&#xff0c;始终以产品创新为企业战略重心&#xff0c;为全家万户提供厨卫及家居定制。公司产品涵盖集成烹饪中心、抽油烟机、燃气灶具、燃气热水器、电热水器&#xff0c;为全球多个国家和地区的消费者提供高品质的服…