前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【JavaSE】异常

【JavaSE】异常

作者头像
鸡先生
发布2022-10-29 17:15:05
3400
发布2022-10-29 17:15:05
举报
文章被收录于专栏:鸡先生鸡先生

异常的介绍

异常,顾名思义,就是指非正常的,在预期之外的情况。

生活中:比如邮寄一个快递可收件人联系不上,这就是生活中的一个异常。

image
image

程序中:在程序运行过程中,各种异常稍不注意就会发生,从而影响程序的正常流程

image
image

常见异常如:

  • 文件找不到
  • 网络连接失败
  • 用户输入了非法数据。

注意:异常指的是在程序运行中出现的错误,而不是语法问题导致的编译错误。

异常的分类

在Java的面向对象世界中,异常当然也是对象,众多的异常对象就描述了各种不同的异常情况。

image
image

Java 的异常有一个顶层父类Throwable,所以的异常都继承自它,在Throwable下又分两大类,一个是 Error,一个是 Exception。

Error类即其子类是指我们程序处理不了或者说不该由程序处理的错误。 这里的错误往往代表JVM在运行过程中出了问题,比如:栈溢出错误、内存不足错误

Exception类即其子类是指程序中可以处理的异常,我们平时最常打交道的就是这种异常。 它下面又分为两大类:

  • 一类是RuntimeException类和其子类
  • 一个是非RuntimeException类

这两种类型的区别就是:

  • RuntimeException 类型不强制你手动处理,比如我们最常见的空指针异常,你无需 try...catch 也无需 throws 代码也能编译成功
  • 非RuntimeException 类的异常如果你不手动处理则会编译失败比如IO异常。

这里延伸出一个概念:那就是受检异常和非受检异常。顾名思义受检异常就是必须手动处理的异常,非受检异常就是不强制程序处理的异常。除了 RuntimeException 外。Error 也属于非受检异常

异常的处理方式

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

try...catch 它就是我们常说的捕获异常

代码语言:javascript
复制
// 可以 catch一个也可以 catch多个
try{
    // 可能会发现异常的逻辑
} catch(IOException e){
    // 发生 IOexception时,执行此代码块
} catch(ClassNotFoundException e){
    // 发生 ClassNotFoundException时,执行此代码块
} catch(Exception e){
    // 发送其他异常时,执行此代码块
    // 父类异常应该放在子类异常后面,否则子类异常不会被捕获
}

我们可以将可能发送异常的代码,放到 try 代码块中,然后使用 catch来捕获对应的异常。如果 try 代码块正常执行,那 catch就不会生效。如果发生了指定的异常,则会执行对应的catch代码块,然后继续往下执行,如此一来,我们就能避免异常影响到我们的正常逻辑

捕获异常时还可以接上finally 代码块,无论发布发生异常finally 代码块都会执行

throws 处理try...catch外还可以使用 throws来处理异常,在方法上使用 throws关键字可以声明该方法可能抛出的异常

代码语言:javascript
复制
// 可以 throws声明一哥异常,也可以声明多个
public static void process() throws IDException,ClassNotFoundException{
    // 可能发送异常的逻辑
}

当我们调用一个方法时,如果这个方法用 throws关键字声明了受检异常

代码语言:javascript
复制
public static void process() throws IOException,ClassNotFoundException{
    // ...
}

public static void f1(){
    process();// 编译失败,因为没有处理受限异常
}

public static void f2(){
    try {
	process();//编译成功
    } catch (IOException | ClassNotFoundException e){
	// ...
    }
}

public static void f3() throws IOException,ClassNotFoundException{
    process();// 编译成功
}

此时我们就必须得手动处理它声明的异常,否则就会编译失败。要么你就 try...catch要么你就在当前方法使用 throws声明同样的或其父类异常。

这里其实就可以体现出throws的作用了

image
image

