Java总结坚持一百天3--java错误处理(异常)

1、什么是异常?
2、异常如何分类?
3、如何声明受检查异常?
4、如何抛出异常?
5、如何创建异常类?

-------------------------------------------什么是异常?-----------------------------------------------------------
异常是java中的一种错误处理机制。

在理想的状态下,用户输入数据格式永远是正确的,选择打开的文件也一定存在,并且永远不会有bug出现。请记住这是理想状态下。就像我们之前学习的物理知识理想状态下,可以套用简单的公式就可以计算出结果,但是在现实中并不是理想状态会有摩擦力,风阻等等因素,这就需要我们按照实际情况去分析。在实际情况中用户输入的数据可能格式不对,或者用户想要上传的文件不存在等等。如果遇到不理想状态我们该怎么去做呢?没有反馈显然是不合理的,如果因为一点点的数据问题或者文件不存在的问题导致整个系统的瘫痪就更不合理了,于是,强大的JAVA语言的开发者们引入了异常处理(异常处理并不是在java才出现的,在产生JAVA语言之前C++,smalltalk,Delphi早就已经使用该错误处理理念)。

假设在一个java程序运行期间出现了一个错误。这个错误可能是文件包含了错误信息,或者网络连接出现问题造成的,也有可能是因为使用无效的数组下标,或者试图使用一个没有被赋值的对象造成的。用户期望在出现错误时,程序能够采用一些理智的行为。如果出现错误而使得某些操作没有完成,程序应该:
1、返回一种安全状态,并能够让用户执行一些其他指令;或者
2、允许用户保存所有操作的结果,并以妥善的方式终止程序。

要做到这些并不是一件很容易的事情。其原因是检测(或引发)错误条件的代码通常离那些能够让程序恢复到安全状态,或者是能够保存用户的操作结果,并正常退出代码很远。异常处理的任务就是将控制权从错误产生的地方转移给能够处理这种情况的错误处理器。

为了在程序中处理异常情况,必须研究程序中可能出现的错误和问题,以及哪类问题需要关注:
1、用户输入错误
除了那些不可避免的键盘输入错误外,有些用户喜欢各行其是,不遵循程序的要求。例如,假设一个用户请求一个url,如果网址不对浏览器会提示错误信息,如果uri不对服务器会返回404页面不存在,如果没有权限会返回您没有此操作权限等等。
2、设备错误
硬件不总是让他做什么,他就做什么。打印机能被关闭,网页可能临时性的不能浏览,在一个任务处理的过程中,硬件可能会出现问题。例如,在打印过程中打印机没有纸了,打印机会返回一个没有纸的信号,那么java程序接受到这个信号之后应该保存现在的状态,并提示用户给打印机续纸,当打印机有纸了之后继续打印。
3、物理限制
磁盘满了,可用的存储空间已经用完。
4、代码错误
程序方法有可能无法正常执行。例如,方法可能返回了一个错误的答案,不符合程序需要或者正常逻辑,或者错误的调用了其他方法。计算的数组索引不合法,试图在三列表中查询一个不存在的记录,或者试图让一个空战执行弹出操作,这些都属于代码错误。

对于方法中的一个错误,传统的做法是返回一个特殊的错误码,由调用方法分析。例如,对一个从文件中读取信息的方法来说,返回值通常不是标准字符,而是-1,表示文件读取结束。这种处理方式对很多异常异常状况都是可行的。还有一种表示错误状况的返回值是null引用。

遗憾的是不是任何时候都可以返回一个错误码。有可能无法明确地将有效数据与无效数据加以区分。一个返回整型的方法就不能简单的返回-1表示错误,因为-1很能就是一个合法的结果。

如果一个方法不能够采用正常的途径完成他的任务,就可以通过另外一个途径退出方法。这种情况并不返回任何值,而是抛出throw一个封装了错误信息的对象。需要注意的是,这个方法将会立刻退出,并不返回任何值。此外,调用这个方法的代码也将无法继续执行,取而代之的是,异常处理机制开始搜索能够处理这种异常状况的异常处理器(exception handler)。

异常具有自己的语法和特定的继承结构。

--------------------------------------------异常如何分类?-----------------------------------------------------------
在java中,异常对象都是派生与Throwable类的一个实例。如果java中内置的异常不能够满足需求,用户可以创建自己的异常类。
在这里插入图片描述
需要注意的是,所有的异常都是由Throwable继承而来,但是在下一层即分为两个分支:Error和Exception。

Error类层次结构描述了Java运行时系统的内部错误和资源耗尽错误。应用程序不应该抛出这种类型的对象。如果出现这样的内部错误,除了通告给用户,并尽力使用程序安全的终止之外,再也无能为力了。这种情况很少见。

在设计java程序时,需要关注Exception层次结构。这个层次结构又分为两个分支:一个分支派生于RuntimeException;另一个分支包含其他异常。划分两个分支的规则是:有程序错误导致的异常属于Runtime Exception;而程序本身没有问题,由于向I/O错误这类问题导致的异常属于其他异常。

派生于RuntimeException的异常包含下面几种情况:

  1. 错误的类型转换
  2. 数组访问越界
  3. 访问null指针

不是派生于RuntimeException的异常包括:

  1. 试图在文件尾部后面读取数据
  2. 试图打开一个不存在的文件。
  3. 试图根据戈丁的字符串查找class对象,而这个字符串表示的类并不存在。

