Java异常处理实例教程

jerry Java 2016年03月10日 收藏

1、什么是异常?
首先,让我们来看看下图的例子:
在这个例子中,存在的错误码由除以0的结果。由于除以0而导致异常: ArithmeticException
HelloException.java

  1. package com.yiibai.tutorial.exception;
  2.  
  3. public class HelloException {
  4.  
  5. public static void main(String[] args) {
  6.  
  7. System.out.println("Three");
  8.  
  9. // This division no problem.
  10. int value = 10 / 2;
  11.  
  12. System.out.println("Two");
  13.  
  14. // This division no problem.
  15. value = 10 / 1;
  16.  
  17. System.out.println("One");
  18. // This division has problem, divided by 0.
  19. // An error has occurred here.
  20. value = 10 / 0;
  21.  
  22. // And the following code will not be executed.
  23. System.out.println("Let's go!");
  24.  
  25. }
  26.  
  27. }
  28.  

运行这个例子,得到的结果是:

可以看到控制台屏幕上的通知。错误通知是很清楚的,包括代码行的信息。
让我们通过下图中的流程看看下面的程序:

  • 程序从(1),(2)至(5)步骤正常运行。
  • 在步骤(6)程序除以0。
  • 程序跳转出 main 方法后,而(7)代码行还没有被执行。

我们将修改上述实施例的代码。

HelloCatchException.java

  1. package com.yiibai.tutorial.exception;
  2.  
  3. public class HelloCatchException {
  4.  
  5. public static void main(String[] args) {
  6.  
  7. System.out.println("Three");
  8.  
  9. // This division no problem.
  10. int value = 10 / 2;
  11.  
  12. System.out.println("Two");
  13.  
  14. // This division no problem.
  15. value = 10 / 1;
  16.  
  17. System.out.println("One");
  18.  
  19. try {
  20. // This division has problem, divided by 0.
  21. // An error has occurred here.
  22. value = 10 / 0;
  23.  
  24. // And the following code will not be executed.
  25. System.out.println("Value =" + value);
  26.  
  27. } catch (ArithmeticException e) {
  28.  
  29. // The code in the catch block will be executed
  30. System.out.println("Error: " + e.getMessage());
  31.  
  32. // The code in the catch block will be executed
  33. System.out.println("Ignore...");
  34.  
  35. }
  36.  
  37. // This code is executed
  38. System.out.println("Let's go!");
  39.  
  40. }
  41.  
  42. }
  43.  

运行示例结果:

Three

Two

One

Error: / by zero

Ignore...

Let's go!

我们将按以下实例图像的流程来解释下面的程序。

  • 步骤(1)至(5)是完全正常的。
  • 异常发生在步骤(6),除以0出现了问题。
  • 它立即跳到catch块执行命令,步骤(7)被跳过。
  • 步骤(8),(9)被执行。
  • 步骤(10)被执行。

2、 异常层次结构
这是Java异常的分层图的模型。

最高的类是:Throwable

两个直接子类是 Error 和 Exception。

在异常转移有一个RuntimeException子类,包括Java中的编译时未检查异常。检查并取消检查在编译时,在下一部分的实施示例中说明。

注意:您的类应该从两个分支:Error或Exception继承,而不是直接从Throwable继承。

当一个动态链接失败,或在虚拟机的一些其他的“硬”故障发生时,虚拟机引发这个错误。典型的Java程序不捕获错误,所以Java程序都不会抛出任何错误。大多数程序抛出并捕获从Exception类派生的对象。异常指示出现了一个问题,但是这些问题并不是严重系统性问题。你写的大多数程序将会抛出和捕获异常。

Exception类在Java包定义了许多子类。这些子类指明不同类型的可能会发生异常。 例如,NegativeArraySizeException表明程序试图创建一个大小为负的数组。

一个导演的子类在Java语言中的特殊含义: RuntimeException类表示Java虚拟机中发生(在运行期间)的异常。运行时异常的一个例子是NullYiibaierException异常,其中,当一种方法试图通过一个空引用来访问对象的成员时就会引发。 NullYiibaierException 可以在任何地方出现某个程序试图取消引用一个对象的引用。经常检查异常捕获的好处远远超过它的成本。

由于运行时异常是无所不在的,在试图捕获或指定所有的时间是徒劳的作法(不可读和不可维护的代码), 编译器允许运行时异常去未捕获和指定。
Java包定义几个RuntimeException类。您可以捕获这些异常,就像其他异常。但是并不需要一种方法来指定它抛出运行时异常。此外可以创建自己的RuntimeException子类。 运行时异常 - 下面讨论包含何时以及如何使用运行时异常进行了深入探讨。 3、使用try-catch处理异常

编写从Exception 继承的类。

AgeException.java

  1. package com.yiibai.tutorial.exception.basic;
  2.  
  3. public class AgeException extends Exception {
  4.  
  5. public AgeException(String message) {
  6. super(message);
  7. }
  8.  
  9. }
  10. TooYoungException.java
  11. package com.yiibai.tutorial.exception.basic;
  12.  
  13. public class TooYoungException extends AgeException {
  14.  
  15. public TooYoungException(String message) {
  16. super(message);
  17. }
  18.  
  19. }
  20.  

TooOldException.java

  1. package com.yiibai.tutorial.exception.basic;
  2.  
  3. public class TooOldException extends AgeException {
  4.  
  5. public TooOldException(String message) {
  6. super(message);
  7. }
  8.  
  9. }
  10.  

以及AgeUtils类检查年龄的检查静态方法。
AgeUtils.java

  1. package com.yiibai.tutorial.exception.basic;
  2.  
  3. public class AgeUtils {
  4.  
  5. // This method checks the age.
  6. // If age is less than 18, the method will throw an exception TooYoungException
  7. // If age greater than 40, the method will throw an exception TooOldException
  8. public static void checkAge(int age) throws TooYoungException,
  9. TooOldException {
  10. if (age < 18) {
  11.  
  12. // If age is less than 18, an exception will be thrown
  13. // This method ends here.
  14. throw new TooYoungException("Age " + age + " too young");
  15. } else if (age > 40) {
  16.  
  17. // If age greater than 40, an exception will be thrown.
  18. // This method ends here.
  19. throw new TooOldException("Age " + age + " too old");
  20. }
  21.  
  22. // If age is between 18-40.
  23. // This code will be execute.
  24. System.out.println("Age " + age + " OK!");
  25. }
  26. }
  27.  

检查异常和未经检查的异常:
AgeException是Exception,TooOldException的子类和TooYoungException2是 AgeException直接子类,所以它们是“Checked Exception”
在AgeUtils.checkAge(int)方法已经抛出异常,需要通过关键字“throws”,列出它们的方法声明。或者可以声明抛出更多的级别。
在使用 AgeUtils.checkAge(int) 位置也必须进行处理,以捕获异常,或继续抛出去。

"Checked exception" 是由 "Java Compiler"来检查。

有两个选择:

TryCatchDemo1.java

  1. package com.yiibai.tutorial.exception.basic;
  2.  
  3. public class TryCatchDemo1 {
  4.  
  5. public static void main(String[] args) {
  6.  
  7.  
  8. System.out.println("Start Recruiting ...");
  9. // Check age
  10. System.out.println("Check your Age");
  11. int age = 50;
  12.  
  13. try {
  14.  
  15. AgeUtils.checkAge(age);
  16.  
  17. System.out.println("You pass!");
  18.  
  19. } catch (TooYoungException e) {
  20.  
  21. // Do something here ..
  22. System.out.println("You are too young, not pass!");
  23. System.out.println(e.getMessage());
  24.  
  25. } catch (TooOldException e) {
  26.  
  27. // Do something here ..
  28. System.out.println("You are too old, not pass!");
  29. System.out.println(e.getMessage());
  30.  
  31. }
  32.  
  33. }
  34. }
  35.  

在下面的例子中,我们将通过父类捕获异常(超Exception类)。
TryCatchDemo2.java

  1. package com.yiibai.tutorial.exception.basic;
  2.  
  3. public class TryCatchDemo2 {
  4.  
  5. public static void main(String[] args) {
  6.  
  7. System.out.println("Start Recruiting ...");
  8. // Check age
  9. System.out.println("Check your Age");
  10. int age = 15;
  11.  
  12. try {
  13.  
  14. // Here can throw TooOldException or TooYoungException
  15. AgeUtils.checkAge(age);
  16.  
  17. System.out.println("You pass!");
  18.  
  19. } catch (AgeException e) {
  20. // If an exception occurs, type of AgeException
  21. // This catch block will be execute
  22. System.out.println("Your age invalid, you not pass");
  23. System.out.println(e.getMessage());
  24.  
  25. }
  26. }
  27. }
  28.  

也可以组不同的异常在块中来处理,如果它们对逻辑程序处理是相同的方式。
TryCatchDemo3.java

  1. package com.yiibai.tutorial.exception.basic;
  2.  
  3. public class TryCatchDemo3 {
  4.  
  5. public static void main(String[] args) {
  6.  
  7. System.out.println("Start Recruiting ...");
  8. // Check age
  9. System.out.println("Check your Age");
  10. int age = 15;
  11.  
  12. try {
  13.  
  14. // Here can throw TooOldException or TooYoungException
  15. AgeUtils.checkAge(age);
  16.  
  17. System.out.println("You pass!");
  18.  
  19. } catch (TooYoungException | TooOldException e) {
  20. // Catch multi exceptions in one block.
  21.  
  22. System.out.println("Your age invalid, you not pass");
  23. System.out.println(e.getMessage());
  24.  
  25. }
  26. }
  27.  
  28. }
  29.  

4、 try-catch-finally
我们已习惯于通过 try-catch 块捕获错误。Try-catch-finally 来完全处理异常。

  1. try {
  2.  
  3. // Do something here
  4.  
  5. } catch (Exception1 e) {
  6.  
  7. // Do something here
  8.  
  9. } catch (Exception2 e) {
  10.  
  11. // Do something here
  12.  
  13. } finally {
  14.  
  15. // Finally block is always executed
  16. // Do something here
  17.  
  18. }
  19.  

TryCatchFinallyDemo.java

  1. package com.yiibai.tutorial.exception.basic;
  2.  
  3. public class TryCatchFinallyDemo {
  4.  
  5. public static void main(String[] args) {
  6.  
  7. String text = "001234A2";
  8.  
  9. int value = toInteger(text);
  10.  
  11. System.out.println("Value= " + value);
  12.  
  13. }
  14.  
  15. public static int toInteger(String text) {
  16. try {
  17.  
  18. System.out.println("Begin parse text: " + text);
  19.  
  20. // An Exception can throw here (NumberFormatException).
  21. int value = Integer.parseInt(text);
  22.  
  23. return value;
  24.  
  25. } catch (NumberFormatException e) {
  26.  
  27. // In the case of 'text' is not a number.
  28. // This catch block will be executed.
  29. System.out.println("Number format exception " + e.getMessage());
  30.  
  31. // Returns 0 if NumberFormatException occurs
  32. return 0;
  33.  
  34. } finally {
  35.  
  36. System.out.println("End parse text: " + text);
  37.  
  38. }
  39. }
  40.  
  41. }
  42.  

这是程序的流程。 finally块无论什么情况下总会被执行。

5、 环绕异常

  • 我们需要一些类参与到这个例子:
  • Person: 模拟一个受试者招募到公司的信息:姓名,年龄,性别。
  • GenderException: 性别异常。
  • ValidateException: 异常评估求职者。
  • ValidateUtils: 静态方法类综合评价面试者。
  • 如果男性年龄在18-40之间的被认为是有效的。

Person.java

  1. package com.yiibai.tutorial.exception.wrap;
  2.  
  3. public class Person {
  4.  
  5. public static final String MALE = "male";
  6. public static final String FEMALE = "female";
  7.  
  8. private String name;
  9. private String gender;
  10. private int age;
  11.  
  12. public Person(String name, String gender, int age) {
  13. this.name = name;
  14. this.gender = gender;
  15. this.age = age;
  16. }
  17.  
  18. public String getName() {
  19. return name;
  20. }
  21.  
  22. public void setName(String name) {
  23. this.name = name;
  24. }
  25.  
  26. public String getGender() {
  27. return gender;
  28. }
  29.  
  30. public void setGender(String gender) {
  31. this.gender = gender;
  32. }
  33.  
  34. public int getAge() {
  35. return age;
  36. }
  37.  
  38. public void setAge(int age) {
  39. this.age = age;
  40. }
  41. }
  42.  

GenderException.java

  1. package com.yiibai.tutorial.exception.wrap;
  2.  
  3. // Gender Exception.
  4. public class GenderException extends Exception {
  5.  
  6. public GenderException(String message) {
  7. super(message);
  8. }
  9. }
  10.  

ValidateException 类包有其他异常。
ValidateException.java

  1. package com.yiibai.tutorial.exception.wrap;
  2.  
  3. public class ValidateException extends Exception {
  4. // Wrap an Exception
  5. public ValidateException(Exception e) {
  6. super(e);
  7. }
  8.  
  9. }
  10.  

ValidateUtils.java

  1. package com.yiibai.tutorial.exception.wrap;
  2.  
  3. import com.yiibai.tutorial.exception.basic.AgeUtils;
  4.  
  5. public class ValidateUtils {
  6.  
  7. public static void checkPerson(Person person) throws ValidateException {
  8. try {
  9.  
  10. // Check age.
  11. // Valid if between 18-40
  12. // This method can throw TooOldException, TooYoungException.
  13. AgeUtils.checkAge(person.getAge());
  14.  
  15. } catch (Exception e) {
  16. // If not valid
  17. // Wrap this exception by ValidateException, and throw
  18. throw new ValidateException(e);
  19.  
  20. }
  21.  
  22. // If that person is Female, ie invalid.
  23. if (person.getGender().equals(Person.FEMALE)) {
  24.  
  25. GenderException e = new GenderException("Do not accept women");
  26. throw new ValidateException(e);
  27.  
  28. }
  29. }
  30.  
  31. }
  32.  

WrapperExceptionDemo.java

  1. package com.yiibai.tutorial.exception.wrap;
  2.  
  3. public class WrapperExceptionDemo {
  4.  
  5. public static void main(String[] args) {
  6. // One participant recruitment.
  7. Person person = new Person("Marry", Person.FEMALE, 20);
  8.  
  9. try {
  10.  
  11. // Exceptions may occur here.
  12. ValidateUtils.checkPerson(person);
  13.  
  14. } catch (ValidateException wrap) {
  15.  
  16. // Get the real cause.
  17. // May be TooYoungException, TooOldException, GenderException
  18. Exception cause = (Exception) wrap.getCause();
  19.  
  20. if (cause != null) {
  21. System.out.println("Not pass, cause: " + cause.getMessage());
  22. } else {
  23. System.out.println(wrap.getMessage());
  24. }
  25.  
  26. }
  27. }
  28.  
  29. }
  30.  

6、RuntimeException和子类 RuntimeException类及其子类都是“未检查的例外”。它不是由Java编译器在编译时进行检查。在某些情况下,你可以从这个分支继承编写自己的异常。

下面是属于RuntimeException分支一些类(当然,这还不是全部)。
一些处理这种类型异常的例子:

6.1- NullYiibaierException
这是最常见的异常,通常会导致错误在程序中。异常被抛出,当你调用方法或访问一个空对象的字段。
NullYiibaierExceptionDemo.java

  1. package com.yiibai.tutorial.exception.runtime;
  2.  
  3. public class NullYiibaierExceptionDemo {
  4.  
  5. // For example, here is a method that can return null string.
  6. public static String getString() {
  7. if (1 == 2) {
  8. return "1==2 !!";
  9. }
  10. return null;
  11. }
  12.  
  13. public static void main(String[] args) {
  14.  
  15. // This is an object that references not null.
  16. String text1 = "Hello exception";
  17.  
  18. // Call the method retrieves the string length.
  19. int length = text1.length();
  20.  
  21. System.out.println("Length text1 = " + length);
  22.  
  23. // This is an object that references null.
  24. String text2 = getString();
  25. // Call the method retrieves the string length.
  26. // NullYiibaierException will occur here.
  27. // It is an exception occurs at runtime (type of RuntimeException)
  28. // Javac compiler does not force you to use a try-catch block to handle it
  29. length = text2.length();
  30.  
  31. System.out.println("Finish!");
  32. }
  33.  
  34. }
  35.  

运行示例的结果:

在现实中,像处理其他异常时,可以使用 try-catch 来捕获并处理这个异常。 然而,这是机械的,通常情况下,我们应该检查,以确保在使用它之前,对象不为空值。
您可以更正上面的代码,使其类似于下面的以避免空指针异常:

  1. // This is a null object.
  2. String text2 = getString();
  3.  
  4. // Check to make sure 'Text2' are not null.
  5. // Instead of using try-catch.
  6. if (text2 != null) {
  7. length = text2.length();
  8. }
  9.  

6.2- ArrayIndexOfBoundException
当您试图访问一个无效的索引的数组元素就会发生此异常。例如,一个数组有10个元素可以访问,但您访问的是索引为20的元素。
ArrayIndexOfBoundsExceptionDemo.java

  1. package com.yiibai.tutorial.exception.runtime;
  2.  
  3. public class ArrayIndexOfBoundsExceptionDemo {
  4.  
  5. public static void main(String[] args) {
  6.  
  7. String[] strs = new String[] { "One", "Two", "Three" };
  8.  
  9. // Access to the element has index 0.
  10. String str1 = strs[0];
  11.  
  12. System.out.println("String at 0 = " + str1);
  13.  
  14. // Access to the element has index 5.
  15. // ArrayIndexOfBoundsException occur here.
  16. String str2 = strs[5];
  17.  
  18. System.out.println("String at 5 = " + str2);
  19.  
  20. }
  21.  
  22. }
  23.  

为了避免 ArrayIndexOfBoundsException,我们更多的应该是检查数组而不是使用try-catch。

  1. if (strs.length > 5) {
  2. String str2 = strs[5];
  3. System.out.println("String at 5 = " + str2);
  4. } else {
  5. System.out.println("No elements with index 5");
  6. }

以上就是本文的全部内容,希望对大家的学习有所帮助。