有关JAVA异常和错误(ERROR)的处理
最近遇到有关ERROR的处理问题,下面这篇文章
?
转至:http://www.cnblogs.com/deepnighttwo/archive/2006/12/11/1964305.html
?
?
LinkageError是一个比较棘手的异常,准确的说它是一个Error而不是Exception。java api对它没有直接的解释,而是介绍了它的子类:
??? Subclasses of LinkageError indicate that a class has some dependency on another class; however, the latter class has incompatibly changed after the compilation of the former class.
似乎是说不兼容性,既编译时,A类用到B类,且这时候A和B是兼容的,但是到运行时,A类得到的B(既某个类加载器加载的B类)却不是A在编译的时候那个与之兼容的B,这个说起来比较复杂,其实就是个二进制兼容性问题,和很多程序不能在98上跑是一个道理,程序就是A,而98就是B。事实上,真正出现二进制兼容性问题的时候,确实是报NoSuchMethodError或者NoSuchFieldError或者NoClassDefFoundError。Java api对NoSuchMethodError的解释(其他的解释几乎相同):Thrown if an application tries to call a specified method of a class (either static or instance), and that class no longer has a definition of that method. Normally, this error is caught by the compiler; this error can only occur at run time if the definition of a class has incompatibly changed. ?关键词是“incompatibly changed ”。?事实证明,当传统意义上的二进制不兼容性(既上面举的98的例子,或者说incompatibly changed)问题发生的时候,java会报NoSuchMethodError,NoSuchFieldError或者NoClassDefFoundError,这三个类都是LinkageError的子类,所以,就好像java api对LinkageError中的解释一样“Subclasses of LinkageError indicate that……”这个解释并没有说LinkageError本身应该是在什么情况下被抛出。倒不是java api顾左右而言他,而是抛出LinkageError的情况实在是很难叙述,《深入java虚拟机》第二版用近乎一章(比较大的一章,和其它章相比)来解释这个问题。归根结底,原因是ClassLoader没有完全按照设计的那样设置:任何一个ClassLoader的实例都应该设置一个恰当的ClassLoader实例为父类加载器,并且在真正defineClass前,都应该先将这个任务委托给其父类加载器。何为恰当的ClassLoader实例?一般来说,就应该是 this.getClass().getClassLoader()(也就是ClassName.class.getClassLoader(),这两个值是同一个值)的返回值),或者是一个设计者认为合理的值。这个值应该保证“相同全限定名的类(可以认为是同一个类,仅仅是可以)不会出现在同一个类的代码中。”举例来说,在一个类的一段代码中(可以是一个方法,或者是一个static块),如果有classLoaderA加载的 test.Test类,也有classLoaderB加载的test.Test,那么,把前者的引用指向后者的实例的时候,就会报LinkageError。所以虽然可以捕获这些错误,用catch(Throwablee)的方式,但还是不建议这么做,业务代码还是catch(Exception?e),
JAVA系统级别的ERROR,系统解决完毕就行了。
参考:http://lvp.iteye.com/blog/356650http://topic.csdn.net/t/20020524/17/749799.html
-----------------------------------------------------------出自《JAVA程序设计》一书8.3? Java的异常处理异常的处理主要包括捕获异常、程序流程的跳转和异常处理语句块的定义等。当一个异常被抛出时,应该有专门的语句来捕获这个被抛出的异常对象,这个过程被称为捕获异常。当一个异常类的对象被捕获后,用户程序就会发生流程的跳转,系统中止当前的流程而跳转至专门的异常处理语句块,或直接跳出当前程序和Java虚拟机,退回到操作系统。
8.3.1? 异常类说明
Java中所有的异常都由类来表示。所有的异常都是从一个名为Throwable的类派生出来的。因此,当程序中发生一个异常时,就会生成一个异常类的某种类型的对象。Throwable类有两个直接子类:Exception和Error。
与Error类型的异常相关的错误发生在Java虚拟机中,而不是在程序中。错误类(Error)定义了被认为是不能恢复的严重错误条件。在大多数情况下,当遇到这样的错误时,建议让该程序中断。这样的异常超出了程序可控制的范围。
由程序运行所导致的错误由Exception类来表示,该异常类定义了程序中可能遇到的轻微的错误条件。可以编写代码来处理这样的异常并继续执行程序,而不是让程序中断。它代表轻微的可以恢复的故障。接收到异常信号后,调用方法捕获抛出的异常,在可能的情况下再恢复回来,这样程序员可以通过处理程序来处理异常。
Java中的异常类具有层次组织,其中Throwable类是Error类(错误类)和Exception类(异常类)的父类,Throwable类是Object类的直接子类。
异常类(java.lang.Exception)继承于java.lang.Object类中的java.lang.Throwable类。异常可分为执行异常(Runtime Exception)和检查异常(Checked Exception)两种,如图8-1所示。为了深入了解执行异常和检查异常内容,这里给出它们的详细介绍列举。
try{
}
一般将可能产生异常情况语句放在try语句块中,这个try语句块用来启动Java的异常处理机制。凡是可能抛出异常的语句,包括throw语句和可能抛出异常的方法的调用语句,都应该包含在这个try语句块中。然后在catch语句块对异常进行处理。Java语言还规定,每个catch语句块都应该与一个try语句块相对应。
【例8-1】捕获除数为零的异常,并显示相应信息。
class ArithmeticExceptionDemo{
??????? }catch (ArithmeticException e) {?????? //捕获divide-by-zero错误
??????????? System.out.println("产生用零除错误。");
??????? }
??????? System.out.println("在捕获语句后执行的一个语句。");
??? }
}
该程序的执行结果如图8-2所示。
try{
}
在出现和未出现异常的情况下都要执行的代码可以放到finally语句块中。加入了finally语句块后有以下3种执行情况。
class Finally_Demo{
}
该程序的执行结果如图8-3所示。
class FinallyWithBreakDemo{
??? public static void main(String args[]) {
??????? for( ; ; )
??????? try{
????? ??????System.out.println("即将被break中断,要退出循环了!");
??????????? break;
??????? }finally{
??????????? System.out.println("但是finally块总要被执行到!");
??????? }
}
该程序的执行结果如图8-4所示。
[修饰符]? 返回类型? 方法名(参数1,参数2,……)throws异常列表
?? {……}
例如:
public int read ( ) throws IOException
?? {……}
throws子句中同时可以指明多个异常,说明该方法将不对这些异常进行处理,而是声明抛弃它们。例如:
public static void main (String args[ ]) throws IOException, IndexOutOf-
BoudsException?? {……}
【例8-4】声明抛出异常的程序格式。
public class ExceptionExam5
{
public static void go() throws IOException
??? {//方法代码}
public static void main(String [] args)
}
因为考虑到go()方法可能产生一个IOException,而此时无法处理异常,所以要从go()方法抛出这个异常,并且需要用throws子句指定异常。另外,Java的I/O系统包含在java.io包中,因此IOException也包含在其中,所以使用语句“import java.io.*;”导入java.io包,然后可以直接引用IOException。
8.3.6? 抛出异常Java应用程序在运行时如果出现了一个可识别的错误,就会产生一个与该错误相对应的异常类的对象。这个对象包含了异常的类型和错误出现时程序所处的状态信息,该异常对象首先被交给Java虚拟机,由虚拟机来寻找具体的异常处理者。在Java中把产生异常对象并将其交给Java虚拟机的过程称为抛出异常。
异常类不同,抛出异常的方法也不同,可以分为以下两种。
EOFException e = new EOFException( );
throw e;
使用throw语句抛出异常有两种方式:直接抛出和间接抛出。
1.直接抛出异常直接抛出方式是直接利用throw语句将异常抛出,格式为:
throw newExceptionObject;
利用throw语句抛出一个异常后,程序执行流程将直接寻找一个捕获(catch)语句,并进行匹配执行相应的异常处理程序,其后的所有语句都将被忽略。
【例8-5】设计自己的异常类,从键盘输入一个double类型的数,若不小于0.0,则输出它的平方根;若小于0.0,则输出提示信息“输入错误”。
import java.io.*;
??? void test(double x) throws MyException{
??????? if(x<0.0) throw new MyException();? //条件成立时,执行throw语句
??????? else System.out.println(Math.sqrt(x));
??? }???
??? public static void main(String args[]) throws IOException{
??????? MyException n = new MyException();
??????? try{
??????????? System.out.print("求输入实数的平方根。请输入一个实数:");
?????? ?????BufferedReader br=
??????????????? new BufferedReader(new InputStreamReader(System.in) );
??????????? String s=br.readLine();
??????????? n.test(Double.parseDouble(s));
??????? }catch(MyException e){
??????????? System.out.println("输入错误!");
??????? }
??? }
}
程序的两次运行结果如图8-5所示。
public void myMethod1() throws IndexOutOfBoundsException {
}
或
public void myMethod2() throws myException1, myException2 {
}
在上层调用该方法时,必须捕获有关异常,否则编译时将会出错。例如,调用方法myMethod2()时,必须按如下方式进行。
try{
}
【例8-6】带有间接抛出异常的类。
public class OutOfRangeException extends Exception{
??? ????int value;
??? ????OutOfRangeException problem =
??????? ????new OutOfRangeException ("Input value is out of range.");
??????????? //创建一个异常对象并可能抛出它
??? ????System.out.print ("Enter an integer value between " + MIN +
?????????????????? ???????????" and " + MAX + ", inclusive: ");
??? ????try{
??? ????}catch (Exception exception) {
? ??????????System.out.println ("Error reading int data, MIN_VALUE value
??????????????????????????????????? returned.");
??????? ????value = Integer.MIN_VALUE;
??? ?????}
???? ???????//确定该异常是否抛出
??? ????if (value < MIN || value > MAX)
??????? ????throw problem;
??? ????System.out.println ("End of main method.");
???? ???????//may never reach this place
??? }
}
这个例子有两个特征,一是它利用了自定义的异常类OutOfRangeException,一旦程序执行违背了所定义的逻辑就抛出这个异常;二是在抛出异常的方法中,利用throws关键字声明了OutOfRangeException异常类的间接抛出,这样若是在其他地方使用到这个类的对象,也可以捕获这个异常。
使用throws子句抛出异常时应注意如下两个问题。
throws异常类名列表
这样做主要是为了通知所有欲调用此方法的方法:由于该方法包含throws了句,所以要准备接受和处理它在运行过程中可能会抛出的异常。如果方法中的throws了句不止一个,方法头的异常类名表中的列出的异常也不止一个,应该包含所有可能产生的异常。例如,在上面的myMethod2( )方法中包含的异常有:myException1和myException2。
class OutBoundsException extends Exception
}
运行结果如图8-6所示。
图8-6? 运行结果
注意:一个方法所声明抛弃的异常是作为这个方法与外界交互的一部分而存在的。所以,方法的调用者必须了解这些异常,并确定如何正确地处理它们。
<!-- 广告位 --><script></script><script></script><script></script><script></script><script></script>
---------------------------------------------------------------<script></script>