使用 try-catch 和 throw 语句。使用 catch、 multi-catch 和 finally 子句。用 try-with-resources 语句使用自动关闭资源。创建自定义异常和自动关闭资源。
Exception
三种类型
- java.lang.Exception排除RuntimeEcxeption
可抛出并表示预期的错误。在某些情况下,程序可以从中恢复。一些例子是: IOException,ParseException,SQLException - java.lang.RuntimeException
并表示在运行时生成的意外错误。在大多数情况下,程序无法从中恢复。一些例子是: arithmeteexception、 ClassCastException、 NullPointerException - java.lang.Error
程序不应该处理的严重问题或异常情况。一些例子是: AssertionError,IOError,LinkageError,VirtualMachineError
Try-Catch
如果没有处理异常,JVM 将提供一个默认的异常处理程序来执行以下任务:
1.它打印出异常描述。
2.它打印堆栈跟踪(发生异常的方法层次结构)。
3.它导致程序终止。
- 如果异常可以在多个块中捕获,则在定义的第一个块中捕获异常。
- 子类之前定义了一个超类,就会产生一个编译时错误
try {
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd");
Date date = sdf.parse("01-10");
System.out.println(date);
} catch (Exception e) {
System.err.println("Exception caught");
} catch (ParseException e) {
System.err.println("ParseException caught");
}
- 一个 catch 块被定义为一个不能被 try 块中的代码抛出的异常,那么也会产生一个错误。但是可以再方法上直接throws任何不会在方法体内抛出的Exception
try {
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd");
Date date = sdf.parse("01-10");
System.out.println(date);
} catch (SQLException e) { // Compile-time error
System.err.println("ParseException caught");
}
这两个错误的原因是两个捕获块的代码将永远不会被执行(正如编译器所说的那样,它是不可达的)。
如果抛出已检查异常的代码不在 try-catch 块中,则包含该代码的方法必须在 throws 子句中声明该异常
- 方法的调用者必须要么捕获异常,要么在 throws 子句中声明它,以此类推,直到到达程序的主方法
public class Test {
public static void main(String[] args)
throws ParseException {
m1();
}
private static void m1() throws ParseException {
m2();
}
private static void m2() throws ParseException {
m3();
}
private static void m3() throws ParseException {
m4();
}
private static void m4() throws ParseException {
SimpleDateFormat sdf =
new SimpleDateFormat("MM/dd");
Date date = sdf.parse("01-10");
System.out.println(date);
}
}
多重捕获Multi-Catch
try {
// Code that may throw one or
// two exceptions
} catch(Exception1 | Exception2 e) {
// Do something with the caught
// exception using reference e
}
要么选择Exception1,要么选择Exception2
Finally
try {
// Code that may throw an
// exception }
finally {
// Block that is always executed
}
- Catch 块是可选的。可以同时拥有 catch 块或 finally
- Finally 块始终执行,不管是在 try 块中抛出异常、在 catch 块中重新抛出异常,还是根本没有捕获异常
Multi-Catch and Finally
int res = 0;
try {
int[] arr = new int[2];
res = (arr[1] != 0) ? 10 / arr[1] : 10 * arr[2];
} catch (ArithmeticException e) {
e.printStackTrace();
return res;
} catch (IndexOutOfBoundsException e) {
e.printStackTrace();
return res;
}
return res;
多 catch 块允许我们用一个 catch 块捕获两个或多个异常
try {
...
} catch (ArithmeticException | IndexOutOfBoundsException e) {
e.printStackTrace();
return res;
}
- catch 子句的末尾只有一个变量用于声明的所有异常。如果你想区分异常,你可以使用 instanceof 操作符
try {
...
} catch (ArithmeticException | IndexOutOfBoundsException e) {
if(e instanceof ArithmeticException) {
// Do something else if the exception type
// is ArithmeticException
}
e.printStackTrace();
return res;
}
- multi-catch中变量被视为 final,这意味着您不能重新分配,只有在多重捕获时才是
- 不能将子类及其超类组合在同一个 multi-catch 块中
try {
...
} catch (ArithmeticException | RuntimeException e) {
// The above line generates a compile-time error
// because ArithmeticException is a subclass of
// RuntimeException
e.printStackTrace();
return res;
}
类似于在子类之前的 catch 块中声明超类的情况。代码是冗余的,超类总是捕获异常。
try {
...
} catch (ArithmeticException | IndexOutOfBoundsException e) {
e.printStackTrace();
} finally {
return res;
}
Finally 块总是执行,即使捕获了异常,或者 try 或 catch 块包含一个 return 语句。因此,它通常用于关闭数据库连接或文件处理程序等资源。
只有一个例外。如果调用 System.exit () ,程序将异常终止而不执行 finally 块。但是,由于调用 System.exit ()被认为是不好的做法,这种情况很少发生
Try-With-Resources
try (AutoCloseableResource r = new AutoCloseableResource()) {
// Code that may thrown an exception
} catch(Exception e) {
// Handle exception
} finally {
// Always executes
}
在 try 块完成后关闭资源
try-with-resources
自 Java 7以来,有了 try-with-resources 块,在这个块中,try 块声明一个或多个资源,这样它们就可以被关闭,而无需在 finally 块中显式地执行
及在try()括号内生命资源
try (BufferedReader br =
new BufferedReader(new FileReader("/file.txt"))) {
int value = 0;
while((value = br.read()) != -1) {
System.out.println((char)value);
}
} catch (IOException e) {
e.printStackTrace();
}
当 try 块执行完成后,BufferedReader 被关闭,这等价于
BufferedReader br = null;
try {
int value = 0;
br = new BufferedReader(new FileReader("/file.txt"));
while((value = br.read()) != -1) {
System.out.println((char)value);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (br != null) br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
- 如果声明多个资源,则必须用分号分隔
try (FileReader fr = new FileReader("/file.txt");
BufferedReader br = new BufferedReader(fr)) {
...
}
- try-with-resources 中声明的资源不能在这个块之外使用(第一个原因,它们超出了范围,第二个原因,它们在 try 块结束后关闭)
try (BufferedReader br =
new BufferedReader(new FileReader("/file.txt"))) {
...
}
String line = br.readLine(); // Compile-time error
- 不要认为任何类在使用资源的尝试中会起作用
在 try-with-resources 块中使用的类必须实现以下接口之一:
java.lang.AutoCloseable
java.io.Closable
class MyResource {
void useResource() { }
}
...
try (MyResource r = new MyResource()) { // Compile-time error
r.useResource()
}
void close() throws Exception;
public void close() throws IOException;
它们都声明 close ()方法,这两个接口之间唯一的实际区别是
- Closeable 接口的 close 方法只引发 IOException 类型的异常
- AutoCloseable 接口的 close ()方法抛出 Exception 类型的异常时(换句话说,它可以抛出几乎任何类型的异常)
close ()方法是自动调用的,如果这个方法实际上抛出和异常,我们可以在 catch 块中捕获它
- 如果try块也抛出异常,结果是 try 块的异常抛出、close ()方法的异常被压制
只会捕获Catch{}中的异常
自定义异常Excetion
可以扩展语言的任何异常来创建我们自己的异常
将 Exception 添加到类名称中是一种约定。Error 和 Throwable 类实际上并不用于自定义异常。
总结
- 在Java中,有三种类型的异常
1.java.lang.Exception异常
2.java.lang.RuntimeException异常
3.java.lang.Error错误 - 不需要捕获RuntimeException及其子类,因为它们不是一直都需要的。它们也被称为未检查异常。
- Exception及其子类(RuntimeException除外)称为检查性异常,因为编译器必须检查它们是否在某个时刻被try-catch语句捕获。
- 如果可以在多个块中捕获异常,则将在定义的第一个块中捕获该异常。
- 类的层次结构,如果在子类之前定义了一个超类,则会生成编译时错误。
- 如果抛出选中异常的代码不在try catch块中,则包含该代码的方法必须在throws子句中声明异常。
- 方法的调用方必须捕获异常,或者在throws子句中声明异常,依此类推,直到到达程序的主方法为止。
- 多重检查异常块允许我们用一个catch块捕获两个或多个不相关的异常:
- 始终执行finally块,即使捕获到异常或try或catch块包含return语句。
- 在try with resources块中,声明了一个或多个资源,以便仅通过实现java.lang.AutoCloseable或java.io.Closeable即可在try块结束后自动关闭这些资源:
Comments | 0 条评论