java 异常

Throwable

    能够抛出任意类型的Throwable对象,它是异常类型的根类。


Error

(1)总是不可控制的(unchecked);

(2)用于表示编译时和系统错误;

(3)如何可能的话,应该在系统级被捕捉。

Exception

(1)可以是可被控制(checked) 或不可控制的(unchecked);

(2)表示一个由程序员导致的错误;

(3)应该在应用程序级被处理。 

    RuntimeException类及子类均为unchecked,该异常类与Error都不建议try/catch。常见的RuntimeException:NullPointerExceptionClassCastExceptionIllegalArgumentException、ArithmeticException、ArrayStoreException 、IndexOutOfBoundsException、NegativeArraySizeException、NumberFormatException、SecurityException、UnsupportedOperationException。

    非RuntimeException为checked,必须要么try,要么throw。

    异常处理理论上有两种基本模型:终止模型和恢复模型。

异常信息

(1)通常异常对象中仅有的信息就是异常类型。

class MyException extends Exception {
    MyException() { super(); }
    MyException(String msg) { super(msg); }
}
public class Test {
    public static void main(String[] args) {
        try {
    	    throw new MyException("My Exception");
	} catch (MyException e) {
            System.out.println("Caught Exception");
	    System.out.println("getMessage(): " + e.getMessage());
	    System.out.println("getLocalizedMessage(): " + e.getLocalizedMessage());
    	    System.out.println("toString(): " + e.toString());
	    System.out.println("printStackTrace(): ");
	    e.printStackTrace(System.out);
	} 
    }
} /* Output:
Caught Exception
getMessage(): My Exception
getLocalizedMessage(): My Exception
toString(): MyException: My Exception
printStackTrace(): 
MyException: My Exception
	at Test.main(Test.java:8)	
*///:~

(2)e.printStackTrace()会将信息输出到标准错误流;e.printStackTrace(PrintWriter out)则是输出至指定的输出流。通常的做法是使用标准错误流,因为System.out也许会被重定向。

    另外,补充System.out/System.in/System.err的重定向。从JDK的源码可以看到这三个流都是final static类型。也就是用户无法通过更改引用的方式来进行重定向,必须借助setIn(InputStream in)/setOut(PrintStream out)/setErr(PrintStream err)。

    /**
     * The "standard" input stream. This stream is already
     * open and ready to supply input data. Typically this stream
     * corresponds to keyboard input or another input source specified by
     * the host environment or user.
     */
    public final static InputStream in = null; 
    /**
     * The "standard" output stream. This stream is already
     * open and ready to accept output data. Typically this stream
     * corresponds to display output or another output destination
     * specified by the host environment or user.
    */
    public final static PrintStream out = null; 
    private static native void setIn0(InputStream in);
    private static native void setOut0(PrintStream out);
    private static native void setErr0(PrintStream err);

(3)记录异常日志可使用java.util.logging工具将输出记录到日志中。

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.logging.Logger;

class ExceptionLog {
	private static Logger logger = Logger.getLogger("ExceptionLog");
	public static void logException(Exception e) {
		StringWriter trace = new StringWriter();
		e.printStackTrace(new PrintWriter(trace));
		logger.severe(trace.toString());
	}
}
public class Test {
	public static void main(String[] args) {
		try {
			throw new NullPointerException();
		} catch (NullPointerException e) {
			ExceptionLog.logException(e);
		} 
	}
}

(4)最后,补充一点:在catch中可能需要重新抛出异常。使用throw e的问题在于e.printStackTrace()会保留原始的异常抛出点的栈信息,如需重新更新这个栈信息可使用throw (Exception)e.fillInStackTrace()。

异常链

    通常想要在捕获一个异常后抛出另一个异常,并希望把原始异常的信息保存下来,这就被称为异常链。

    将Throwable对象作为cause参数是用来保留原始异常信息的。Error、Exception、RuntimeException类提供有cause参数的构造器。但大多数异常都没有这个构造函数,应该使用e.initCause(cause)。

