Java的异常处理惩罚及应用
当前位置:以往代写 > JAVA 教程 >Java的异常处理惩罚及应用
2019-06-14

Java的异常处理惩罚及应用

Java的异常处理惩罚及应用

副标题#e#

Java 异常处理惩罚是利用 Java 语言举办软件开拓和测试剧本开拓时不容忽视的问题之一,是否举办异常处理惩罚直接干系到开拓出的软件的不变性和结实性。本文系统的叙述了 Java 异常处理惩罚的道理和要领,并罗列了一些实例,使读者对 Java 异常处理惩罚能有一个全面的认识,领略异常处理惩罚机制,能越发机动和有效地在开拓中利用它。

Java 异常处理惩罚引出

假设您要编写一个 Java 措施,该措施读入用户输入的一行文本,并在终端显示该文本。

措施如下:

1 import java.io.*;
2 public class EchoInput {
3      public static void main(String args[]){
4          System.out.println("Enter text to echo:");
5          InputStreamReader isr = new InputStreamReader(System.in);
6          BufferedReader inputReader = new BufferedReader(isr);
7          String inputLine = inputReader.readLine();
8          System.out.println("Read:" + inputLine);
9   }
10 }

阐明上面的代码,在 EchoInput 类中,第 3 行声明白 main 要领;第 4 行提示用户输入文本;第 5、6 行配置 BufferedReader 对像毗连到 InputStreamReader,而 InputStreamReader 又毗连到尺度输入流 System.in;第 7 行读入一行文本;第 8 行用尺度输出流 System.out 显示出该文本。

外貌看来上面的措施没有问题,但实际上,EchoInput 类完全大概呈现问题。要在挪用第 7 行的 readLine 要领时正确读取输入,这几种假设都必需创立:假定键盘有效,键盘能与计较机正常通信;假定键盘数据可从操纵系统传输到 Java 虚拟机,又从 Java 虚拟机传输 inputReader。

大大都环境下上述假设都创立,但不尽然。为此,Java 回收异常要领,以应对大概呈现的错误,并采纳步调举办矫正。在本例中,若试图编译以上代码,将看到以下信息:

Exception in thread "main" java.lang.Error: Unresolved compilation problem:
    Unhandled exception type IOException
    at EchoInput.main(EchoInput.java:7)

从中可以看到,第 7 行挪用 readLine 要领大概堕落:若果然如此,则发生 IOException 来记录妨碍。编译器错误是在汇报您,需要变动代码来办理这个潜在的问题。在 JDK API 文档中,可以看到同样的信息。我们可以看到 readLine 要领,如图 1 所示。

图 1. BufferedReader 类的 readLine 要领的 JDK API 文档

图 1. BufferedReader 类的 readLine 要领的 JDK API 文档

由图 1 可知,readLine 要领有时发生 IOException。如那里理惩罚潜在的妨碍?编译器需要“捕捉”或“声明”IOException。

“捕捉 (catch)”指当 readLine 要领发生错误时截获该错误,并处理惩罚和记录该问题。而“声明 (declare)”指错误大概激发 IOException,并通知挪用该要领的任何代码:大概发生异常。

若要捕捉异常,必需添加一个非凡的“处理惩罚代码块”,来吸收和处理惩罚 IOException。于是措施改为如下:

1 import java.io.*;
2 public class EchoInputHandle {
3      public static void main(String args[]){
4          System.out.println("Enter text to echo:");
5          InputStreamReader isr = new InputStreamReader(System.in);
6          BufferedReader inputReader = new BufferedReader(isr);
7          try{
8              String inputLine = inputReader.readLine();
9              System.out.println("Read:" + inputLine);
10          }
11          catch(IOException exc){
12              System.out.println(“Exception encountered: ” + exc);
13          }
14      }
15 }

新添的代码块包括要害字 try 和 catch(第 7,10,11,13 行),暗示要读取输入。若乐成,则正常运行。若读取输入时错误,则捕捉问题(由 IOException 工具暗示),并采纳相应法子。在本例,回收的处理惩罚方法是输出异常。

若禁绝备捕捉 IOException,仅声明异常,则要出格指定 main 要领大概堕落,并且出格说明大概发生 IOException。于是措施改为如下:

1 import java.io.*;
2 public class EchoInputDeclare {
3      public static void main(String args[]) throws IOException{
4          System.out.println("Enter text to echo:");
5          InputStreamReader isr = new InputStreamReader(System.in);
6          BufferedReader inputReader = new BufferedReader(isr);
7          String inputLine = inputReader.readLine();
8          System.out.println("Read:" + inputLine);
9   }
10 }

从上面的这个简朴的例子中,我们可以看出异常处理惩罚在 Java 代码开拓中不能被忽视。

Java 异常以及异常处理惩罚

可将 Java 异常看作是一类动静,它传送一些系统问题、妨碍及未按划定执行的行动的相关信息。异常包括信息,以将信息从应用措施的一部门发送到另一部门。

#p#分页标题#e#

编译语言为何要处理惩罚异常?为何不在异常呈现位置随时处理惩罚详细妨碍?因为有时候我们需要在系统中交换错误动静,以便凭据统一的方法处理惩罚问题,有时是因为有若干处理惩罚问题的大概方法,但您不知道利用哪一种,此时,可将处理惩罚异常的任务委托给挪用要领的代码。挪用者凡是更能相识问题来历的上下文,能更好简直定规复方法。

图 2 是一个通用动静架构。

图 2. 通用动静架构

图 2. 通用动静架构

从上图可以看出,肯定在运行的 Java 应用措施的一些类或工具中发生异常。呈现妨碍时,“发送者”将发生异常工具。异常大概代表 Java 代码呈现的问题,也大概是 JVM 的相应错误,或基本硬件或操纵系统的错误。

异常自己暗示动静,指发送者传给吸收者的数据“负荷”。首先,异常基于类的范例来传输有用信息。许多环境下,基于异常的类既能识别妨碍本因并能矫正问题。其次,异常还带有大概有用的数据(如属性)。

在处理惩罚异常时,动静必需有吸收者;不然将无法处理惩罚发生异常的底层问题。

在上例中,异常“发生者”是读取文本行的 BufferedReader。在妨碍呈现时,将在 readLine 要领中构建 IOException 工具。异常“吸收者”是代码自己。EchoInputHandle 应用措施的 try-catch 布局中的 catch 块是异常的吸收者,它以字符串形式输出异常,将问题记录下来。

Java 异常类的条理布局

在我们从总体上相识异常后,我们应该相识如安在 Java 应用措施中利用异常,即需要相识 Java 类的条理布局。图 3 是 Java 类的条理布局图。

图 3. Java 类的条理布局

图 3. Java 类的条理布局

在 Java 中,所有的异常都有一个配合的祖先 Throwable(可抛出)。Throwable 指定代码中可用异常流传机制通过 Java 应用措施传输的任何问题的共性。

Throwable 有两个重要的子类:Exception(异常)和 Error(错误),二者都是 Java 异常处理惩罚的重要子类,各自都包括大量子类。

Exception(异常)是应用措施中大概的可预测、可规复问题。一般大大都异常暗示中度到轻度的问题。异常一般是在特定情况下发生的,凡是呈此刻代码的特定要领和操纵中。在 EchoInput 类中,当试图挪用 readLine 要领时,大概呈现 IOException 异常。

Error(错误)暗示运行应用措施中较严重问题。大大都错误与代码编写者执行的操纵无关,而暗示代码运行时 JVM(Java 虚拟机)呈现的问题。譬喻,当 JVM 不再有继承执行操纵所需的内存资源时,将呈现 OutOfMemoryError。

