概述
Java异常
程序在运行过程中发生错误或异常情况是不可避免的,如果每一个运行时错误都要由程序员事先想到并手动控制和处理,其工作量是不可想象的。 Java语言中的异常处理机制就解决的上述问题,把错误与异常的管理以类的方式带到了面向对象的世界,即 Java语言定义了很多异常类,将运行错误和异常的信息和处理方法封装在了异常类中,帮助程序员检查和控制异常 。
一、异常的分类及继承结构
从图中可以看出, Java语言按照错误严重性,从throwale根类衍生出Error和Exception两大派系
1.所有的异常都是从Throwable继承而来的,是所有异常的共同祖先。
2.Throwable有两个子类,Error和Exception。其中Error是错误,对于所有的编译时期的错误以及系统错误都是通过Error抛出的。这些错误表示故障发生于虚拟机自身、或者发生在虚拟机试图执行应用时,如Java虚拟机运行错误(Virtual MachineError)、类定义错误(NoClassDefFoundError)等。 错误对程序而言是致命的,将导致程序无法运行。常见的错误有内存溢出,jvm虚拟机自身的非正常运行,calss文件没有主方法。程序本身是不能处理错误的,只能依靠外界干预。Error是系统内部的错误,由jvm抛出,交给系统来处理。
3.Exception,是另外一个非常重要的异常子类。是程序正常运行中,可以预料的意外情况。比如数据库连接中断,空指针,数组下标越界。异常出现可以导致程序非正常终止,也可以预先检测,被捕获处理掉,使程序继续运行。
异常和错误的区别是,异常是可以被处理的,而错误是没法处理的。
按照性质,异常又分为编译异常(可检测)和运行时异常(不可检测)。
4.Checked Exception
可检查的异常,这是编码时非常常用的,所有checked exception都是需要在代码中处理的。它们的发生是可以预测的,正常的一种情况,可以合理的处理。比如IOException,或者一些自定义的异常。除了RuntimeException及其子类以外,都是checked exception。
5.Unchecked Exception
RuntimeException及其子类都是unchecked exception。比如NPE空指针异常,除数为0的算数异常ArithmeticException等等,这种异常是运行时发生,无法预先捕捉处理的。Error也是unchecked exception,也是无法预先处理的。
我们主要处理的异常是Exception这个派系的,包括运行时异常以及IO异常。
二、Java的异常处理机制
既然程序运行过程中出现异常了会导致程序运行的中断,这当然不是我们想要的,那么我们该怎么办呢?这个问题看起来不是很聪明的样子,看标题就知道出了异常就要处理,处理完了程序就可以继续运行了。那咋个处理才是我们要讨论的事情.。
(一)、两种处理异常的机制
为了可以让我们程序员处理能够预见的异常,确保程序继续运行,Java语言给我们提供了两种异常的处理方式。
1、使用 throw ,throws关键字抛出异常
一个方法不处理这个异常,而是调用层次向上传递,谁调用这个方法,这个异常就由谁来处理。
注意:重写之后的方法不可以比重写之前的方法抛出更大的异常
1.1、throws
将throws关键声明在可能出现异常的方法声明处,就能够将将来程序运行时出现的异常,抛给”上一级“ ,提醒该方法的调用者来处理异常 。所谓上一级就是调用这个出现了异常的方法的调用者,调用者同样需要对这个抛上来的异常进行处理,它的处理方式也有两种。
注意:若是Java中的异常发生之后一直往上抛,且抛的过程中不能解决这个异常,最终抛给了main方法,main方法抛给jvm,jvm知道异常发生后就会终止程序的运行
格式:
修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2 ... { }
示例:
public class Test {
public static void main(String[] args) {
doSome();
}
public static void doSome() throws ClassNotFoundException{
System.out.println("dosome...");
}
}
程序出错的原因是什么?
因为dosome方法在声明位置使用了throws关键字 :throws ClassNotFoundException ,这样做的意思是dosome方法在运行过程中可能会出现ClassNotFoundException,而这个ClassNotFoundException他是编译时异常,编译时异常必须编写代码来处理,否则就会报异常。让它不报错的一个方法是在main方法也使用throws抛出一个ClassNotFoundException异常或者是ClassNotFoundException的父类异常。
当然也可以使用try catch的方式去处理。
1.2、throw
throw用在方法内,用来抛出一个异常对象,将这个异常对象传递到调用者处,并结束当前方法的执行。
使用格式:
throw new 异常类名(参数);
示例:
public class Test {
public static void main(String[] args) {
int a = Test.div(4,0);
System.out.println(a);
}
public static int div(int a,int b)
{
if(b==0)
throw new ArithmeticException(" 除数不能为0异常");//抛出具体问题,编译时不检测
return a/b;
}
}
区别:
1、写法上 : throw 在方法体内使用,throws 函数名后或者参数列表后方法体前
2、意义 : throw 强调动作,而throws 表示一种倾向、可能但不一定实际发生
3、throws 后面跟的是异常类,可以一个,可以多个,多个用逗号隔开。throw 后跟的是异常对象,或者异常对象的引用。
2、使用try catch 方式捕捉异常
关键词try后的一对大括号将一块可能发生异常的代码包起来,称为监控区域。Java方法在运行过程中出现异常,则创建异常对象。将异常抛出监控区域之 外,由Java运行时系统试图寻找匹配的catch子句以捕获异常。若有匹配的catch子句,则运行其异常处理代码,try-catch语句结束。
匹配的原则是:如果抛出的异常对象属于catch子句的异常类,或者属于该异常类的子类,则认为生成的异常对象与catch块捕获的异常类型相匹配。
使用格式:
try {
... //监视代码执行过程,一旦返现异常则直接跳转至catch,
// 如果没有异常则直接跳转至finally
} catch (SomeException e) {
... //可选执行的代码块,如果没有任何异常发生则不会执行;
//如果发现异常则进行处理或向上抛出。
} finally {
... //必选执行的代码块,不管是否有异常发生,
// 即使发生内存溢出异常也会执行,通常用于处理善后清理工作。
}
示例:
public static void main(String[] args) throws ClassNotFoundException {
try {
new FileInputStream("C:file//c.txt");
System.out.println("出现异常后,try代码块中出现异常语句后面的代码不会执行!");
} catch (FileNotFoundException e) {
System.out.println("文件找不到异常!");
}
System.out.println("try catch 捕捉了异常 , 这里的代码继续执行");
}
2.1、try catch 中finally子句的使用
1. 在finally子句中的代码是最后执行且一定会执行的,即使在try中出现了异常;finally子句必须跟try一起出现不能够单独出现。
示例:
public static void main(String[] args) {
FileInputStream inputStream = null;
String str = null;
try {
inputStream = new FileInputStream("C:newFile//text.txt");
str.toString();// 这里一定会出现异常
// inputStream.close(); 若是在这里关闭流的话,一旦出现异常,就关不了了
} catch (Exception e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();// 写在finally子句中即使出现了异常也会被执行
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
关于finally:
finally 块:无论是否捕获或处理异常,finally块里的语句都会被执行。当在try块或catch块中遇到return语句时,finally语句块将在方法返回之前被执行。在以下4种特殊情况下,finally块不会被执行:
1)在finally语句块中发生了异常。
2)在前面的代码中用了System.exit()退出程序。
3)程序所在的线程死亡。
4)关闭CPU。
try、catch、finally语句块的执行顺序:
1)当try没有捕获到异常时:try语句块中的语句逐一被执行,程序将跳过catch语句块,执行finally语句块和其后的语句;
2)当try捕获到异常,catch语句块里没有处理此异常的情况:当try语句块里的某条语句出现异常时,而没有处理此异常的catch语句块时,此异常将会抛给JVM处理,finally语句块里的语句还是会被执行,但finally语句块后的语句不会被执行;
3)当try捕获到异常,catch语句块里有处理此异常的情况:在try语句块中是按照顺序来执行的,当执行到某一条语句出现异常时,程序将跳到catch语句块,并与catch语句块逐一匹配,找到与之对应的处理程序,其他的catch语句块将不会被执行,而try语句块中,出现异常之后的语句也不会被执行,catch语句块执行完后,执行finally语句块里的语句,最后执行finally语句块后的语句;
2.2、有关finally的常见面试题
1、先不要看答案,你以为输出结果是什么?
public static void main(String[] args) {
System.out.println(m());
}
public static int m() {
int i = 10;
try {
return i;
} finally {
i++;
}
}
是11,对吗?
我告诉你,答案是10;意外吧!不是说finally子句会在return前执行吗?怎么会这样?
其实,在Java中有两条更古不变的语法规则:
1.方法体中的代码必须遵循自上而下的顺序依次执行
2.return语句一旦执行,整个方法必须结束
在这个例子中要不违背这两条规则,才行。所以return出现在int i=10; 的下面,所以它的返回值必须是10;同时finally子句还必须要执行且return语句在方法的最后执行,所以方法体的语句上到下依次运行到return i=10 ;的时候还不能被执行但要保持return i=10;这个状态,等到finally子句执行完了才执行return i=10;虽然你finally中i++令i=11;但我return的状态就是i=10;所以最终返回的就是10;
可以看看finally中的 i 是多少
结果:
1.2 final finally finalize 有什么区别
final 关键字
final关键字修饰的类无法被继承
final关键字修饰的方法无法被重写
final关键字修饰的变量无法重新赋值
finally 关键字
和try一起使用,且其子句块中的代码是必须执行的
finalize 标识符
是Object类中的一个方法名,是由垃圾回收器GC负责调用的
3、异常对象的常用方法
3.1、 getMessage(); 获取异常的简单描述信息
3.2、printStackTrace();// 打印异常追踪的堆栈信息
public static void main(String[] args) throws ClassNotFoundException {
FileNotFoundException e = new FileNotFoundException("文件找不到异常!!!!");
String message = e.getMessage();
System.out.println(message);
System.out.println("............................................");
e.printStackTrace();
}
(二)、如何自定义异常类
方法:
定义一个普通类去继承一个异常类,然后添加上一个无参构造器以及一个带有String类型参数的有参构造器,显示调用父类的有参构造器
示例:
public class MyException extends Exception {
public MyException() {}
public MyException(String message) {
super(message);
}
}
测试:
public static void main(String [] args ) {
MyException e = new MyException("我的异常!");
e.printStackTrace();
System.out.println("异常信息:"+e.getMessage());
}
最后
以上就是积极荷花为你收集整理的Java的异常体系Java异常的全部内容,希望文章能够帮你解决Java的异常体系Java异常所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复