随笔-204  评论-149  文章-0  trackbacks-0
RuntimeException异常以及其子类异常,不需要异常说明就可以从任何地方抛出
是uncheck exception。

从程序的输出看出,无论有没有抛出异常,finally子句总会得到执行,
这个程序也启发我们应该如何处理我们前面讲到过的,Java异常(和C
++
的异常一样)会阻止程序回到异常抛出的地方恢复执行这个问题。
如果你把try块放进一个循环,你就能构建一个程序运行之前必须满足的条件。

class ThreeException extends Exception{
    
}

public class FinallyWorks {

    
    
static int count = 0;
    
    
public static void main(String[] args) {
        
while(true){
            
try{
                
if(count++==0){
                    
throw new ThreeException();
                }

                System.out.println(
"No Exception");
            }
catch(Exception e){
                System.err.println(
"ThreeException");
            }
finally{
                System.err.println(
"In finally clause");
                
if(count==2)
                    
break;
            }

        }

    }


}


ThreeException
In 
finally clause
No Exception
In 
finally clause





Finally子句的执行
class FourException extends Exception {
}


public class AlwaysFinally {

    
public static void main(String[] args){
        System.out.println(
"Entering first try block");
        
try {
            System.out.println(
"Entering second try block");
            
try {
                
throw new FourException();
            }
 finally {
                System.out.println(
"finally in 2nd try block");
            }

        }
 catch (FourException e) {
            System.err.println(
"Caught FourException in 1st try block");
        }
 finally {
            System.err.println(
"finally in 1st try block");
        }


    }

}

Entering first 
try block
Entering second 
try block
finally in 2nd try block
Caught FourException in 1st 
try block
finally in 1st try block





丢失的异常
package exceptiontest;

class VeryImportantException extends Exception {
    
public String toString() {
        
return "A very important exception!";
    }

}


class HoHumException extends Exception {
    
public String toString() {
        
return "A trivial exception";
    }

}


public class LostMessage {
    
void f() throws VeryImportantException {
        
throw new VeryImportantException();
    }


    
void dispose() throws HoHumException {
        
throw new HoHumException();
    }


    
public static void main(String[] args) throws Exception {
        LostMessage lm 
= new LostMessage();
        
try {
            lm.f();
        }
 finally {
            lm.dispose();
        }


    }

}


看到了吗?VeryImportantException消失的无影无踪了,它直接被finally里面的HoHumException给取代了,这是一个相当严重的错误,它表示这个异常被彻底丢失了,而在真实环境中,这种情况会远比上述程序更为微妙,更难以察觉。相反,C
++会把这种“第一个异常尚未得到处理,就产生了第二个异常”的现象,当成极端严重的编程错误。







//Java构造函数中发生的异常
class InputFile {
    
private BufferedReader in;

    
public InputFile(String fname) throws Exception {
        
try {
            in 
= new BufferedReader(new FileReader(fname));
            
// Other code that might throw exceptions
        }
 catch (FileNotFoundException e) {
            System.err.println(
"Could not open " + fname);
            
// Wasn't open, so don't close it
            throw e;
        }
 catch (Exception e) {
            
// All other exceptions must close it
            try {
                in.close();
            }
 catch (IOException e2) {
                System.err.println(
"in.close() unsuccessful");
            }

            
throw e; // Rethrow
        }
 finally {
            
// Don't close it here!!!
        }

    }


    
public String getLine() {
        String s;
        
try {
            s 
= in.readLine();
        }
 catch (IOException e) {
            
throw new RuntimeException("readLine() failed");
        }

        
return s;
    }


    
public void dispose() {
        
try {
            in.close();
            System.out.println(
"dispose() successful");
        }
 catch (IOException e2) {
            
throw new RuntimeException("in.close() failed");
        }

    }

}


public class Cleanup {
    
private static Test monitor = new Test();

    
public static void main(String[] args) {
        
try {
            InputFile in 
= new InputFile("Cleanup.java");
            String s;
            
int i = 1;
            
while ((s = in.getLine()) != null)
                ; 
// Perform line-by-line processing here
            in.dispose();
        }
 catch (Exception e) {
            System.err.println(
"Caught Exception in main");
            e.printStackTrace();
        }

        monitor.expect(
new String[] "dispose() successful" });
    }

}
 // /:~



异常处理系统还是一扇能让你放弃程序正常运行顺序的暗门。当某种“异常情况”出现的时候,这个门就开启了,于是程序再也不能,或者再也不按照正常的顺序执行下去。异常表示的是一些“当前方法无法处理”的情况。之所以要开发异常处理系统,是因为要对每次函数调用的每个错误做检查实在是太费力了,所以程序员根本就不去做。结果就是把错误给忽略了。
异常处理的一个重要准则就是“如果你不知道该如何处理这个异常,你就别去捕捉它”。实际上,异常处理有一项重要的目标,这就是将处理异常的代码从异常发生的地方移开。这样你就能在一个地方集中精力去解决你想解决的问题,然后再到另外一个地方处理这些异常问题了。
但是 java所特有的checked exception将这种情况变的稍微复杂些了,这是因为即使你不准备这么做,编译器也强制要求你在try的后面加上catch子句,于是这就导致了“错误地私吞harmful 
if swallowed”的问题了:


注意一下throw e.fillInStackTrace();的用法

package exceptiontest;

import java.util.Collections;

public class Rethrowing {
    
public static void f()throws Exception{
        System.err.println(
"originating the exception n f()");
        
throw new Exception("throw from f()");
    }

    
public static void g()throws Throwable{
        
try{
            f();
        }
catch(Exception e){
            System.err.println(
"Inside g(),e.printlStackTrace()");
            e.printStackTrace();
            
//throw e;
            throw e.fillInStackTrace();
        }

        
    }

    
public static void h()throws Exception{
        f();
    }

    
public static void main(String[] args)throws Throwable{
        
try{
            g();
        }
catch(Exception e){
            System.err.println(
"Caught in main,e.printStackTrace");
            e.printStackTrace();
        }

    }


}

运行结果:
originating the exception n f()
Inside g(),e.printlStackTrace()
java.lang.Exception: throw from f()
 at exceptiontest.Rethrowing.f(Rethrowing.java:8)
 at exceptiontest.Rethrowing.g(Rethrowing.java:12)
 at exceptiontest.Rethrowing.main(Rethrowing.java:26)
Caught in main,e.printStackTrace
java.lang.Exception: throw from f()
 at exceptiontest.Rethrowing.g(Rethrowing.java:17)
 at exceptiontest.Rethrowing.main(Rethrowing.java:26)


如不使用 throw e.fillInStackTrace(),而是throw e
originating the exception n f()
Inside g(),e.printlStackTrace()
java.lang.Exception: throw from f()
 at exceptiontest.Rethrowing.f(Rethrowing.java:8)
 at exceptiontest.Rethrowing.g(Rethrowing.java:12)
 at exceptiontest.Rethrowing.main(Rethrowing.java:26)
Caught in main,e.printStackTrace
java.lang.Exception: throw from f()
 at exceptiontest.Rethrowing.f(Rethrowing.java:8)
 at exceptiontest.Rethrowing.g(Rethrowing.java:12)
 at exceptiontest.Rethrowing.main(Rethrowing.java:26)



Exception chaining

Often you want to catch one exception and throw another, but still keep the information about the originating exception—this is called exception chaining. Prior to JDK 1.4, programmers had to write their own code to preserve the original exception information, but now all Throwable subclasses may take a cause object in their constructor. The cause is intended to be the originating exception, and by passing it in you maintain the stack trace back to its origin, even though you’re creating and throwing a new exception at this point.

It’s interesting to note that the only Throwable subclasses that provide the cause argument in the constructor are the three fundamental exception classes Error (used by the JVM to report system errors), Exception, and RuntimeException. If you want to chain any other exception types, you do it through the initCause( ) method rather than the constructor.

//: c09:DynamicFields.java
// A Class that dynamically adds fields to itself.
// Demonstrates exception chaining.
// {ThrowsException}
import com.bruceeckel.simpletest.*;

class DynamicFieldsException extends Exception {}

public class DynamicFields {
  
private static Test monitor = new Test();
  
private Object[][] fields;
  
public DynamicFields(int initialSize) {
    fields 
= new Object[initialSize][2];
    
for(int i = 0; i < initialSize; i++)
      fields[i] 
= new Object[] nullnull };
  }

  
public String toString() {
    StringBuffer result 
= new StringBuffer();
    
for(int i = 0; i < fields.length; i++{
      result.append(fields[i][
0]);
      result.append(
"");
      result.append(fields[i][
1]);
      result.append(
"\n");
    }

    
return result.toString();
  }

  
private int hasField(String id) {
    
for(int i = 0; i < fields.length; i++)
      
if(id.equals(fields[i][0]))
        
return i;
    
return -1;
  }

  
private int
  getFieldNumber(String id) 
throws NoSuchFieldException {
    
int fieldNum = hasField(id);
    
if(fieldNum == -1)
      
throw new NoSuchFieldException();
    
return fieldNum;
  }

  
private int makeField(String id) {
    
for(int i = 0; i < fields.length; i++)
      
if(fields[i][0== null{
        fields[i][
0= id;
        
return i;
      }

    
// No empty fields. Add one:
    Object[][]tmp = new Object[fields.length + 1][2];
    
for(int i = 0; i < fields.length; i++)
      tmp[i] 
= fields[i];
    
for(int i = fields.length; i < tmp.length; i++)
      tmp[i] 
= new Object[] nullnull };
    fields 
= tmp;
    
// Reursive call with expanded fields:
    return makeField(id);
  }

  
public Object
  getField(String id) 
throws NoSuchFieldException {
    
return fields[getFieldNumber(id)][1];
  }

  
public Object setField(String id, Object value)
  
throws DynamicFieldsException {
    
if(value == null{
      
// Most exceptions don't have a "cause" constructor.
      
// In these cases you must use initCause(),
      
// available in all Throwable subclasses.
      DynamicFieldsException dfe =
        
new DynamicFieldsException();
      dfe.initCause(
new
 NullPointerException());
      
throw
 dfe;
    }

    
int fieldNumber = hasField(id);
    
if(fieldNumber == -1)
      fieldNumber 
= makeField(id);
    Object result 
= null;
    
try {
      result 
= getField(id); // Get old value
    }
 catch(NoSuchFieldException e) {
      
// Use constructor that takes "cause":
      throw new RuntimeException(e);
    }

    fields[fieldNumber][
1= value;
    
return result;
  }

  
public static void main(String[] args) {
    DynamicFields df 
= new DynamicFields(3);
    System.out.println(df);
    
try {
      df.setField(
"d""A value for d");
      df.setField(
"number"new Integer(47));
      df.setField(
"number2"new Integer(48));
      System.out.println(df);
      df.setField(
"d""A new value for d");
      df.setField(
"number3"new Integer(11));
      System.out.println(df);
      System.out.println(df.getField(
"d"));
      Object field 
= df.getField("a3"); // Exception
    }
 catch(NoSuchFieldException e) {
      
throw new RuntimeException(e);
    }
 catch(DynamicFieldsException e) {
      
throw new RuntimeException(e);
    }

    monitor.expect(
new String[] {
      
"null: null",
      
"null: null",
      
"null: null",
      
"",
      
"d: A value for d",
      
"number: 47",
      
"number2: 48",
      
"",
      
"d: A new value for d",
      
"number: 47",
      
"number2: 48",
      
"number3: 11",
      
"",
      
"A value for d",
      
"Exception in thread \"main\" " +
      
"java.lang.RuntimeException: " +
      
"java.lang.NoSuchFieldException",
      
"\tat DynamicFields.main(DynamicFields.java:98)",
      
"Caused by: java.lang.NoSuchFieldException",
      
"\tat DynamicFields.getFieldNumber(" +
      
"DynamicFields.java:37)",
      
"\tat DynamicFields.getField(DynamicFields.java:58)",
      
"\tat DynamicFields.main(DynamicFields.java:96)"
    }
);
  }

}
 ///:~




方法覆盖时异常的情况
package exceptiontest;
//方法覆盖时异常的情况
//: c09:StormyInning.java
//Overridden methods may throw only the exceptions
//specified in their base-class versions, or exceptions
//derived from the base-class exceptions.

class BaseballException extends Exception {
}


class Foul extends BaseballException {
}


class Strike extends BaseballException {
}


abstract class Inning {
    
public Inning() throws BaseballException {
    }


    
public void event() throws BaseballException {
        
// Doesn't actually have to throw anything
    }


    
public abstract void atBat() throws Strike, Foul;

    
public void walk() {
    }
 // Throws no checked exceptions
}


class StormException extends Exception {
}


class RainedOut extends StormException {
}


class PopFoul extends Foul {
}


interface Storm {
    
public void event() throws RainedOut;

    
public void rainHard() throws RainedOut;
}


public class StormyInning extends Inning implements Storm {
    
// OK to add new exceptions for constructors, but you
    
// must deal with the base constructor exceptions:
    
//构造函数可以多,但是它必须加基类构造函数所声明的异常
    public StormyInning() throws RainedOut, BaseballException {
    }


    
public StormyInning(String s) throws Foul, BaseballException {
    }


    
// Regular methods must conform to base class:
    
//异常声明只少不多,但这种异常方面的限制对构造函数不起作用
    
// ! void walk() throws PopFoul {} //Compile error
    
// Interface CANNOT add exceptions to existing
    
// methods from the base class:以基类为准而不是以接口为准
    
// ! public void event() throws RainedOut {}
    
// If the method doesn't already exist in the
    
// base class, the exception is OK:
    public void rainHard() throws RainedOut {
    }


    
// You can choose to not throw any exceptions,
    
// even if the base version does:
    
//异常声明只少不多*****************************
    public void event() {
    }


    
// Overridden methods can throw inherited exceptions:
    public void atBat() throws PopFoul {
    }


    
public static void main(String[] args) {
        
try {
            StormyInning si 
= new StormyInning();
            si.atBat();
        }
 catch (PopFoul e) {
            System.err.println(
"Pop foul");
        }
catch(Foul e){
            
        }
catch (RainedOut e) {
            System.err.println(
"Rained out");
        }
 catch (BaseballException e) {
            System.err.println(
"Generic baseball exception");
        }

        
// Strike not thrown in derived version.
        try {
            
// What happens if you upcast?
            Inning i = new StormyInning();
            i.atBat();
            
// You must catch the exceptions from the
            
// base-class version of the method:
        }
 catch (Strike e) {
            System.err.println(
"Strike");
        }
 catch (Foul e) {
            System.err.println(
"Foul");
        }
 catch (RainedOut e) {
            System.err.println(
"Rained out");
        }
 catch (BaseballException e) {
            System.err.println(
"Generic baseball exception");
        }

    }

}

posted on 2009-06-18 23:40 Frank_Fang 阅读(989) 评论(0)  编辑  收藏 所属分类: Java编程

只有注册用户登录后才能发表评论。


网站导航: