您的位置:首页 > 编程语言 > Java开发

Java中的异常和处理详解

2017-09-13 19:50 477 查看

简介

程序运行时,发生的不被期望的事件,它阻止了程序按照程序员的预期正常执行,这就是异常。异常发生时,是任程序自生自灭,立刻退出终止,还是输出错误给用户?或者用C语言风格:用函数返回值作为执行状态?。

Java提供了更加优秀的解决办法:异常处理机制。

异常处理机制能让程序在异常发生时,按照代码的预先设定的异常处理逻辑,针对性地处理异常,让程序尽最大可能恢复正常并继续执行,且保持代码的清晰。
Java中的异常可以是函数中的语句执行时引发的,也可以是程序员通过throw 语句手动抛出的,只要在Java程序中产生了异常,就会用一个对应类型的异常对象来封装异常,JRE就会试图寻找异常处理程序来处理异常。

Throwable类是Java异常类型的顶层父类,一个对象只有是 Throwable 类的(直接或者间接)实例,他才是一个异常对象,才能被异常处理机制识别。JDK中内建了一些常用的异常类,我们也可以自定义异常。

Java异常的分类和类结构图

Java标准裤内建了一些通用的异常,这些类以Throwable为顶层父类。

Throwable又派生出Error类和Exception类。

错误:Error类以及他的子类的实例,代表了JVM本身的错误。错误不能被程序员通过代码处理,Error很少出现。因此,程序员应该关注Exception为父类的分支下的各种异常类。

异常:Exception以及他的子类,代表程序运行时发送的各种不期望发生的事件。可以被Java异常处理机制使用,是异常处理的核心。

class Father
{
public void start() throws IOException
{
throw new IOException();
}
}

class Son extends Father
{
public void start() throws Exception
{
throw new SQLException();
}
}
/**********************假设上面的代码是允许的(实质是错误的)***********************/
class Test
{
public static void main(String[] args)
{
Father[] objs = new Father[2];
objs[0] = new Father();
objs[1] = new Son();

for(Father obj:objs)
{
//因为Son类抛出的实质是SQLException,而IOException无法处理它。
//那么这里的try。。catch就不能处理Son中的异常。
//多态就不能实现了。
try {
obj.start();
}catch(IOException)
{
//处理IOException
}
}
}
}


View Code

2、Java程序可以是多线程的。每一个线程都是一个独立的执行流,独立的函数调用栈。如果程序只有一个线程,那么没有被任何代码处理的异常 会导致程序终止。如果是多线程的,那么没有被任何代码处理的异常仅仅会导致异常所在的线程结束。

也就是说,Java中的异常是线程独立的,线程的问题应该由线程自己来解决,而不要委托到外部,也不会直接影响到其它线程的执行。

finally块和return

首先一个不容易理解的事实:在 try块中即便有return,break,continue等改变执行流的语句,finally也会执行。

public static void main(String[] args)
{
int re = bar();
System.out.println(re);
}
private static int bar()
{
try{
return 5;
} finally{
System.out.println("finally");
}
}
/*输出:
finally
5
*/


很多人面对这个问题时,总是在归纳执行的顺序和规律,不过我觉得还是很难理解。我自己总结了一个方法。用如下GIF图说明。



也就是说:try...catch...finally中的return 只要能执行,就都执行了,他们共同向同一个内存地址(假设地址是0x80)写入返回值,后执行的将覆盖先执行的数据,而真正被调用者取的返回值就是最后一次写入的。那么,按照这个思想,下面的这个例子也就不难理解了。

finally中的return 会覆盖 try 或者catch中的返回值。

public static void main(String[] args)
{
int result;

result  =  foo();
System.out.println(result);     /////////2

result = bar();
System.out.println(result);    /////////2
}

@SuppressWarnings("finally")
public static int foo()
{
trz{
int a = 5 / 0;
} catch (Exception e){
return 1;
} finally{
return 2;
}

}

@SuppressWarnings("finally")
public static int bar()
{
try {
return 1;
}finally {
return 2;
}
}


finally中的return会抑制(消灭)前面try或者catch块中的异常

class TestException
{
public static void main(String[] args)
{
int result;
try{
result = foo();
System.out.println(result);           //输出100
} catch (Exception e){
System.out.println(e.getMessage());    //没有捕获到异常
}

try{
result  = bar();
System.out.println(result);           //输出100
} catch (Exception e){
System.out.println(e.getMessage());    //没有捕获到异常
}
}

//catch中的异常被抑制
@SuppressWarnings("finally")
public static int foo() throws Exception
{
try {
int a = 5/0;
return 1;
}catch(ArithmeticException amExp) {
throw new Exception("我将被忽略,因为下面的finally中使用了return");
}finally {
return 100;
}
}

//try中的异常被抑制
@SuppressWarnings("finally")
public static int bar() throws Exception
{
try {
int a = 5/0;
return 1;
}finally {
return 100;
}
}
}


finally中的异常会覆盖(消灭)前面try或者catch中的异常

class TestException
{
public static void main(String[] args)
{
int result;
try{
result = foo();
} catch (Exception e){
System.out.println(e.getMessage());    //输出:我是finaly中的Exception
}

try{
result  = bar();
} catch (Exception e){
System.out.println(e.getMessage());    //输出:我是finaly中的Exception
}
}

//catch中的异常被抑制
@SuppressWarnings("finally")
public static int foo() throws Exception
{
try {
int a = 5/0;
return 1;
}catch(ArithmeticException amExp) {
throw new Exception("我将被忽略,因为下面的finally中抛出了新的异常");
}finally {
throw new Exception("我是finaly中的Exception");
}
}

//try中的异常被抑制
@SuppressWarnings("finally")
public static int bar() throws Exception
{
try {
int a = 5/0;
return 1;
}finally {
throw new Exception("我是finaly中的Exception");
}

}
}


上面的3个例子都异于常人的编码思维,因此我建议:

不要在fianlly中使用return。

不要在finally中抛出异常。

减轻finally的任务,不要在finally中做一些其它的事情,finally块仅仅用来释放资源是最合适的。

将尽量将所有的return写在函数的最后面,而不是try ... catch ... finally中。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: