国内最全IT社区平台 联系我们 | 收藏本站
华晨云阿里云优惠2
您当前位置:首页 > php开源 > php教程 > Java中的异常处理机制

Java中的异常处理机制

来源:程序员人生   发布时间:2017-02-13 08:08:39 阅读次数:3186次

学习Java的同学注意了!!! 
学习进程中遇到甚么问题或想获得学习资源的话,欢迎加入Java学习交换群,群号码:183993990  我们1起学Java!


异常机制已成为判断1门编程语言是不是成熟的标准,异常机制可使程序中异常处理代码和正常业务代码分离,保证程序代码更加优雅,并提高程序硬朗性。

         Java异常机制主要依赖于try、catch、finally、throw、throws5个关键字。

         1.try:它里面放置可能引发异常的代码

         2.catch:后面对应异常类型和1个代码块,用于表明该catch块用于处理这类类型的代码块,可以有多个catch块。

         3.finally:主要用于回收在try块里打开的物力资源(如数据库连接、网络连接和磁盘文件),异常机制总是保证finally块总是被履行。只有finally块,履行完成以后,才会回来履行try或catch块中的return或throw语句,如果finally中使用了return或   throw等终止方法的语句,则就不会跳回履行,直接停止。

         4.throw:用于抛出1个实际的异常,可以单独作为语句使用,抛出1个具体的异常对象。

         5.throws:用在方法签名中,用于声明该方法可能抛出的异常。

 

       Java的异常分为两种,checked异常(编译时异常)和Runtime异常(运行时异常)

1.       java认为checked异常都是可以再编译阶段被处理的异常,所以它强迫程序处理所有的checked异常,而Runtime异常不必处理,java程序必须显式处理checked异常,如果程序没有处理,则在编译时会产生毛病,没法通过编译。

2.       checked异常体现了java设计哲学:没有完善处理的代码根本不会被履行,体现了java的严谨性,

     对构造大型、硬朗、可保护的利用系统而言,毛病处理是全部利用需要斟酌的重要方面。Java异常处理机制,在程序运行出现意外时,系统会生成1个Exception对象,来通知程序,从而实现将“业务功能实现代码”和“毛病处理代码”分离,提供更好的可读性。

     如果履行try块里的业务逻辑代码时出现异常,系统会自动生成1个异常对象,该异常对象被提交给运行环境,这个进程被称为抛出(throw)异常。Java环境收到异常对象时,会寻觅适合的catch块,如果找不到,java运行环境就会终止,java程序将退出。

     不同的catch块,视为了针对不同的异常类,提供不同的处理方法。

 

对毛病处理机制,主要有以下的两个缺点:

1.没法穷举所有异常情况:由于人类的知识是有限的,异常情况总比可以斟酌到的情况多,总有漏网之鱼

2.毛病处理代码和业务实现代码混杂严重影响程序的可读性,会增加程序保护的难度。

1.使用try...catch捕获异常

java提出了1种假定,如果程序可以顺利完成,那末1切正常,把系统的业务实现代码放在try块中定义,所有的异常处理逻辑放在catch块中进行处理。

即:try{

//业务实现代码

...

}

catch(Exception e){

输入不合法

}

上面的格式中try块和catch块后的{...}都是不可以省略的!

履行步骤:

1.如果履行try块中的业务逻辑代码时出现异常,系统自动生成1个异常对象,该异常对象被提交给java运行环境,这个进程称为抛出(throw)异常。

2.当java运行环境收到异常对象时,会寻觅能处理该异常对象的catch块,如果找到适合的cathc块并把该异常对象交给catch块处理,那这个进程称为捕获(catch)异常;如果java运行时环境找不到捕获异常的catch块,则运行时环境终止,jav程序也将退出。

注意1:不管程序代码块是不是处于try块中,乃至包括catch块中代码,只要履行该代码时出现了异常,系统都会自动生成1个异常对象,如果程序没有为这段代码定义任何catch块,java运行环境肯定找不到处理该异常的catch块,程序肯定在此退出。

注意2:try块后可以有多个catch块,try块后使用多个catch块是为了针对不同异常类提供的不同的异常处理方式。当系统产生不同意外情况时,系统会生成不同的异常对象,java运行时就会根据该异常对象所属的异常类来决定使用哪一个catch块来处理该异常。

注意3:通常情况下,如果try块被履行1次,则try块后只有1个catch块会被履行,绝不可能有多个catch块被履行,除非在循环中使用类continue开始下1次循环,下1次循环又重新运行了try块,这才可能致使多个catch块被履行。

注意4:进行异常捕获时,1定要记住先捕获小的异常,再捕获大的异常。

 

