说明:捕获错误最理想情况下是在编译期间捕获,但是并不是所有的错误都能够在编译期间捕获,有些错误必须等到运行期间才能发现,检测到运行期间发生的错误后该如何通知及处理?如果每次调用一个方法时都要细致地检查错误,代码可读性大大降低。
违例:一种例外情况,在问题发生的时候,我们可能不知道该如何解决,但一定知道的是程序不能就这样一直执行下去,需要将错误报告出去,并采取一定的措施。本地可能没有足够多的信息,需要将其抛出交给上一级处理。
好处:我们在一个地方处理问题,不用因为检查一个特定的错误,在多个地方进行控制。
下面介绍:正确控制违例以及如何生成自己的违例
1.基本违例:
1.1违例条件:出现什么问题时应该中止方法或作用域的继续
1.2违例过程:违例发生时,在内存堆里使用new创建了一个违例对象,停止当前执行路径,从当前环境中释放出违例对象句柄,违例控制机制接管一切,使我们从错误产生地方迁移到其他地方解决。
2.违例捕获:
若某个方法产生违例,必须保证该违例能被捕获,并获得正确对待。掷出一个违例时,违例控制器会自动搜索自变量与违例类型相符的第一个控制器,并不在搜索其他违例控制器。
try{
可能产生违例的地方
}
生成的违例在catch中中止
catch(Exception1 exception1){
处理特定类型的违例
}catch(Exception2 exception2){
处理特定类型的违例
}...
}.catch(Exceptionn Exceptionn){
处理特定类型的违例
}
抛出所有潜在的违例类型
void f() throws Exception1,...Exceptionn{..}
3.重新掷出违例
掷出当前违例句柄,违例进入更高一级违例控制器中,同一try块中的catch从句仍然被忽略。使用throw掷出当前句柄e,只有在高一级catch块中捕获。
package com.zd.java.exception;
/**
* 将当前堆栈的信息填充到原来的违例中
* Created by ZD on 2017/10/10.
*/
public class Rethrowing {
public static void f() throws Exception{
System.out.println("originating the exception in f()");
throw new Exception("throw from f()");
}
public static void g() throws Throwable{
try{
f();
}catch (Exception e){
System.out.println("Inside g(),e.printStackTrace()");
e.printStackTrace();
throw e;
}
}
public static void main(String[] args) throws Throwable{
try{
g();
}catch (Exception e){
System.out.println("caught in main,e.printStackTrace()");
e.printStackTrace();
}
}
}
打印结果:
originating the exception in f()
java.lang.Exception: throw from f()
Inside g(),e.printStackTrace()
at com.zd.java.exception.Rethrowing.f(Rethrowing.java:11)
at com.zd.java.exception.Rethrowing.g(Rethrowing.java:16)
at com.zd.java.exception.Rethrowing.main(Rethrowing.java:26)
caught in main,e.printStackTrace()
java.lang.Exception: throw from f()
at com.zd.java.exception.Rethrowing.f(Rethrowing.java:11)
at com.zd.java.exception.Rethrowing.g(Rethrowing.java:16)
at com.zd.java.exception.Rethrowing.main(Rethrowing.java:26)
4.创建自己的违例
经常需要创建自己的违例,指出自己所写的库可能存在的问题,创建自己的违例类,必须从一个现有的违例类型继承,最好在含义上与新违例类似。
java.lang.Exception–>程序能捕获的基本违例,其他违例基本都是从此衍生出去的,也有程序不是从Exception衍生的,比如IO有关的都是从IOException衍生的。
package com.zd.java.exception;
/**
* 创建自己的违例时,可以采取更多的操作,可添加额外的构建器及成员
* Created by ZD on 2017/10/10.
*/
public class Inheriting2 {
public static void f() throws MyException2{
System.out.println("throwing myexception2 from f()");
throw new MyException2();
}
public static void g() throws MyException2{
System.out.println("throwing myexception2 from g()");
throw new MyException2("originated in g()");
}
public static void h() throws MyException2{
System.out.println("throwing myexception2 from h()");
throw new MyException2("originated in h()");
}
public static void main(String[] args){
try{
f();
}catch (MyException2 e){
e.printStackTrace();
}
try{
g();
}catch (MyException2 e){
// e.printStackTrace();
}
try{
h();
}catch (MyException2 e){
// e.printStackTrace();
System.out.println("e.val()="+e.val());
}
}
}
class MyException2 extends Exception{
private int i;
public MyException2(){}
public MyException2(String msg){
super(msg);
}
public MyException2(String msg,int x){
super(msg);
i = x;
}
public int val(){
return i;
}
}
com.zd.java.exception.MyException2
at com.zd.java.exception.Inheriting2.f(Inheriting2.java:10)
at com.zd.java.exception.Inheriting2.main(Inheriting2.java:25)
throwing myexception2 from f()
throwing myexception2 from g()
throwing myexception2 from h()
e.val()=0
5.违例的限制
覆盖一个方法时,只能产生在方法基础类版本中声明的违例,重写方法中可以不声明违例,但不能声明未在基类方法中声明的违例。
package com.zd.java.exception;
/**
* Created by ZD on 2017/10/11.
*/
class BaseballException extends Exception{}
class Foul extends BaseballException{}
class Strike extends BaseballException{}
abstract class Inning{
Inning() throws BaseballException{}
void event() throws BaseballException{}
abstract void atBat() throws Strike,Foul;
void walk(){};
}
class StromException extends Exception{}
class RainedOut extends StromException{}
class PopFoul extends Foul{}
interface Storm{
void event() throws RainedOut;
void rainHard() throws RainedOut;
}
public class StormyInning extends Inning implements Storm {
StormyInning() throws RainedOut,BaseballException{}
// /**
// * 基类方法walk未声明抛出PopFoul异常,子类方法不可抛出
// * @throws PopFoul
// */
//void walk() throws PopFoul{}
// /**
// * 实现接口的event方法,基类中也有event方法,相当于重写了基类的event方法,
// * 在基类event方法中没有声明RainedOut异常
// * @throws RainedOut
// */
// @Override
// public void event() throws RainedOut {
// }
/**
* 实现接口方法,重写了基类中方法,接口方法声明异常与基类方法声明异常不一致,可以选择不抛出异常
*/
@Override
public void event() {
}
@Override
public void rainHard() throws RainedOut {
}
/**
* 重写方法可以抛出异常的子类
* @throws PopFoul
*/
@Override
void atBat() throws PopFoul{
}
public static void main(String[] args){
try{
StormyInning si = new StormyInning();
si.atBat();
}catch (PopFoul popFoul) {
popFoul.printStackTrace();
}catch (RainedOut rainedOut) {
rainedOut.printStackTrace();
} catch (BaseballException e) {
e.printStackTrace();
}
try{
Inning i = new StormyInning();
i.atBat();
}catch (RainedOut rainedOut) {
rainedOut.printStackTrace();
} catch (Strike strike) {
strike.printStackTrace();
} catch (Foul foul) {
foul.printStackTrace();
} catch (BaseballException e) {
e.printStackTrace();
}
}
}
6.finally
无论一个违例是否发生,都想要执行特定的代码。
try{
可能产生违例的地方
}
生成的违例在catch中中止
catch(Exception1 exception1){
处理特定类型的违例
}catch(Exception2 exception2){
处理特定类型的违例
}...
}.catch(Exceptionn Exceptionn){
处理特定类型的违例
}finally{
无论何种情况,一定会执行的
}
finally使用过程中需要注意,在构建器中使用违例控制时,比如打开文件,finally就不是关闭文件位置的好选择。
package com.zd.java.exception;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
/**
* Created by ZD on 2017/10/11.
*/
class InputFile{
private BufferedReader in;
InputFile(String filename) throws Exception{
try{
in = new BufferedReader(new FileReader(filename));
}catch (FileNotFoundException e){
System.out.println(“could not open “+filename);
throw e;
}catch (Exception e){
try{
in.close();
System.out.println(“in.close()”);
}catch (IOException e2){
System.out.println(“in.close() unsuccessful”);
}
throw e;
}finally {
//do not close it here
}
}
String getLine() {
String s;
try{
s = in.readLine();
}catch (IOException e){
System.out.println(“readLine() unsucessful”);
s = “failed”;
}
return s;
}
void cleanuo(){
try{
in.close();
}catch (IOException e){
System.out.println(“in.close() unsucessful”);
}
}
}
public class Cleanup {
public static void main(String[] args){
try{
InputFile file = new InputFile(“Cleanup.java”);
String s;
int i = 1;
while ((s = file.getLine()) != null){
System.out.println(“”+ i++ + “: “+s);
}
file.cleanuo();
}catch (Exception e){
System.out.println(“caught in main,e.printStackTrace()”);
e.printStackTrace();
}
}
}
执行结果:
could not open Cleanup.java
caught in main,e.printStackTrace()
java.io.FileNotFoundException: Cleanup.java (系统找不到指定的文件。)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.(FileInputStream.java:138)
at java.io.FileInputStream.(FileInputStream.java:93)
at java.io.FileReader.(FileReader.java:58)
at com.zd.java.exception.InputFile.(Cleanup.java:17)
at com.zd.java.exception.Cleanup.main(Cleanup.java:59)
7.违例丢失
违例可能会丢失,在使用finally从句中存在违例丢失情况
**
package com.zd.java.exception;
/**
* 违例可能会丢失
* VeryImportantException违例丢失
* Created by ZD on 2017/10/11.
*/
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();
}
}
}
输出结果:
Exception in thread "main" a trivial exception
at com.zd.java.exception.LostMessage.dispose(LostMessage.java:29)
at com.zd.java.exception.LostMessage.main(LostMessage.java:38)
**