回顾异常处理机制:
异常机制使程序中异常处理代码和正常业务代码分离,也就是把某些异常交给异常处理器去处理,不让JVM直接处理。
JMV的处理方式时打印异常跟踪栈的信息,并终止程序运行,比如:
[java]
public static void main(String[] args) {
System.out.println(1 / 0); // 程序抛出java.lang.ArithmeticException: / by zero 然后程序结束。
... // 下面的代码无法得到执行。
}
public static void main(String[] args) {
System.out.println(1 / 0); // 程序抛出java.lang.ArithmeticException: / by zero 然后程序结束。
... // 下面的代码无法得到执行。
}于是乎,我来捕捉一下这个异常好了:
[java]
public static void main(String[] args) {
try {
System.out.println(1 / 0); // 如果捕捉到异常,生成对应的异常类的对象
}catch(ArithmeticException ae) { // 如果捕捉到异常对象,进行自定义异常处理
ae.printStackTrace(); // 简单的异常处理,打印异常的跟踪栈信息
}
System.out.println("main方法结束"); // 这就是异常处理代码和正常业务代码分离的好处,逻辑上清晰,并且单独处理被捕获的异常。
}
public static void main(String[] args) {
try {
System.out.println(1 / 0); // 如果捕捉到异常,生成对应的异常类的对象
}catch(ArithmeticException ae) { // 如果捕捉到异常对象,进行自定义异常处理
ae.printStackTrace(); // 简单的异常处理,打印异常的跟踪栈信息
}
System.out.println("main方法结束"); // 这就是异常处理代码和正常业务代码分离的好处,逻辑上清晰,并且单独处理被捕获的异常。
}问,上面的异常需要被捕捉吗?算术异常.
如果按照平常思维来思考,程序运行时有异常退出就行了。还捕捉啥呢?还干嘛分为checked异常跟runtime异常呢?
1:捕捉异常是为了让程序单独处理被捕获的异常。
2:区分checked异常跟runtime异常,是为了增强程序健壮性。
checked(知道编译时可能会有问题,我能处理,或者你来处理,最后必须处理(抛向JVM)),编译时就必须给我说清楚怎么处理。
runtime(知道运行时可能会有问题,我愿意处理就处理,你爱处理不处理),运行期出了错你负责。
无论是哪种异常,都不一定100%发生异常,100%发生异常的代码?你会写吗?你会写编译器让你写吗?
分析与解读:
运行时异常意思就是:编译时无法发现只有在运行时才会出现的异常,比如NullPointerException,编译期是无法判断的。
如果发生了问题一定是代码bug所致,至于会不会发生问题,要看什么时候程序会运行到出错的地方。
对于运行时异常,如果知道可能会有问题,又不影响编译,那就向上抛出就好了。声明让调用者处理该运行时异常(站在设计者的角度)。
运行时异常即使使用try...catch块进行捕捉,那也不是真正能处理掉的,下次程序执行到这又会出现异常,因为代码本身有Bug.
如果不用异常类去描述这些异常,那程序出现异常了,岂不死翘翘了,所以说,异常的出现是为了增强程序健壮性。
其它的runtime异常类像:IndexOuterOfBoundsException、ArithmeticException、ClassCastException
checked异常意思就是:编译时就知道这个地方可能会出现异常,你的程序代码很健康,但是编译器知道你的代码中某个操作会出现问题,或者说你的代码中的某个操作已经抛出异常了,你必须对其进行处理。
比如FileInputStream fis = new FileInputStream("a.txt"); 此构造抛出FileNotFoundException,所以调用者必须处理该异常,否则编译不通过。
上面的操作是通过打开一个到实际文件的连接来创建一个FileInputStream,文件会100%不存在吗?如果发生错误了肯定是在运行时吧?
那这老家伙为何抛出编译时异常呢?!他只是觉得你必须对可能产生的异常进行捕捉罢处理了,认为你能搞定的。怎么搞看你需求。
看一下他的构造器源码:
[java]
public FileInputStream(String name) throws FileNotFoundException { // 他抛出了编译时异常
this(name != null new File(name) : null);
}
public FileInputStream(String name) throws FileNotFoundException { // 他抛出了编译时异常
this(name != null new File(name) : null);
}再来看一下File构造器的源码:
[java]
public File(String pathname) {
if (pathname == null) { // 他抛的是运行时异常!注意是throw,不是throws。
throw new NullPointerException();
}
this.path = fs.normalize(pathname);
this.prefixLength = fs.prefixLength(this.path);
}
public File(String pathname) {
if (pathname == null) { // 他抛的是运行时异常!注意是throw,不是throws。
throw new NullPointerException();
}
this.path = fs.normalize(pathname);
this.prefixLength = fs.prefixLength(this.path);
}看出问题了吗?FileInputStream构造器亦可以不处理或者捕获处理该File构造器抛出的运行时异常,但他之所以选择抛出编译时异常,是觉得需要处理并且有能力处理该异常。
再来看InputStream类的public abstract int read() throws IOException; read方法涉及到I/O操作,需要访问外部资源。由于外部资源不受JVM控制,
所以有可能会出现异常,操作失败或者操作中断或者没有权限访问。对于这些可能出现的异常,不也是运行时才能出现的吗?抛出IOException,还是觉得需要处理罢了。增强程序健壮性。
有人说他内部也没有再去调用抛出运行时异常的方法了啊?这里read方法做的是访问系统底层操作,代码不是Java写滴。
透彻理解编译时异常(checked):到底编译时异常是个啥玩意?我都没有运行程序咋还就出现异常了?别叫名字给骗