Java的异常类,和他们的继承关系:

 java把所有非正常情况分成两种:异常(Exception)和毛病(Error),都是继承自Throwable父类。

 Error毛病:1般是指虚拟机相干的问题,如系统崩溃,虚拟机出毛病等,这类毛病没法恢复或不可能捕获,将致使利用程序中断,通常不处理。

 

         Throwable():Throwable 类是 Java 语言中所有毛病或异常的超类。只有当对象是此类(或其子类之1)的实例时,才能通过 Java 虚拟机或 Java throw 语句抛出。类似地,只有此类或其子类之1才可以是 catch 子句中的参数类型。

         1.Error(毛病):1般是指java虚拟机相干的问题,如系统崩溃、虚拟机出毛病、动态链接失败等,这类毛病没法恢复或不可能捕获,将致使利用程序中断,通常利用程序没法处理这些毛病,因此利用程序不应当捕获Error对象,也不必在其throws子句中声明该方法抛出任何Error或其子类。

         2.Exception:Exception 类及其子类是 Throwable 的1种情势,它指出了公道的利用程序想要捕获的条件

         (1). SQLException:该异常提供关于数据库访问毛病或其他毛病的信息。

         (2). RuntimeException 是那些可能在 Java 虚拟机正常运行期间抛出的异常的超类

         (3).IOException:此类为异常的通用类,它是由失败的或中断的 I/O 操作生成的。

异常对象包括的经常使用方法:

1.       getMessage();返回该异常的详细描写字符

2.       printStackTrace():将该异常的跟踪栈信息输出到标准毛病输出。

3.       printStackTrace(PrintStream s):将该异常的跟踪栈信息输出到指定的输出流

4.       getStackTrace():返回该异常的跟踪栈信息。

复制代码
 1 public class TestException
 2 {
 3 
 4 public static void main(String[] args)
 5 {
 6 
 7     try{
 8         FileInputStream fis=new FileInputStream("a.txt");
 9        }
10     catch(IOException ioe)
11     {
12         System.out.println(ioe.getMessage());
13         ioe.printStackTrace();
14     }
15 
16 }
17 
18 }
复制代码

 

 

使用finally回收资源

 有时候,程序在try块里面打开了1些物力资源(比如数据库连接,网络连接好磁盘文件等),这些物理资源都必须显式回收。

由于:java的垃圾回收机制不会回收任何的物理资源,垃圾回收机制只回收堆内存中对象所占用的内存。

 

问题1:那末在哪边回收这些物理资源呢?

答:在finally块中,由于如果try块的某条语句引发1场,该语句后的其他语句通常不会被履行,那将致使位于该语句后的资源回收语句得不到履行;如果在catch块里进行资源回收,但catch块完全有可能得不到履行,这也将致使不能及时回收这些物理资源。所以我们不管try块中的代码是不是出现异常,也不管哪一个catch块会被履行,finally块总会被履行。

那末:java异常处理的完全语法结构以下:

try
{
     //业务实现逻辑
     ...
}
catch(SubException e)
{
     //异常处理快1
     ...
}
catch(SubException2 e)
{
     //异常处理快2
     ...
}
     ...
finally
{
    //资源回收块
    ...
}

以上的异常处理语法结构中
注意点1:只有try块石必须的,也就是说如果没有try块,则不可能有后面的catch块和finally块;
注意点2:catch块和finally块都是可选的,但catch块和finally块最少出现其中之1,也能够同时出现;
注意点3:可以有多个catch块,捕获父类异常的catch块必须位于捕获子类异常的后面;
注意点4:不能只有try块,既没有catch块,也没有finally块;
注意点5:多个catch块必须位于try块以后,finally块必须位于所有catch块以后。

复制代码
 1 import java.io.FileInputStream;
 2 import java.io.IOException;
 3 
 4 public class TestException
 5 {
 6 
 7     /**
 8      * @param args
 9      */
10     public static void main(String[] args)
11     {
12         // TODO Auto-generated method stub
13         FileInputStream fis = null;
14         try
15         {
16             fis = new FileInputStream("a.txt");
17         } catch (IOException ioe)
18         {
19             System.out.println(ioe.getMessage());
20             // return语句强迫方法返回
21             return;
22             // 使用exit来退出虚拟机
23             // System.exit(1);
24         } finally
25         {
26             // 关闭磁盘文件,回收资源
27             if (fis != null)
28             {
29                 try
30                 {
31                     fis.close();
32                 } catch (IOException ioe)
33                 {
34                     ioe.printStackTrace();
35                 }
36             }
37             System.out.println("程序已履行了finally里德资源回收");
38         }
39     }
40 
41 }
复制代码

运行程序结果:
a.txt (系统找不到指定的文件。)
程序已履行了finally里德资源回收

如果将catch块中的最后两句注释放入程序,那末结果为:a.txt (系统找不到指定的文件。)

 以上两种情况显示:除非在try块或catch块中调用了退出虚拟机的方法(即System.exit(1);),否则不管在try块、catch块中履行怎样的代码,出现怎样的情况,异常处理的finally块总是会被履行的。不过,1般情况下,不要再finally块中使用renturn或throw等致使方法终止的语句,由于1旦使用,将会致使try块、catch块中的return、throw语句失效。

 

 

