异常
不管你愿不愿意你在编程中总是会遇到各种各样的异常,虽然很不想看到。但是有异常,不见得是一件坏事,有异常说明我们的程序有问题,这有助于我们及时的改正程序。
定义
Java为我们提供了很完整的异常处理机制,如图为Java的异常体系。
从上图可以看出,主要分为两大类,一类是Erro,一类是Exception。
分类
Error是程序无法处理的错误,比如OutOfMemoryError、ThreadDeath等。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。
Exception是程序本身可以处理的异常,这种异常分两大类:非运行时异常(发生在编译阶段,又称checkException)和运行时异常(发生在程序运行过程中,又叫RuntimeException)。非运行时异常一般就是指一些没有遵守Java语言规范的代码,容易看的出来,并且容易解决的异常,运行时异常是那些在程序运行过程中产生的异常,具有不确定性,如空指针异常等,造成空指针的原因很多,所以运行时异常具有不确定性,往往难以排查,还有就是程序中存在的逻辑错误,光从一段代码中看不出问题,需要纵观全局才能发现的错误,也会造成运行时异常,这就要求我们在写程序时多多注意,尽量处理去处理异常,当异常发生时,希望程序能朝理想的方面运行。
异常处理
JVM处理
如果说我们的代码中出现了异常但是我们并没有做异常处理,这时候JVM就会自动处理异常,处理方式也就是打印堆栈信息,同时停止程序。
int a = 1,b = 0;
System.out.println(a/b);
上述代码会出现ArithmeticExceptionJVM就会向控制台输出异常信息,然后停掉进程。
用try…catch…finally处理异常
当然我们使用try…catch…finally语句块手动的捕获异常然后处理,处理格式如下:
try {
可能出现问题的代码 ;
}catch(异常名 变量名){
针对问题的处理 ;
}finally{
释放资源;
}
例如上面的代码异常我们用try…catch…finally语句块处理
int a=1;
int b=0;
try {
System.out.println(a / 0);
}catch (ArithmeticException e){
System.out.println("除数为0了");
}finally{
System.out.println("我一定会执行");
}
这时程序就会执行catch的语句块并且不会停掉进程而不是打印堆栈信息然后停掉进程了。而且不论程序是否发生异常,finally 代码块总是会执行。所以 finally 一般用来关闭资源。
自定义异常
Java 确实给我们提供了非常多的异常,但是异常体系是不可能预见所有的希望加以报告的错误,所以 Java 允许我们自定义异常来表现程序中可能会遇到的特定问题。
Java 自定义异常的使用要经历如下四个步骤:
1、定义一个类继承 Throwable 或其子类。
2、添加构造方法(当然也可以不用添加,使用默认构造方法)。
3、在某个方法类抛出该异常。
4、捕捉该异常。
public class MyException extends Exception{
public MyException(){
}
public MyException(String message){
super(message);
}
}
public class Test {
public void display(int i) throws MyException{
if(i == 0){
throw new MyException("该值不能为0.......");
}
else{
System.out.println( i / 2);
}
}
public static void main(String[] args) {
Test test = new Test();
try {
test.display(0);
System.out.println ("---------------------");
} catch (MyException e) {
e.printStackTrace();
}
}
}
异常使用注意事项
1.尽可能的减小try块,因为如果try代码块过于冗杂的话当抛出异常时我们很难找到问题出在那一块,所以尽量减小try块。
2.保证所有资源都被正确释放,充分运用 finally 关键词,如果该程序发生了异常那么 conn.close(); out.close();是不可能执行得到的,这样势必会导致资源不能释放掉。所以如果程序用到了文件、Socket、JDBC 连接之类的资源,即使遇到了异常,我们也要确保能够正确释放占用的资源。这里 finally 就有用武之地了:不管是否出现了异常,finally 总是有机会运行的,所以 finally 用于释放资源是再适合不过了。
3.catch 语句应当尽量指定具体的异常类型,而不应该指定涵盖范围太广的 Exception 类。 不要一个 Exception 试图处理所有可能出现的异常,大家都知道这样可以,但是这和没有处理有什么区别????你还不如把它抛上去,所以尽量的细化异常,不同的异常对应不同的处理方式。
4.捕获异常不做处理,就是我们所谓的丢弃异常。们都知道异常意味着程序出现了不可预期的问题,程序它希望我们能够做出处理来拯救它,但是你呢?一句 ex.printStackTrace() 搞定,这是多么的不负责任对程序的异常情况不理不顾。虽然这样在调试可能会有一定的帮助,但是调试阶段结束后呢?不是一句 ex.printStackTrace() 就可以搞定所有的事情的!
改进
1、处理异常。对所发生的的异常进行一番处理,如修正错误、提醒。再次申明 ex.printStackTrace() 算不上已经“处理好了异常”.
2、重新抛出异常。既然你认为你没有能力处理该异常,那么你就尽情向上抛吧。
3、封装异常。这是我认为最好的处理方法,对异常信息进行分类,然后进行封装处理。
4、不要捕获异常。
throw和throws的区别
throws 是方法抛出异常。在方法声明中,如果添加了 throws 子句,表示该方法即将抛出异常,异常的处理交由它的调用者,至于调用者任何处理则不是它的责任范围内的了。所以如果一个方法会有异常发生时,但是又不想处理或者没有能力处理,就使用 throws 吧!(对于checkedException我们一般处理就是throws)
而 throw 是语句抛出异常。它不可以单独使用,要么与 try…catch 配套使用,要么与 throws 配套使用
//使用throws抛出异常
public void f() throws MyException{
try {
FileReader reader = new FileReader("G:\\myfile\\struts.txt");
Scanner in = new Scanner(reader);
System.out.println(in.next());
} catch (FileNotFoundException e) {
throw new MyException("文件没有找到", e); //throw
}
}