Notes: Exceptions in Java(Java中的异常处理)

Java的异常机制是Java作为一门高级语言比C和其他早期语言先进的地方。通过在方法声明异常和在方法抛出异常的方法,可以大大增强程序的鲁棒性。具体体现在:


C和其它早期语言反映运行时出现错误通常通过让方法(函数)返回某个特殊值(最常用的是-1)或者修改某个全局变量(flag)的值表示出现错误。所以,如果出现错误的时候,由调用方法的客户端程序员负责写问题的处理方法。这样做的话有几点弊端:

1) 如果函数确实要返回-1这个正确的值时就会出现混淆;

2) 可读性降低,将程序代码与处理异常的代码混爹在一起(需要在代码中加上if判断返回是否是-1,是的话需要错误处理代码);

3) 由调用函数的程序来分析错误,这就要求客户程序员对库函数有很深的了解;同时,需要客户端程序员去留意全局变量的变化,所以客户端程序员更倾向于:对,错误也许发生了,但那是别人造成的错误,不关我事。继而忽略错误。


于是Java提出利用try... catch的结构实现的异常机制的机制来解决上述问题:

1) 利用try.. catch分离正常程序代码和异常处理代码;

2)由库程序的程序员在方法的声明处声明可能抛出(出现)什么样的异常,让客户端程序员能确切知道写什么样的代码能捕获潜在的异常。如果写的方法代码中有可能产生异常,但库函数的程序员却没有自己用try... catch处理,此时,Java编译器就强制库函数的程序员做出选择,要么写try... catch来处理异常,否则声明有可能出现什么异常。这种在编译的时候会被检查的异常称为被检查的异常(checked exception)。声明语法如下:

void f() throws TooBig, TooSmall { //... 

}

但是要是这么写:

void f(){

}

表示此方法不会抛出任何异常。但是除了从RuntimeException继承的异常,它们可以在没有异常声明的情况下被抛出。


但是,需要注意的是,可以声明方法将抛出异常却不抛出的做法是允许的。这就涉及到一种良好的抽象基类/ 接口的编写方法:

为将来的派生类/ 实现接口能抛出这些已经在抽象基类/ 接口声明的异常,就在抽象基类/ 接口声明处加上异常抛出声明。


下面这张图来自:http://www.diycode.cc/topics/208,很好地描述了Java异常类的族谱:




Error类描述了Java运行系统中的内部错误以及资源耗尽的情形(如:java.lang.OutOfMemoryError)。编写程序不应该抛出这种类型的对象(一般是由JVM抛出)。如果出现这种错误,除了尽力使程序安全退出外,在其他方面是无能为力的。所以,在进行程序设计时,应该更关注Exception体系。


RuntimeException的出现是由于在编译时期的语义分析阶段存在未被发现的错误,大部分的RuntimeException都是程序员疏忽造成的。常见的有:


1)java.lang.NullPointerException

"程序遇上了空指针",简单地说就是调用了未经初始化的对象或者是不存在的对象。如,创建了引用之后没有采用new调用构造器来初始化对象;或者创建了数组的名称后,没有使用new来初始化数组的内容;或者创建了一个基本类型变量忘了赋值。这里重新温故一个概念:凡是用new初始化的东西都是存在堆中(包括数组),而直接声明的名称或者基本类型的直接声明初始化都是采取“自动存储原则”。如果在对象的局部方法中声明的,则是存在于栈。否则,在类声明中的成员变量,存在于堆。


2) java.lang.NumberFormatException:继承java.lang.IllegalArgumentException,字符串转换为数字时出现。比如int i= Integer.parseInt("ab3");

在数据类型转换过程中,如果是字符型转换为数字型过程中出现的问题,对于这个异常在Java程序中采用了一个独立的异常,即NumberFormatException。


3) java.lang.ArithmeticException:这个异常的解释是"数学运算异常",比如程序中出现了除以零这样的运算就会出这样的异常。


4) java.lang.ClassCastException:类型转换错误。比如 Object obj=new Object(); String s=(String)obj; 

在Java应用程序中,有时候需要对数据类型进行转换。这个转换包括显示的转换与隐式的转换。不过无论怎么转换,都必须要符合一个前提的条件,即数据类型的兼容性。如果在数据转换的过程中,违反了这个原则,那么就会触发数据类型转换异常。例如,当客户输入的日期只有月和日的时候,如果强制把输入的数据变为date类型就会报这个错误。属于开发的低级错误,需要通过输入检查来避免。简而言之,数据类型进行转换之前,就保证数据类型的兼容性。如此的话,就不容易造成数据类型的转换异常。如在只允许数值类型的字段中,可以设置不允许用户输入数值以外的字符。


5) java.lang.IllegalArgumentException
这个异常的解释是"方法的参数错误",比如g.setColor(int red,int green,int blue)这个方法中的三个值,如果有超过255的也会出现这个异常,因此一旦发现这个异常,我们要做的,就是赶紧去检查一下方法调用中的参数传递是不是出现了错误。