那就是我不想处理这个异常时,我可以把问题往外抛,谁调用我谁就来处理,就好像在工作中出现了一个问题:你可以选择将这个问题自行解决,也可以将这个问题丢给你的上级解决,而你的上级碰到问题时,也会面临同样的选择:要么他自己解决,要么他将问题抛给更上级。

如果一个问题或者是一个异常,发生后就一直往上抛。

代码语言:javascript
复制
public static void main(String[] args)throws Exception
{    // 如果发生异常,则程序终止
}

到最顶层的main 方法了都没人去try...catch 解决,那程序就会终止运行

调用时机 一个很简单的原则:

代码语言:javascript
复制
try{
    process();
} catch (Exception e){
    // ...
}

// 上面发送异常,这里也能执行
xxx();

如果当前方法需要继续运行下去,就肯定得用 try...catch,当前方法不需要继续运行就可以选择throws

建议:尽量选择捕获异常

异常必须丢给上一层去解决,这种情况毕竟在少数。 这也是为什么在设计自定义异常时都强烈建议继承RuntimeException,因为这会让你省去很多麻烦

自定义异常

Java 标准库中提供了非常多的异常类型,用来表达各种异常情况。

代码语言:javascript
复制
public class MyException extends RuntimeException{
    public MyException() {
    }

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

    public MyException(String message,Throwable cause) {
	super(message,cause);
    }

    public MyException(Throwable cause) {
	super(cause);
    }
}

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

只要主动继承异常类就可以定义我们自己的异常,上面说过强烈建议大家继承 RuntimeException 在自定义异常时,还强烈建议大家照着父类学习,提供多个构造方法,这样就可以传递错误信息和堆栈信息

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

代码语言:javascript
复制
thorow new MyException();// 直接抛出异常
thorow new MyException("程序崩溃");// 抛出异常的同时,传递异常信息
thorow new MyException(new NullPointerException());// 抛出异常的同时,传递其他异常的堆栈信息

注意:thorw和 thorws关键字只有一个字母之差不要弄混

throw

throws

位置

代码块中

方法声明上

作用

主动制造并抛出异常

方法声明上

作用位置

代码块中

声明方法可能会发送的异常

image
image

主动抛出异常

代码语言:javascript
复制
public static void process(String arg) {
    // ...业务逻辑
}

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

  • 第一种做法就是给参数设置一个默认值,然后继续执行后续逻辑
代码语言:javascript
复制
public static void process(String arg) {
    if(arg == null) {
       arg = "默认值";
    }
    //  ...继续执行业务逻辑
}
// 就好像你非法进入一个地方,保安发现了你,不光没赶你走还贴心地给了你一个身份牌,让你可以继续前行
  • 第二种做法就是直接结束方法,不执行后面逻辑,这里还可以返回不同的值,来表达方法执行的结果
代码语言:javascript
复制
    public static boolean process(String arg){
	if(arg == null){
	   return false;
	}
	// ...业务逻辑
	return true;
    }
	// 就好像保安发现了你,就不让你继续前进了
  • 第三种做法就是直接抛出异常
代码语言:javascript
复制
    public static void process(String arg) {
	if(arg == null) {
	   throw new MyException();
	}
	// ...业务逻辑
    }
	//这个就比较猛了,就好像保安发现了你,不光不让你继续前进,还把你打了一顿。
	//要是你没有捕捉异常,你就会被保安打到shi(程序终止)

使用情况

如果遇到了会影响正常逻辑的情况,基本就这三大类处理方式

image
image

知道各个方式的特点后,其实就能根据自己的需求,来做响应的处理了。

  • 如果问题能够解决,并且你也愿意解决,那就让逻辑继续执行
  • 如果问题无法解决,或者你不愿解决,但又不至于抛哥异常给调用者,就可以直接结束方法
  • 如果问题非常严重,严重到需要警告调用者,就可以抛出异常
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-04-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 异常的介绍
  • 异常的分类
  • 异常的处理方式
  • 自定义异常
  • 主动抛出异常
  • 使用情况
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档