try/catch/finally

(1)在代码块中,throw/return语句后不要再写其他语句,否则会因为执行不到而导致编译失败。

(2)一般声明几个异常就应该对应几个catch。当出现多个catch时应该将处理基类异常的catch子句放在其子类的最下面,否则因为下面的catch语句永远得不到执行而导致编译失败。另外,catch中的unchecked异常必须是try语句块中已声明的异常,否则会编译失败。

class E1 extends Exception {}
class E2 extends E1 {}
class E3 extends E2 {}
class A {
	void f() throws E1{
		throw new E1();
	}
}
class B extends A {
	void f() throws E2{
		throw new E2();
	}
}
class C extends B {
	void f() throws E3{
		throw new E3();
	}
}
public class Test {
	public static void main(String[] args) {
		A a = new C();
		try {
			a.f();
		} catch (E3 e) {
			e.printStackTrace();
		} catch (E2 e) {
			e.printStackTrace();
		} catch (E1 e) {
			e.printStackTrace();
		}
	}
} /* Output:
E3
	at C.f(Test.java:16)
	at Test.main(Test.java:23)
*///:~

(3)finally为必定会执行的部分,只有一种情况不会执行那就是System.exit(0)。将除内存外的资源恢复到它们的初始状态,就要用到finally子句。

(4)finally子句中最好不要使用return语句。下面这段程序结果返回2,程序会先执行try语句中的a++,在即将return时转而执行finally的return语句退出函数。另外,在finally的return处会产生警告。

public class Test {
	@SuppressWarnings({ "finally" })
	static int test() {
		int a = 0;
		try {
			return a++;
		} finally {
			return ++a;
		}
	}
	public static void main(String[] args) {
		System.out.println(test());	
	}
}

(5)某些特殊方式使用finally子句会造成异常丢失。

class E1 extends Exception {
	E1() {}
	E1(String msg) { super(msg); }
}
class E2 extends Exception {
	E2() {};
	E2(String msg) { super(msg); }
}
public class Test {
	static void fun1() throws E1 {
		throw new E1("fun1()抛出的异常");
	}
	static void fun2() throws E2 {
		throw new E2("fun2()抛出的异常");
	}
	public static void main(String[] args) {
		try {
			try {
				fun1();
			} finally {
				fun2();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
} /* Output:
E2: fun2()抛出的异常
	at Test.fun2(Test.java:14)
	at Test.main(Test.java:21)
*///:~
public class Test {
	public static void main(String[] args) {
		try {
			throw new RuntimeException();
		} finally {
			return;
		}
	}
}///:~

异常的限制

    当覆盖方法时,只能抛出在基类方法的异常说明列表中列出的异常(或这些异常的子类)。另外,子类向上提升后,必须捕捉基类方法中的异常。

    异常限制对构造器不起作用,但子类构造器的异常说明必须包含基类构造器的异常说明,且子类构造器中无法捕获基类构造器抛出的异常。

class BaseballException extends Exception{}
class Foul extends BaseballException{}
class Strike extends BaseballException{}
abstract class Inning {
	public Inning() throws BaseballException{}
	public void walk(){}
	public void event() throws BaseballException{}
	public abstract void atBat() throws Strike,Foul;
}
class StormException extends Exception{}
class RainOut extends StormException{}
class PopFoul extends Foul{}
interface Storm {
	public void event() throws RainOut;
	public void rainHard() throws RainOut;
}
class StormyInning extends Inning implements Storm {
	//必须抛BaseballException
	StormyInning()throws BaseballException{}
	//必须抛BaseballException
	StormyInning(String s) throws RainOut, BaseballException{}
	//只能抛RainOut类或其子类
	public void rainHard() {}
	//不能抛任何异常
	public void event() {}
	//不能抛任何异常
	public void walk() {}
	//只能抛Strike,Foul类或其子类
	public void atBat() throws PopFoul {}	
}

    最后,需要补充一点:异常说明不属于方法类型的一部分。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值