复制代码
 1 public class TestException1
 2 {
 3 
 4     public static boolean test()
 5     {
 6         try
 7         {
 8             return true;
 9         } finally
10         {
11             return false;
12         }
13     }
14 
15     public static void main(String[] args)
16     {
17         boolean a = test();
18         System.out.println(a);
19     }
20 
21 }
复制代码

 

 

运行结果:false

以上的小程序说明:在finally块中定义了1个renturn false语句,这将致使try块中的return true 失去作用!

总结1下这个小问题:

当程序履行try块,catch块时遇到return语句或throw语句,这两个语句都会致使该方法立即结束,所以系统其实不会立即履行这两个语句,而是去寻觅该异常处理流程中的finally块,如果没有finally块,程序立即履行return语句或throw语句,方法终止。如果有finally块,系统立即开始履行finally块,只有当finally块履行完成后,系统才会再次跳回来履行try块、catch块里的return或throw语句,如果finally块里也使用了return或throw等致使方法终止的语句,则finally块已终止了方法,不用再跳回去履行try块、catch块里的任何代码了。

综上:尽可能避免在finally块里使用return或throw等致使方法终止的语句,否则可能出现1些很奇怪的情况!

异常处理的嵌套

例如catch块中再次包括了1个完全的异常处理流程,这类在try块,catch块或finally块中包括完全的异常处理流程的情形称为异常处理的嵌套。异常处理流程的代码可以放在任何可履行代码的地方,因此完全的异常处理流程既可放在try块,也可放在catch块,也可放在finally块里。

嵌套的深度没有很明确的限制,通常没有必要写层次太深的嵌套异常处理,会致使程序可读性下降。

 Checked异常和Runtime异常体系

 java异常被分为两大类:Checked异常和Runtime异常(运行时异常)。

所有RuntimeException类及其子类的实例被称为Runtime异常,不是RuntimeException类及其子类的异常实例则被称为Checked异常。

只有java语言提供了Checked异常,其他语言都没有提供,java认为Checked异常都是可以被处理(修复)的异常,所以java程序不必显式的处理Checked异常。如果程序没有处理Checked异常,该程序在编译时就会产生毛病,没法通过编译。

Checked异常的处理方式:

①:当方法明确知道如何处理异常,程序应当使用try...catch块来捕获该异常,然后在对应的catch块中修补该异常。

②:当方法不知道如何处理异常,应当在定义该方法时声明抛出该异常。

Runtime异常不必显式声明抛出,如果程序需要捕捉Runtime异常,也能够使用try...catch块来捕获Runtime异常。

问题是:大部份的方法总是不能明确知道如何处理异常,这就只能声明抛出异常了。

使用throws抛出异常

使用throws抛出异常的思路是:当前方法不知道如何处理这类类型的异常,该异常应当由上1级调用者处理,如果main方法也不知道应当如何处理这类类型的异常,也能够使用使用throws声明抛出异常,该异常将交给JVM来处理。

JVM对异常的处理方法:打印异常跟踪栈的信息,并终止程序运行,所以有很多程序遇到异常后自动结束。

使用throws抛出异常的格式:

throws声明的抛出的语法格式紧跟在方法以后,可以声明多个异常类,多个异常类之间以逗号隔开。1旦使用了throws语句声明抛出异常,就不用再使用try...catch来捕获异常了。

如:throws ExceptionClass1,ExceptionClass2...

注意点1:如果某段代码调用了1个带throws声明的方法,该方法声明抛出了Checked异常,这表明该方法希望它的调用者来处理该异常。那末这段代码要末放在try块中显示捕获该异常,要末这段代码处于另外一个带throws声明抛出的方法中。

举例以下:

复制代码
 1 //方法1:
 2 
 3 import java.io.FileInputStream;
 4 import java.io.IOException;
 5 
 6 public class TestException2
 7 {
 8 
 9     // test() 方法抛出了异常,那末test()方法的调用者要末放在try块中显示捕获该异常,要末这段代码处于另外一个带throws声明抛出的方法中。
10 
11     // 以下为后者的处理方法
12 
13     public static void test() throws IOException
14     {
15         FileInputStream fis = new FileInputStream("a.txt");
16     }
17 
18     public static void main(String[] args) throws Exception
19     {
20         test();
21     }
22 
23 }
复制代码
复制代码
 1 //方法2:
 2 
 3 import java.io.FileInputStream;
 4 import java.io.IOException;
 5 
 6 public class TestException2
 7 {
 8 

 生活不易,码农辛苦
如果您觉得本网站对您的学习有所帮助,可以手机扫描二维码进行捐赠
程序员人生
------分隔线----------------------------
分享到:
------分隔线----------------------------
关闭
程序员人生