Java 异常
Java教程 - Java异常
异常是在运行时在代码序列中出现的异常状况。例如,读取一个不存在的文件。
Java异常是描述异常条件的对象发生在一段代码中。
关键词
Java异常处理通过五个关键字管理: try,catch,throw,throws
和finally。
try
block包含要监视的程序语句异常。
如果在块中发生异常,则抛出异常。
catch
语句可以捕获异常并以合理的方式处理它。
要手动抛出异常,请使用关键字throw。
任何抛出的异常一个方法必须由一个 throws
子句指定。
任何代码绝对必须是在try块完成之后执行的命令被放在 finally
块中。
语法
要处理一个异常,我们把可能有的代码在try ... catch语句中的异常。
try { // block of code to monitor for errors } catch (ExceptionType1 exOb) { // exception handler for ExceptionType1 } catch (ExceptionType2 exOb) { // exception handler for ExceptionType2 }
可能有异常的程序语句包含在 try
块中。异常处理程序使用 catch
语句进行编码。
这里, ExceptionType
是发生的异常的类型。
例子
在try块和catch子句中封装要监视的代码。
下面的程序包括一个try块和一个catch子句处理由除法生成的ArithmeticException错误:
public class Main { public static void main(String args[]) { int d, a; try { // monitor a block of code. d = 0; a = 42 / d; System.out.println("This will not be printed."); } catch (ArithmeticException e) { // catch divide-by-zero error System.out.println("Division by zero."); } System.out.println("After catch statement."); } }
此程序生成以下输出:
例2
一旦抛出异常,程序控制就会从try块转移到catch块中。执行从未从catch返回到try块。
以下代码处理异常并继续。
import java.util.Random; public class Main { public static void main(String args[]) { int a = 0, b = 0, c = 0; Random r = new Random(); for (int i = 0; i < 32000; i++) { try { b = r.nextInt(); c = r.nextInt(); a = 12345 / (b / c); } catch (ArithmeticException e) { System.out.println("Division by zero."); a = 0; // set a to zero and continue } System.out.println("a: " + a); } } }
上面的代码生成以下结果。
Java 异常语句
Java教程 - Java异常语句
为了防止和处理运行时错误,请将代码包含在try块中进行监视。
紧跟在try块之后,包括一个catch子句它指定您希望捕获的异常类型。
Java try catch语句
public class Main { public static void main(String args[]) { try { // monitor a block of code. int d = 0; int a = 42 / d; System.out.println("This will not be printed."); } catch (ArithmeticException e) { // catch divide-by-zero error System.out.println("Division by zero."); } System.out.println("After catch statement."); } }
上面的代码生成以下结果。
多个catch子句
您可以指定两个或多个catch子句,每个捕获不同类型的异常。
当抛出异常时,将按顺序检查每个catch语句,并执行类型与异常类型匹配的第一个。
在执行一个catch语句之后,绕过其他catch语句,并在try/catch块之后继续执行。
public class Main { public static void main(String args[]) { try { int a = args.length; System.out.println("a = " + a); int b = 42 / a; int c[] = { 1 }; c[42] = 99; } catch (ArithmeticException e) { System.out.println("Divide by 0: " + e); } catch (ArrayIndexOutOfBoundsException e) { System.out.println("Array index oob: " + e); } System.out.println("After try/catch blocks."); } }
当您使用多个catch语句时,异常子类必须在它们的任何超类之前。
上面的代码生成以下结果。
嵌套try语句
try语句可以嵌套。
public class Main { public static void main(String args[]) { try { int a = args.length; int b = 42 / a; System.out.println("a = " + a); try { // nested try block if (a == 1) a = a / (a - a); // division by zero exception if (a == 2) { int c[] = { 1 }; c[4] = 9; // an out-of-bounds exception } } catch (ArrayIndexOutOfBoundsException e) { System.out.println("Array index out-of-bounds: " + e); } } catch (ArithmeticException e) { System.out.println("Divide by 0: " + e); } } }
上面的代码生成以下结果。
Java throw语句
我们可以在异常情况下抛出异常。
语法
throw的一般形式如下所示:
throw ThrowableInstance;
这里,ThrowableInstance必须是Throwable类型的对象或Throwable的子类。
有两种方法可以获取Throwable对象:在catch子句中使用参数,或者使用new运算符创建一个。
执行流程在throw语句之后立即停止; 任何后续不执行语句。
如何使用Java throws语句?
public class Main { static void aMethod() { try { throw new NullPointerException("demo"); } catch (NullPointerException e) { System.out.println("Caught inside demoproc."); throw e; // rethrow the exception } } public static void main(String args[]) { try { aMethod(); } catch (NullPointerException e) { System.out.println("Recaught: " + e); } } }
上面的代码生成以下结果。
Java throws语句
如果一个方法想抛出一个异常,它必须指定这个行为。
这是包含throws子句的方法声明的一般形式:
type method-name(parameter-list) throws exception-list { // body of method }
exception-list是一个逗号分隔的列表,列出了方法可以抛出的异常。
public class Main { static void throwOne() throws IllegalAccessException { System.out.println("Inside throwOne."); throw new IllegalAccessException("demo"); } public static void main(String args[]) { try { throwOne(); } catch (IllegalAccessException e) { System.out.println("Caught " + e); } } }
上面的代码生成以下结果。
Java finally语句
任何代码,将被执行,不管try块放在一个 finally
阻止。
这是异常处理块的一般形式:
try { // block of code to monitor for errors } catch (ExceptionType1 exOb) { // exception handler for ExceptionType1 } catch (ExceptionType2 exOb) { // exception handler for ExceptionType2 } // ... finally { // block of code to be executed after try block ends }
finally
创建一个代码块在 try
/catch
块完成后执行。
即使没有catch语句与异常匹配, finally
块也将执行。
finally
块可用于关闭文件句柄和释放任何其他资源。finally子句是可选的。
public class Main { // Through an exception out of the method. static void methodC() { try { System.out.println("inside methodC"); throw new RuntimeException("demo"); } finally { System.out.println("methodC finally"); } } // Return from within a try block. static void methodB() { try { System.out.println("inside methodB"); return; } finally { System.out.println("methodB finally"); } } // Execute a try block normally. static void methodA() { try { System.out.println("inside methodA"); } finally { System.out.println("methodA finally"); } } public static void main(String args[]) { try { methodC(); } catch (Exception e) { System.out.println("Exception caught"); } methodB(); methodA(); } }
上面的代码生成以下结果。
Java 异常类型
Java教程 - Java异常类型
下图显示了Java异常类型层次结构:
Throwable | | +---Exception. | | | | | +--- RuntimeException | +---Error
异常及其子类用于用户程序应捕获的异常条件。您可以子类化Exception以创建自己的自定义异常类型。
错误定义在正常情况下不期望捕获的异常。 Java运行时系统使用错误以指示运行时环境中的错误。 堆栈溢出是这种错误的一个例子。
未捕获异常
这个小程序包括一个有意造成除以零误差的表达式:
public class Main { public static void main(String args[]) { int d = 0; int a = 42 / d; } }
以下是执行此示例时生成的异常:
例子
这里是另一个版本的前面的程序,引入相同的错误,但在一个方法与main()分开:
public class Main { static void subroutine() { int d = 0; int a = 10 / d; } public static void main(String args[]) { subroutine(); } }
从默认异常处理程序生成的堆栈跟踪显示如何显示整个调用堆栈:
例2
您可以在println()语句中显示异常描述消息。
例如,catch块可以这样写:
import java.util.Random; public class Main { public static void main(String args[]) { int a = 0, b = 0, c = 0; Random r = new Random(); for (int i = 0; i < 32000; i++) { try { b = r.nextInt(); c = r.nextInt(); a = 12345 / (b / c); } catch (ArithmeticException e) { System.out.println("Exception: " + e); a = 0; // set a to zero and continue } System.out.println("a: " + a); } } }
上面的代码生成以下结果。
什么是Java的内置异常
子类化RuntimeException的异常不需要包含在任何方法的throws列表中。这些被称为未检查异常。
java.lang中定义的未检查异常在下表中列出。
异常 | 含义 |
---|---|
ArithmeticException | 算术错误,如除以零。 |
ArrayIndexOutOfBoundsException | 数组索引超出边界。 |
ArrayStoreException | 分配给不兼容类型的数组元素。 |
ClassCastException | 投射无效。 |
EnumConstantNotPresentException | 尝试使用未定义的枚举值。 |
IllegalArgumentException | 用于调用方法的非法参数。 |
IllegalMonitorStateException | 非法监视器操作,例如等待解锁的线程。 |
IllegalStateException | 环境或应用程序状态不正确。 |
IllegalThreadStateException | 请求的操作与当前线程状态不兼容。 |
IndexOutOfBoundsException | 一些类型的索引是超出界限的。 |
NegativeArraySizeException | 使用负尺寸创建的数组。 |
NullPointerException | 无效引用的使用无效。 |
NumberFormatException | 字符串到数字格式的转换无效。 |
SecurityException | 试图违反安全。 |
StringIndexOutOfBounds | 尝试在字符串的边界之外建立索引。 |
TypeNotPresentException | 未找到类型。 |
UnsupportedOperationException | 遇到不支持的操作。 |
检查的异常在下表中列出。
异常 | 含义 |
---|---|
ClassNotFoundException | 找不到类。 |
CloneNotSupportedException | 尝试克隆不实现Cloneable接口的对象。 |
IllegalAccessException | 对类的访问被拒绝。 |
InstantiationException | 尝试创建抽象类或接口的对象。 |
InterruptedException | 一个线程已被另一个线程中断。 |
NoSuchFieldException | 请求的字段不存在。 |
NoSuchMethodException | 请求的方法不存在。 |
Java自定义异常类
您可以通过定义 Exception
的子类来创建自己的异常类。
异常
类没有定义自己的任何方法。它继承由 Throwable
提供的方法。
以下程序创建自定义异常类型。
class MyException extends Exception { private int detail; MyException(int a) { detail = a; } public String toString() { return "MyException[" + detail + "]"; } } public class Main { static void compute(int a) throws MyException { System.out.println("Called compute(" + a + ")"); if (a > 10) throw new MyException(a); System.out.println("Normal exit"); } public static void main(String args[]) { try { compute(1); compute(20); } catch (MyException e) { System.out.println("Caught " + e); } } }
上面的代码生成以下结果。
Java链接异常
链接异常允许您将另一个异常与异常相关联。第二个异常描述了第一个异常的原因。
为了允许链接异常,两个构造函数和两个方法被添加到 Throwable
。
Throwable(Throwable causeExc) Throwable(String msg, Throwable causeExc)
这里是一个例子,说明处理链接异常的机制:
public class Main { static void demoproc() { NullPointerException e = new NullPointerException("top layer"); e.initCause(new ArithmeticException("cause")); throw e; } public static void main(String args[]) { try { demoproc(); } catch (NullPointerException e) { System.out.println("Caught: " + e); System.out.println("Original cause: " + e.getCause()); } } }
上面的代码生成以下结果。