异常处理和文本I/O
Java 可以让一个方法可以抛出一个异常 ,该异常可以被调用者捕获和处理 。
try-throw-catch
import java.util.Scanner;
public class QuotientWithException {
public static int quotient(int number1, int number2){
if(number2 == 0)
throw new ArithmeticException("Divisor cannot be zero");
return number1 / number2;
}
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("Enter two integers:");
int number1 = input.nextInt();
int number2 = input.nextInt();
try {
int result = quotient(number1, number2);
System.out.println(number1 + " / " + number2 + " = " + result);
}
catch (ArithmeticException ex){
System.out.println("Exception: an integer " +
"cannot be divided by zero ");
}
System.out.println("Execution continues...");
}
}
Enter two integers:
5 0
Exception: an integer cannot be divided by zero
Execution continues...
Enter two integers:
3 2
3 / 2 = 1
Execution continues...
语句
throw new ArithmeticException("Divisor cannot be zero");
- 通过异常类
java.lang.ArithemeticException
创建一个异常类对象,从而抛出异常 - 当异常抛出后,正常的执行流程被中断
- 抛出异常就是将异常从一个地方传递到另一个地方
try 块
包含了正常情况下执行的代码- 异常被
catch 块
所捕获 。catch块
中的代码执行以处理异常 - throw 语句类似于方法的调用 , 但不同于调用方法的是
- 它调用的是 catch 块
- 在执行完 catch 块之后 , 程序控制不返回到 throw 语句;而是执行 catch 块后的下一
条语句
异常处理最根本的优势就是将检测错误(由被调用的方法完成)从处理错误(由调用方法完成)中分离出来 。
很多库方法都会抛出异常
import java.util.InputMismatchException;
import java.util.Scanner;
public class InputMismatchExceptionDemo {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
boolean continueInput = true;
do {
try {
System.out.println("Enter an integer:");
int number = input.nextInt();
System.out.println("The number entered is " + number);
continueInput = false;
}
catch (InputMismatchException ex){
System.out.println("Try again.");
input.nextLine(); // 丢弃当前输入行
}
}while (continueInput);
}
}
Enter an integer:
3.00
Try again.
Enter an integer:
0
The number entered is 0
异常类型
异常是对象 , 而对象都采用类来定义 。 异常的根类是
java.lang.Throwable
Throwable类
是所有异常类的根 。 所有的 Java 异常类都直接或者间接地继承自Throwable 。 可以通过继承 Exception 或者 Exception 的子类来**创建自己的异常类 **
RuntimeException
、 Error
以及它们的子类都称为免检异常 ( unchecked exception )
。 所有其他异常都称为必检异常 ( checked exception )
, 意思是指编译器会强制程序员检査并通过 try - catch
块处理它们 , 或者在方法头进行声明
关于异常处理的更多知识
Java异常处理的三种操作:
- 声明一个异常
- 抛出一个异常
- 捕获一个异常
声明异常
方法要拋出的其他异常都必须在方法头中显式声明 , 这样 , 方法的调用者会被告知有异常
public void myMethod() throws IOException
关键字 throws
表明 myMethod 方法
可能会抛出异常IOException
。如果方法可能会抛出多个异常, 就可以在关键字 throws 后添加一个用逗号分隔的异常列表
public void myMethod()
throws Exception1, Exception2, ..., ExceptionN
如果方法没有在父类中声明异常 , 那么就不能在子类中对其进行继承来声明异常
抛出异常
检测到错误的程序可以创建一个合适的异常类型的实例并抛出它 , 这就称为抛出一个异常。假如程序发现传递给方法的参数与方法的合约不符 ( 例如 , 方法中的参数必须是非负的 , 但是传入的是一个负参数 ) , 这个程序就可以创建 IllegalArgumentException
的一个实例并抛出它
IllegalArgumentException ex =
new IllegalArgumentException("Wrong Argument");
throw ex;
或者表示为:
throw new IllegalArgumentException("Wrong Argument");
捕获异常
当抛出一个异常时 , 可以在try - catch
块中捕获和处理它
try{
statements;
}
catch(Exception1 exVar1){
handler for exception1;
}
catch(Exception2 exVar2){
handler for exception2;
}
...
catch(ExceptionN exvarN){
handler for exceptionN;
}
如果在执行 try 块的过程中没有出现异常 , 则跳过 catch 子句
如果 try 块中的某条语句抛出一个异常 , Java 就会跳过 try 块中剩余的语句 , 然后开始査找处理这个异常的代码的过程
注意
- 从一个通用的父类可以派生出各种异常类 。 如果一个 catch 块可以捕获一个父类的异常对象,它就能捕获那个父类的所有子类的异常对象 。
- 在 catch 块中异常被指定的顺序是非常重要的。 如果父类的 catch 块出现在子类的catch 块之前 , 就会导致编译错误
- Java 强迫程序员处理必检异常
- 对于使用同样的处理代码处理多个异常的情况 , 可以使用新的 JDK 7 的
多捕获特征( multi - catch feature )
简化异常的代码编写
catch(Exception1|Exception2|...|ExceptionN ex){ // 如果其中一个异常被捕获,则执行处理的代码
// Same code for handling these exceptions;
}
从异常中获取信息
可以利用下面这些java.lang.Throwable
类中的实例方法获取有关异常的信息
实例
finally子句
无论异常是否产生 , finally 子句总是会被执行的
try{
statements;
}
catch(TheException ex){
handling ex;
}
finally{
finalStatements;
}
何时使用异常
当错误需要被方法的调用者处理的时候 , 方法应该抛出一个异常 。
try 块包含正常情况下执行的代码 。 catch 块包含异常情况下执行的代码 。 异常处理将错误处理代码从正常的程序设计任务中分离出来 , 这样 , 可以使程序更易读 、 更易修改
不要用 try - catch 块处理简单的 、 可预料的情况
重新抛出异常
如果异常处理器不能处理一个异常 , 或者只是简单地希望它的调用者注意到该异常 , Java 允许该异常处理器重新抛出异常 。
链式异常
catch 块重新抛出原始的异常 。 有时候,可能需要同原始异常一起抛出一个新异常(带有附加信息), 这称为链式异常
main
方法调用 method1()
( 第 4 行 ), method1
调用 method2
( 第 13 行 ) , method2
拋出一
个异常 ( 第 21 行 ) 。 该异常被 method1
的 catch 块所捕获 , 并在第 16 行被包装成一个新异
常 。 该新异常被抛出 , 并在 main 方法
中的 catch 块
中被捕获 ( 第 6 行 ) 。 示例输出在第 7 行中 printStackTrace()
方法的结果 。 首先 , 显示从 method1
中抛出的新异常 , 然后显示从
method 2
中抛出的原始异常
创建自定义异常类
可以通过派生
java.lang.Exception
类来定义一个自定义异常类
要创建一个InvalidRachusExMption
类 , 必须传递一个半径 。
Write by Gqq