能导致3.7亿美元损失的异常,到底是怎么回事?

1996年6月,阿丽亚娜5号火箭进行了第一次发射。火箭发射后37秒自毁,导致任务失败,损失约3.7亿美元。故障调查小组最终发现,是由数据转换而导致整数溢出造成的异常。由此看来,提前预判出异常并进行处理对于系统的正常运行是多么重要。

不管是小白还是大神,异常总是程序员无法避免的一个话题。尤其是刚入门编程的程序员,一出现异常就不知道如何应对,非常容易慌乱。

那么什么时候才会出现异常呢?只有在当前的环境下程序无法正常运行下去,程序已经无法来正确解决问题了,异常才会从当前环境中跳出来。在实际编程中,异常出现的情形总是不期而至:文件不存在或者格式不对、网络连接失败、内存或硬盘满了等等。

一、异常的体系

首先我们可以明确一点,就是异常的处理机制可以确保我们程序的健壮性,提高系统可用率。虽然我们不是特别喜欢看到它,但是我们不能不承认它的地位和作用。接下来,我们先通过一张图来了解下Java异常的体系结构。

从上面这幅图可以看出,Java标准库内建了一些通用的异常,Throwable是这些类的顶层父类。Throwable又派生出Error和Exception。

Error及其子类代表非程序异常,不能被程序员通过代码处理。由于Error一般是系统性的错误,当出现这些异常时,Java虚拟机(JVM)一般会选择终止线程,所以程序员不用试图去捕获Error引发的异常状况。

Exception及其子类代表程序本身可以捕获并且可以处理的异常。可以被Java异常处理机制使用,是异常处理的核心。根据编译器对异常的检查情况,又将Exception的子类分为运行时异常(RuntimeException)和编译期异常(CheckedException)。

运行时异常:在编译期不会提示和发现这样的异常,这样的异常发生的原因多半是代码写的有问题,比如:使用了空对象而引发的NullPointerException。对于RuntimeException这样的异常,我们应该修正代码来进行处理。

编译期异常:都是可以在编译阶段被处理的异常,比如:可能会产生I/O错误时的IOException。Java认为CheckedException都是可以在编译阶段被处理的异常,所以程序会强制要求预先处理所有的CheckedException,否则编译不会通过。

二、异常的处理

编程语言觉得尽量在程序员犯错的时候“恶心”一下程序员,“逼着”他们去处理异常。Java异常的处理主要依赖于try、catch、finally、throws、throw这五个关键字,一般来说我们会使用try…catch…finally语句块进行异常处理,或者在方法签名中使用throws 声明,“不负责任的”的让方法调用者自己去解决。

1.异常“终结者”try,catch

使用try-catch语句块可以捕获异常并进行处理,try-catch-finally的常规语法如下:

try{

//可能会出现异常的程序代码 

语句1;

语句2;

语句3;

}catch(异常类型 e) {

//捕获并处理异常或者使用throw抛出异常

}finally{

//必执行的代码

}

语句4;

语句5;

当try代码块中没有出现异常时:try语句块中的语句逐一被执行,程序将跳过catch语句块,执行finally语句块和其后的语句。

当try代码块中出现异常时:try语句块中的异常语句之后的代码将被忽略,程序将直接跳到catch语句块。

如果catch语句块中捕获到了异常进行处理,会在catch语句块执行后接着执行finally语句块和其后的语句。如果没有捕获到异常或者使用throw抛出了异常,在catch语句块执行后接着只会执行finally语句块,但finally语句块后的语句不会被执行。

2.“不负责任”的throws

throws是另一种处理异常的方式。如果方法内没有捕获和处理异常,而是通过throw抛出了编译期异常,那么必须通过throws进行声明。throws运用于方法声明之上,表示当前方法不处理异常,而是提醒该方法的调用者来处理异常。

声明异常格式如下:

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

采取这种异常处理的原因可能是:方法本身不知道如何处理这样的异常,或者说让调用者处理更好,调用者需要为可能发生的异常负责。

3.自定义异常

在复杂业务环境下,Java自带的异常可能满足不了我们业务的需求,这个时候我们可以自定义异常来进行对业务异常的处理。自定义异常都应该继承Exception基类,如果希望自定义运行时异常,则应该继承RuntimeException。

定义自定义异常时通常需要提供2种构造器:一个是无参数的构造器;另一个是带一个字符串参数的构造器,这个字符串将作为该异常对象的详细说明。语法格式如下:

public class Register Exception extends Runtime Exception {

/*** 空参构造 */

public Register Exception() {  

  } /**** @param message 表示异常提示 */

public Registe rException(String message) {

super(message);   

 }

}

作为一名合格的程序员,我们不仅需要学会如何挑选格子衬衫,还需要在疯狂的coding中锻炼出更多的肌肉,以便随时应对前来改需求的产品经理,更重要的就是要做到对常见异常有一些印象,在真正遇到时知道去哪找API并且优雅的处理掉异常。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值