异常(exception)是正常程序流程不能处理或没有处理的异常情况。比如:数组下标越界,文件不存在等
1.异常种类
主要分成两类
1)受检异常:在编译时被编译器检测到
2)非受检异常:不能被编译器检测到。
非受检异常又分为运行时异常(比如除数为0)和错误异常(Error,程序中无法被处理)
主要谈程序能够处理的异常
在java中,异常是以类形式进行封装的(java.lang.Exception及其子类RuntimeException等)。
举例:
public class ExpectionDemo {
public static void main(String[] args){
int a=10;
int b=0;
int c=a/b;
System.out.println(a);
System.out.println(b);
System.out.println(c);
}
}
输出结果:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at expection.ExpectionDemo.main(ExpectionDemo.java:7)
产生了一个java.lang.ArithmeticException类型的异常
2.异常的产生
异常能够在执行程序时自动发现并且产生,可以在程序中显式生成,这种显式生成异常的方法叫做抛出异常。通过throw语句实现。
throw
ArithmeticException e = new ArithmeticException();
throw e;
或
throw new ArithmeticException();
try-catch-finally结构
try{
可能会产生异常的语句XXXXXXXX
}
catch(Exception1 e1){
XXXXXXXX
}
catch(Exception2 e2){
XXXXXXXX
}
.
.
.
finally{
XXXXXXXX
}
例如
public class ExceptionDemo {
public static void main(String[] args) {
try {
System.out.println("try语句");
throw new Exception();
} catch (Exception e1) {
System.out.println("catch语句");
e1.printStackTrace();
} finally {
System.out.println("finally语句");
}//try..结束
}//main结束
}
执行结果:
try语句
catch语句
java.lang.Exception
at expection.ExpectionDemo.main(ExpectionDemo.java:7)
finally语句
如果去掉try中的throw语句
执行结果:
try语句
finally语句
由此可见:
这种结构中,try语句块有异常发生时中断try剩余语句,产生异常实例对象。如果try语句块没有异常产生,那么catch语句不会被执行,而finally一般总是会执行。
throws
throw 用于方法块里面的代码,比如try…catch ….语句块,表示它抛出异常,但它不会处理它,而是由方法块的throws Exception来调用异常处理类来处理。
public class ExpectionDemo {
public void exception() throws NumberFormatException{
int a = Integer.parseInt("10L");
}
public static void main(String[] args){
ExpectionDemo test = new ExpectionDemo();
try{
test.exception();
}catch(NumberFormatException e){
System.out.println(e.getMessage());
}
}
}
输出结果
For input string: "10L"
3.throw和throws
1)throws 用于抛出方法层次的异常,并且直接由些方法调用异常处理类来处理该异常,所以它常用在方法的后面。比如
public static void main(String[] args) throws SQLException
2)throw 用于方法块里面的代码,比throws的层次要低,比如try…catch ….语句块,表示它抛出异常,但它不会处理它,而是由方法块的throws Exception来调用异常处理类来处理。
4.异常处理误区
1)将异常包含在循环语句块中
如下代码所示,异常包含在 for 循环语句块中。
清单 6
for(int i=0; i<100; i++){
try{
}catch(Exception e){
XXXXXX
}
}
异常处理占用系统资源。一般不会直接犯这样的错误,换个角度,类 A 中执行了一段循环,循环中调用了 B 类的方法,B 类中被调用的方法却又包含 try-catch 这样的语句块。褪去类的层次结构,代码和上面如出一辙。
2)利用 Exception 捕捉所有潜在的异常
一段方法执行过程中抛出了几个不同类型的异常,为了代码简洁,利用基类 Exception 捕捉所有潜在的异常,如下例所示:
public void retrieveObjectById(Long id){
try{
//…抛出 IOException 的代码调用
//…抛出 SQLException 的代码调用
}catch(Exception e){
//这里利用基类 Exception 捕捉的所有潜在的异常,如果多个层次这样捕捉,会丢失原始异常的有效信息
throw new RuntimeException(“Exception inretieveObjectById”, e);
}
}
3)忽略异常
如下异常处理只是将异常输出到控制台,没有任何意义。而且这里出现了异常并没有中断程序,进而调用代码继续执行,导致更多的异常。
public void retrieveObjectById(Long id){
try{
//..some code that throws SQLException
}catch(SQLException ex){
/**
* 这里的异常打印毫无意义,仅仅是将错误堆栈输出到控制台。
* 而在 Production 环境中,需要将错误堆栈输出到日志。
* 而且这里 catch 处理之后程序继续执行,会导致进一步的问题*/
ex.printStacktrace();
}
}
这是三个我觉得新手最容易进入的误区
引自Java 异常处理的误区和经验总结