Exception 类有一个重要的子类 RuntimeException。RuntimeException 类及其子类暗示“JVM 常用操纵”激发的错误。譬喻,若试图利用空值工具引用、除数为零或数组越界,则别离激发运行时异常(NullPointerException、ArithmeticException)和 ArrayIndexOutOfBoundException。


#p#副标题#e#

Java 异常的处理惩罚

在 Java 应用措施中,对异常的处理惩罚有两种方法:处理惩罚异常和声明异常。

处理惩罚异常:try、catch 和 finally

若要捕捉异常,则必需在代码中添加异常处理惩罚器块。这种 Java 布局大概包括 3 个部门,

都有 Java 要害字。下面的例子中利用了 try-catch-finally 代码布局。

1 import java.io.*;
2 public class EchoInputTryCatchFinally {
3      public static void main(String args[]){
4          System.out.println("Enter text to echo:");
5          InputStreamReader isr = new InputStreamReader(System.in);
6          BufferedReader inputReader = new BufferedReader(isr);
7          try{
8              String inputLine = inputReader.readLine();
9              System.out.println("Read:" + inputLine);     
10          }
11          catch(IOException exc){
12              System.out.println("Exception encountered: " + exc);
13          }
14          finally{
15             System.out.println("End. ");
16      }
17 }
18}

个中:

try 块:将一个可能多个语句放入 try 时,则暗示这些语句大概抛出异常。编译器知道大概要产生异常,于是用一个非凡布局评估块内所有语句。

catch 块:当问题呈现时,一种选择是界说代码块来处理惩罚问题,catch 块的目标便在于此。catch 块是 try 块所发生异常的吸收者。根基道理是:一旦生成异常,则 try 块的执行中止,JVM 将查找相应的 JVM。

#p#分页标题#e#

finally 块:还可以界说 finally 块,无论运行 try 块代码的功效如何,该块内里的代码必然运行。在常见的所有情况中,finally 块都将运行。无论 try 块是否运行完,无论是否发生异常,也无论是否在 catch 块中得处处理惩罚,finally 块都将执行。

try-catch-finally 法则:

必需在 try 之后添加 catch 或 finally 块。try 块后可同时接 catch 和 finally 块,但至少有一个块。

必需遵循块顺序:若代码同时利用 catch 和 finally 块,则必需将 catch 块放在 try 块之后。

catch 块与相应的异常类的范例相关。

一个 try 块大概有多个 catch 块。若如此,则执行第一个匹配块。

可嵌套 try-catch-finally 布局。

在 try-catch-finally 布局中,可从头抛出异常。

除了下列环境,总将执行 finally 做为竣事:JVM 过早终止(挪用 System.exit(int));在 finally 块中抛出一个未处理惩罚的异常;计较机断电、失火、或遭遇病毒进攻。

声明异常

若要声明异常,则必需将其添加到要领签名块的竣事位置。下面是一个实例:

public void errorProneMethod(int input) throws java.io.IOException {
    //Code for the method,including one or more method
    //calls that may produce an IOException
}

这样,声明的异常将传给要领挪用者,并且也通知了编译器:该要领的任何挪用者必需遵守处理惩罚或声明法则。声明异常的法则如下:

必需声明要领可抛出的任何可检测异常(checked exception)。

非检测性异常(unchecked exception)不是必需的,可声明,也可不声明。

挪用要领必需遵循任何可检测异常的处理惩罚和声明法则。若包围一个要领,则不能声明与包围要领差异的异常。声明的任何异常必需是被包围要领所声明异常的同类或子类。

Java 异常处理惩罚的分类

Java 异常可分为可检测异常,非检测异常和自界说异常。

可检测异常

可检测异常经编译器验证,对付声明抛出异常的任何要领,编译器将强制执行处理惩罚或声明法则,譬喻:sqlExecption 这个异常就是一个检测异常。你毗连 JDBC 时,不捕获这个异常,编译器就通不外,不答允编译。

非检测异常

非检测异常不遵循处理惩罚或声明法则。在发生此类异常时,不必然非要采纳任何适当操纵,编译器不会查抄是否已办理了这样一个异常。譬喻:一个数组为 3 个长度,当你利用下标为3时,就会发生数组下标越界异常。这个异常 JVM 不会举办检测,要靠措施员来判定。有两个主要类界说非检测异常:RuntimeException 和 Error。

Error 子类属于非检测异常,因为无法预知它们的发生时间。若 Java 应用措施内存不敷,则随时大概呈现 OutOfMemoryError;起因一般不是应用措施的非凡挪用,而是 JVM 自身的问题。别的,Error 一般暗示应用措施无法办理的严重问题。

RuntimeException 类也属于非检测异常,因为普通 JVM 操纵激发的运行时异常随时大概产生,此类异常一般是由特定操纵激发。但这些操纵在 Java 应用措施中会频繁呈现。因此,它们不受编译器查抄与处理惩罚或声明法则的限制。

自界说异常

自界说异常是为了暗示应用措施的一些错误范例,为代码大概产生的一个或多个问题提供新寄义。可以显示代码多个位置之间的错误的相似性,也可以区分代码运行时大概呈现的相似问题的一个可能多个错误,或给出应用措施中一组错误的特定寄义。譬喻,对行罗列办操纵时,有大概呈现两种环境:空行列时试图删除一个元素;满行列时试图添加一个元素。则需要自界说两个异常来处理惩罚这两种环境。

Java 异常处理惩罚的原则和隐讳

Java 异常处理惩罚的原则

尽大概的处理惩罚异常

要尽大概的处理惩罚异常,假如条件确实不答允,无法在本身的代码中完成处理惩罚,就思量声明异常。假如工钱制止在代码中处理惩罚异常,仅出声明,则是一种错误和依赖的实践。

详细问题详细办理

异常的部门利益在于能为差异范例的问题提供差异的处理惩罚操纵。有效异常处理惩罚的要害是识别特定妨碍场景,并开拓办理此场景的特定相应行为。为了充实操作异常处理惩罚本领,需要为特定范例的问题构建特定的处理惩罚器块。

记录大概影响应用措施运行的异常

至少要采纳一些永久的方法,记录下大概影响应用措施操纵的异常。抱负环境下,虽然是在第一时间办理激发异常的根基问题。不外,无论回收哪种处理惩罚操纵,一般总应记录下潜在的要害问题。别看这个操纵很简朴,但它可以辅佐您用很少的时间来跟踪应用措施中巨大问题的起因。

按照景象将异常转化为业务上下文

#p#分页标题#e#

若要通知一个应用措施特有的问题,有须要将应用措施转换为差异形式。若用业务特定状态暗示异常,则代码更易维护。从某种意义上讲,无论何时将异常传到差异上下文(即另一技能层),都应将异常转换为对新上下文有意义的形式。

Java 异常处理惩罚的隐讳

一般不要忽略异常

在异常处理惩罚块中,一项最危险的流动是“不加告示”地处理惩罚异常。如下例所示:

1   try{
2       Class.forName("business.domain.Customer");
3   }
4   catch (ClassNotFoundException exc){}

常常可以或许在代码块中看到雷同的代码块。有人总喜欢在编写代码时简朴快速地编写空处理惩罚器块,并“自我慰藉地”宣称筹备在“后期”添加规复代码,但这个“后期”酿成了“无期”。

这种做法有什么弊端?假如异常对应用措施的其他部门确实没有任何负面影响,这未尝不行。但事实往往并非如此,异常会扰乱应用措施的状态。此时,这样的代码无异于掩耳盗铃。

这种做法若影响较轻,则应用措施大概呈现独特行为。譬喻,应用措施配置的一个值不见了, 或 GUI 失效。若问题严重,则应用措施大概会呈现重大问题,因为异常未记录原始妨碍点,难以处理惩罚,如反复的 NullPointerExceptions。

假如采纳法子,记录了捕捉的异常,则不行能碰着这个问题。实际上,除非确认异常对代码其余部门绝无影响,至少也要作记录。进一步讲,永远不要忽略问题;不然,风险很大,在后期会引举事以预料的效果。

不要利用包围式异常处理惩罚块

另一个危险的处理惩罚是包围式处理惩罚器(blanket handler)。该代码的根基布局如下:

1   try{
2     // …
3   }
4   catch(Exception e){
5     // …
6   }

利用包围式异常处理惩罚块有两个前提之一:

1. 代码中只有一类问题。

这大概正确,但即便如此,也不该利用包围式异常处理惩罚,捕捉更详细的异常形式有利物弊。

#p#副标题#e#

2. 单个规复操纵始终合用。

这险些绝对错误。险些没有哪个要领能放之四海而皆准,能应对呈现的任何问题。

阐明下这样编写代码将产生的环境。只要要领不绝抛出预期的异常集,则一切正常。可是,假如抛出了未预推测的异常,则无法看到要采纳的操纵。当包围式处理惩罚器对新异常类执行千篇一律的任务时,只能间接看到异常的处理惩罚功效。假如代码没有打印或记录语句,则基础看不到功效。

更糟糕的是,今世码产生变革时,包围式处理惩罚器将继承浸染于所有新异常范例,并以沟通方法处理惩罚所有范例。

一般不要把特定的异常转化为更通用的异常

将特定的异常转换为更通用异常时一种错误做法。一般而言,这将打消异常起初抛出时发生的上下文,在将异常传到系统的其他位置时,将更难处理惩罚。见下例:

1   try{
2     // Error-prone code
3   }
4   catch(IOException e){
5      String msg = "If you didn ’ t have a problem before,you do now!";
6      throw new Exception(msg);
7   }

因为没有原始异常的信息,所以处理惩罚器块无法确定问题的起因,也不知道如何矫正问题。

不要处理惩罚可以或许制止的异常

对付有些异常范例,实际上基础不必处理惩罚。凡是运行时异常属于此类领域。在处理惩罚空指针可能数据索引等问题时,不必求助于异常处理惩罚。

Java 异常处理惩罚的应用实例

在界说银行类时,若取钱数大于余额时需要做异常处理惩罚。

界说一个异常类 insufficientFundsException。取钱(withdrawal)要领中大概发生异常,条件是余额小于取额。

处理惩罚异常在挪用 withdrawal 的时候,因此 withdrawal 要领要声明抛出异常,由上一级要领挪用。

异常类:

class InsufficientFundsExceptionextends Exception{
   private Bank  excepbank;      // 银行工具
   private double excepAmount;   // 要取的钱
   InsufficientFundsException(Bank ba, double  dAmount)
    {  excepbank=ba;
       excepAmount=dAmount;
   }
   public String excepMessage(){
   	  String  str="The balance is"+excepbank.balance
       + "\n"+"The withdrawal was"+excepAmount;
   	  return str; 	
   }
}// 异常类

银行类:

class Bank{
   double balance;// 存款数
   Bank(double  balance){this.balance=balance;}
   public void deposite(double dAmount){
   	 if(dAmount>0.0) balance+=dAmount;
   }
   public void withdrawal(double dAmount)
               throws  InsufficientFundsException{
   	 if (balance<dAmount)     throw new
          InsufficientFundsException(this, dAmount);
      balance=balance-dAmount;
   }
   public void showBalance(){
      System.out.println("The balance is "+(int)balance);
   }
}

#p#分页标题#e#

前端挪用:

public class ExceptionDemo{
   public static void main(String args[]){
   	 try{
   	    Bank ba=new Bank(50);
          ba.withdrawal(100);
          System.out.println("Withdrawal successful!");
      }catch(InsufficientFundsException e) { 
          System.out.println(e.toString());
          System.out.println(e.excepMessage());
      }
   }
}

    关键字:

在线提交作业