6)java.lang.IndexOutOfBoundsException

这个异常还有两个常见的子异常类型。ArrayIndexOutOfBoundsException, StringIndexOutOfBoundsException。指示某序列(例如数组、字符串或向量)的访问超出其定义的大小范围时抛出。前者是:用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引。后者是:指示索引或者为负,或者超出字符串的大小。对诸如 charAt 的一些方法,当索引等于字符串的大小时,也会抛出该异常。


7)java.lang.ArrayStoreException

试图将错误类型的对象存储到一个对象数组时抛出的异常。例如,以下代码可生成一个 ArrayStoreException

Object x[] = new String[3];

x[0] = new Integer(0);


8)java.lang.UnsupportedOperationException


该对象的类不支持所调用的方法。例如使用Arrays.asList方法生成的list不能使用add()和remove()。如果在代码中调用这些方法就会产生这类异常。


Checked Exceptions中,有以下几个常见的:

关于类的加载/ 克隆/ 实例化:

1)java.lang.ClassNotFoundException
当应用程序试图使用以下方法通过字符串名加载类时,抛出该异常。
Class 类中的 forName 方法。
ClassLoader 类中的 findSystemClass 方法。
ClassLoader 类中的 loadClass 方法。
但是没有找到具有指定名称的类的定义。


2)java.lang.CloneNotSupportedException
当调用 Object 类中的 clone 方法复制对象,但该对象的类无法实现 Cloneable 接口时,抛出该异常。
重写 clone 方法的应用程序也可能抛出此异常,指示不能或不应复制一个对象。


3)java.lang.InstantiationException
当应用程序试图使用 Class 类中的 newInstance 方法创建一个类的实例,而指定的类对象无法被实例化时,抛出该异常。实例化失败有很多原因,包括但不仅限于以下原因:
类对象表示一个抽象类、接口、数组类、基本类型、void
类没有非 null 构造方法(或者类的构造函数是private的)


4)java.lang.IllegalAccessException
这个异常的解释是"没有访问权限",当应用程序要调用一个类,但当前的方法即没有对该类的访问权限便会出现这个异常。对程序中用了Package的情况下要注意这个异常

关于并发编程:


5)障碍:java.util.concurrent.BrokenBarrierException
当某个线程试图等待处于断开状态的 barrier 时,或者 barrier 进入断开状态而线程处于等待状态时,抛出该异常。


6)中断:java.lang.InterruptedException
当线程在活动之前或活动期间处于正在等待、休眠或占用状态且该线程被中断时,抛出该异常。有时候,一种方法可能希望测试当前线程是否已被中断,如果已被中断,则立即抛出此异常。下列代码可以达到这种效果:


  if (Thread.interrupted())  // Clears interrupted status!
      throw new InterruptedException();


7)阻塞:java.util.concurrent.TimeoutException

阻塞操作超时时,抛出该异常。对于指定超时的阻塞操作来说,需要一种指示发生超时的方法。多数这样的操作可能返回一个值指示超时;当不可能或不需要返回超时值时,将声明并抛出 TimeoutException。


关于调用类的数据成员和方法:


8)方法:java.lang.NoSuchMethodException
无法找到某一特定方法时,抛出该异常。


9)数据成员:java.lang.NoSuchFieldException
类不包含指定名称的字段时产生的信号。


与MySQL交互:


10)java.sql.SQLException


提供关于数据库访问错误或其他错误信息的异常。现在的Java应用程序大部分都是依赖于数据库运行的。在Java应用程序中,所有数据库操作发生异常时,都会触发这一个类。所有此时Java应用程序本身的提示信息往往过于笼统,只是说与数据库交互出现错误,没有多大的参考价值。此时反而是数据库的提示信息更加有使用价值,将数据库的错误信息通过这个类显示给用户(利用getMessage)。


例如:
如现在用户往系统中插入数据,而在数据库中规定某个字段必须唯一。当用户插入数据的时候,如果这个字段的值跟现有的纪录重复了,违反了数据库的唯一性约束,此时数据库就会跑出一个异常信息。这个信息一般用户可能看不到,因为其发生在数据库层面的。此时这个操作数据库异常类就会捕捉到数据库的这个异常信息,并将这个异常信息传递到前台。


每个 SQLException 都可提供以下多种消息:


描述错误的字符串。此字符串用作 Java Exception 消息,可以通过方法 getMessage 获得。
"SQLstate" 字符串,该字符串遵守 XOPEN SQLstate 约定或 SQL:2003 约定。SQLState 字符串的值在适当的规范中描述。DatabaseMetaData 的方法 getSQLStateType 可用于确定驱动程序返回 XOPEN 类型还是 SQL:2003 类型。
特定于每个供应商的整数错误代码。通常,这将是底层数据库返回的实际错误代码。
到下一个 Exception 的链接。可以使用此链接提供其他错误信息。
因果关系,如果存在任何导致此 SQLException 的原因。



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值