如果出现RuntimeException异常,那么就一定是你的问题,是一条相当有道理的规则。

用该通过检测数组下表是否越界来避免ArrayIndexOutofBoundsException异常;应该通过在使用变量之前检测是否为null来杜绝NullPointException异常的发生。

如果处理不存在的文件呢?难道不能先检查文件是否存在再打开它吗? 这个文件有可能在你检查他是否存在的之前就被删除了。 因此,“是否存在”取决于环境,而不是取决于你的代码。

java语言规范将派生于Error类或者RuntimeException类的所有异常成为非受检查(unchecked)异常,其他所有异常成为受检查(Checked)异常。这是两个很有用的术语,在会用到。编译器将核查是否为所有的受检查异常提供了异常处理。

--------------------------------------------如何声明受检查异常?-----------------------------------------------------------
如果遇到了无法处理的情况,那么java的方法可以排除一个异常。这个道理很简单:一个方法不仅需要告诉编译器将要返回什么值,还要告诉编译器还会发生什么错误。 例如,一段读取文件的代码知道有可能读取的文件不存在,或者内容为空,因此,试图处理文件细信息的代码就需要通知编译器可能会抛出IOException类的异常。

方法应该再其首生命所有可能抛出的异常。这样可以从首部反映出这个方法可能抛出那些受检查异常。例如,下面是标准类库中提供的FileInputStream类的一个构造器的声明。

public FileInputStream(String name) throws FileNotFoundException

这个声明表示这个构造器将根据给定的String参数生产一个FileInputStream对象,但也有可能抛出一个FileNotFoundException异常。如果发生了这种糟糕情况,构造器将不会初始化一个新的FileInputStream对象,而是抛出一个FileNotFoundException类对象。如果这个方法真的抛出了这样一个异常对象,运行时系统就会开始搜索异常处理器,以便知道如何处理FileNotFoundException对象。

在自己编写方法时,不必将所有可能抛出的异常都进行声明。至于什么时候需要在方法中用throws子句声明,需要记住在遇到下面4种情况是应该抛出异常:

  1. 调用一个抛出受检查异常的方法,例如FileInputStream构造器。
  2. 程序运行过程中发现错误,并且利用throw语句抛出一个受查异常
  3. 程序出现错误,例如 a[-1] = 0 会抛出一个ArrayIndexOutofBoundsException这样的非受检查异常。
  4. Java虚拟机和运行时库出现的内部错误

--------------------------------------------如何抛出异常?-----------------------------------------------------------
假设在程序代码中发生了一些很糟糕的事情。一个名为readData的方法正在读取一个首部具有下列信息的问价

Content-length:1024

然而读到733个字符之后文件就结束了。我们认为这是一种不正常的情况,希望跑出一个异常。
首先要决定应该抛出什么样的异常。将上述异常归结为IOException是一种很好的选择。仔细的阅读Java API文档之后发现:EOFException异常描述的是“在输入过程中,遇到了一个未预期的EOF后的信号”。这正是我们要抛出的异常。下面是抛出异常的语句:

throw new EOFException()

或者

EOFException e = new EOFException();
threw e;

下面将这些代码放在一起:

String readData(Scanner in) throws EOFException
{
	……
	while(……){
		if(!in.hasNext)   //EOF encountered
		{
			if(n<len)
					throw new EOFException();
		}
		……
	}
	return s;
}

EOFException类还有一个含有一个字符串型参数的构造器。这个构造器可以更加细致描述异常出现的情况。

String gripe = "Content-length"+len++",Received:"+n;
throw new EOFException(gripe);

在前面已经看到,对于一个已经存在的异常类,将其抛出非常容易。在这种情况下:
1)找到一个合适的异常类
2)创建这个类的一个对象
3)将对象抛出

一旦方法抛出异常,这个方法就不可能返回到调用者。也就是说,不必为返回的默认值或者错误代码担忧。

--------------------------------------------如何创建异常类-----------------------------------------------------------
在程序中,可能会遇到任何标准异常类都没有能够充分的描述清楚的问题。在这种情况下,创建自己的异常类就是一件顺理成章的事情。我们需要做的只是定义一个派生于Exception子类的类。例如,定义一个派生于IOException的类。习惯上,定义的类应该包含两个构造器,一个是默认构造器;另一个是带有详细描述信息的构造器(超类Throwable的toString方法将打印出这些详细信息,这在调试中非常有用)。

class FileFormatException extends IOException
{
	public FileFormatException (){}
	public FileFormatException (String gripe){
		super(gripe)
	}
}

现在就可以抛出自己定义的异常类型了。

  String readData(Scanner in) throws FileFormatException 
    {
    	……
    	while(……){
    		if(!in.hasNext)   //EOF encountered
    		{
    			if(n<len)
    					throw new FileFormatException ();
    		}
    		……
    	}
    	return s;
    }

java.lang.Throwable
  • Throwable(),构造一个新的Throwable对象,这个对象没有详细地描述信息
  • Throwable(String
    message),构造一个新的throwable对象,这个对象带有特定的详细表述信息。习惯上,所有炮声的异常类都支持一个默认的构造器和一个带有详细信息的构造器。
  • String getMessage(),获得Throwable对象详细描述信息。

参照 – Java技术 卷I

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值