在正常的程序设计中,程序异常处理是非常关键和重要的一部分。试想一个项目中没有一个好的异常处理,这个项目会怎么样?
异常其实是程序上的错误,包括程序逻辑错误和系统错误。比如数组下标越界、内存溢出等,这些都是意外的情况,错误在我们的程序的编写过程中会经常发生,包括编译期间和运行期间的错误。在编译期间出现的错误编译器会帮助我们修正,可是在运行期间的错误编译器就无能为力了,并且运行期间的错误往往是难以预料的。
程序出现了错误,我们不能不去处理,这样的程序的健壮性太差了。为了提高程序的健壮性我们要合理的解决这些错误!于是Java中提供了异常的处理机制,通过异常来处理程序运行期间中出现的错误。通过这一特性,我们可以很好的提高程序的健壮性。
Java是一个全面的面向对象语言,不像PHP那样,既支持过程式编程,也支持面向对象编程。Java中异常的父类是java.lang.Throwable类。在Java中定义很多的的异常类,比如OutOfMenoryError、NullPointerException、IndexOutOfBoundsException等。
所有的异常类是从 java.lang.Exception 类继承的子类。
异常类有两个主要的子类:IOException 类和 RuntimeException 类。
Exception,也就是我们经常见到的一些异常情况,例如NullPointerException、IndexOutOfBoundsException等,这些异常时是我们可以处理的异常。
Exception类的异常包括checked exception和unchecked exception(unchecked exception也称作运行时异常RuntimeException,Exception类的异常都是在运行期间发生的),对于运行时异常,Java编译器不要求必须进行异常处理捕获处理或者抛出,这个由程序员自行决定。
checked exception(检查异常),也称为非运行时异常(运行时异常以外的异常就是非运行时异常),Java编译器强制程序员必须捕获处理,比如常见的IOException和SQLException。对于非运行时异常如果不进行捕获或者抛出处理,Java编译器都不会通过。
在网上找了一个图,能够很清楚的描述在Java中, 异常类的结构层次 (有些时候语言就略显苍白,不如图片或者视频表现力丰富)。
在Java中,所有的异常都是继承至java.lang.Throwable类。Error类是error类型异常的父类,Exception类是exception类型异常的父类,RuntimeException类是所有运行时异常的父类,RuntimeException以外的并且继承Exception的类是非运行时异常。
在Java中如果需要处理异常,必须先对异常进行捕获(这一点是和PHP是相同的)。使用try和catch关键字进行处理。具体的规则如下:
try{ // 程序代码 }catch(异常类型1 异常的变量名1){ // 程序代码 }catch(异常类型2 异常的变量名2){ // 程序代码 }finally{ // 程序代码 }
来段实际的代码:
import java.io.*; public class ExcepTest{ public static void main(String args[]){ try { File file = new File("/Users/sam/a.txt"); if(!file.exists()) file.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } }
被try块包围的代码说明这段代码可能会发生异常,一旦发生异常,异常便会被catch捕获到,然后需要在catch块中进行异常处理。这是一种处理异常的方式。在Java中还提供了另一种异常处理方式即抛出异常,顾名思义,也就是说一旦发生异常,我把这个异常抛出去,让调用者去进行处理,自己不进行具体的处理,此时需要用到throw和throws关键字。
我们看下面的代码:
public class Main { public static void main(String[] args) { try { createFile(); } catch (Exception e) { // TODO: handle exception } } public static void createFile() throws IOException{ File file = new File("/Users/sam/a.txt); if(!file.exists()) file.createNewFile(); } }
这段代码和上面一段代码的区别是,在实际的createFile方法中并没有捕获异常,而是用throws关键字声明抛出异常,即告知调用者此方法可能会抛出IOException,需要调用者进行捕获处理。那么在main方法中调用createFile方法的时候,采用try...catch块进行了异常捕获处理。
还可以使用throw关键字进行抛出异常。看下面的例子:
package exception; /** * Created by Sam on 18/6/17. */ public class Main { public static void main(String[] args){ People people = new People("Sam",new Byte("25")); people.sayAge(); } } class People { private String name; private Byte age; public People(String name, Byte age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Byte getAge() { return age; } public void setAge(Byte age) { this.age = age; } public Byte sayAge(){ if (age > Byte.MIN_VALUE){ throw new MyException("年龄太大了","100" ); } return age; } } public class MyException extends RuntimeException { private String code; public MyException(String message, String code) { super(message); this.code = code; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } }
上面就是利用throw关键字进行手动抛出异常。调用者可以捕获处理异常,也可以不用处理异常。下面我们就修改一下代码进行捕获处理:
public class Main { public static void main(String[] args){ People people = new People("Sam",new Byte("25")); try { people.sayAge(); }catch (Exception e){ System.out.println(e); } } } 程序输出: exception.MyException: 年龄太大了
也就说在Java中进行异常处理的话,对于可能会发生异常的代码,可以选择三种方法来进行异常处理:
1、对代码块用try..catch进行异常捕获处理;
2、在该代码的方法体外用throws进行抛出声明,告知此方法的调用者这段代码可能会出现这些异常,你需要谨慎处理。此时有两种情况:
如果声明抛出的异常是非运行时异常,此方法的调用者必须显示地用try..catch块进行捕获或者继续向上层抛出异常。
如果声明抛出的异常是运行时异常,此方法的调用者可以选择地进行异常捕获处理。
3、在代码块用throw手动抛出一个异常对象,此时也有两种情况,跟2)中的类似:
如果抛出的异常对象是非运行时异常,此方法的调用者必须显示地用try..catch块进行捕获或者继续向上层抛出异常。
如果抛出的异常对象是运行时异常,此方法的调用者可以选择地进行异常捕获处理。(如果最终将异常抛给main方法,则相当于交给jvm自动处理,此时jvm会简单地打印异常信息)
关于Java的异常机制就暂时说到这里。
最后更新于 2018-06-29 09:23:18 并被添加「java Java学习系列文章」标签,已有 1 位童鞋阅读过。