异常是程序中的不正常情况,有一些不正常情况是异常,可以在程序中处理;有一些不正常情况是错误,在程序中无能为力。
异常发生的原因有很多,通常有:用户输入了非法数据,要打开的文件不存在,物理内存溢出或损坏等等。
所有的异常都继承于Throwable类,异常主要分成两类,一种是错误,一种是异常。
错误指Error类,Error是指运行时环境发生的错误,一般发生在严重故障时,比如内存不足,Java程序处理不了。
我们常说的异常指的是Java程序本身能处理的Exception类。Exception异常又分成两类,一类是检查时异常,这类异常不处理就不能成功编译;另一类是运行时异常,这类异常可以通过编译,在运行时发生,如果在程序中适当处理,不影响程序继续运行,这类异常是我们进行异常处理的重点。
常见异常 | 描述 |
---|---|
ArithmeticException | 算术错误异常,例如,一个整数"除以零"时 |
ArrayIndexOutOfBoundsException | 访问数组下标越界异常 |
ClassCastException | 对象强制转换为不是实例的子类 |
IllegalArgumentException | 向方法传递了一个不合法或不正确的参数 |
NullPointerException | 空指针异常,访问的对象其值为null |
InputMisMatchException | 想得到的数据类型与实际输入的数据类型不匹配 |
NumberFormatException | 数字格式转换异常,如把“abc”转成数字 |
ClassNotFoundException | 应用程序试图加载类时,找不到相应的类 |
NoSuchFieldException | 请求的变量不存在 |
异常的捕捉
使用 try 和 catch 关键字可以捕获异常。把可能发生异常的代码块放在try里,catch有可能发生的异常。
语法格式:
try{
//可能发生异常的代码;
}catch(异常的类型){
//对捕获到的异常进行处理;
}
把可能发生异常的代码块放在try里执行,发生了异常就匹配catch块里的异常类型;如果匹配就执行catch块里的语句,不匹配则程序中止,异常处理没有完成。异常处理后,程序将继续往下运行。
多重catch
使用多个catch块对异常进行处理;前面的catch块是后面的子类,最后一个才可以是Exception,捕捉异常时尽量捕捉精确的异常。
多个catch块在执行时,是从前往后逐个匹配,只执行第一个匹配的catch块。
finally
finally 关键字用来创建在 try 代码块后面执行的代码块。无论是否发生异常,finally 代码块中的代码总会被执行。在 finally 代码块中,可以运行收尾善后性质的语句,比如关闭IO流的操作。
try{
//可能发生异常的代码;
}catch(异常的类型){
//对捕获到的异常进行处理;
}finally{
//不管异常有没有捕捉到,都会执行的语句;
}
finally里的语句无论如何都会执行,唯一例外的情况是前面出现了System.exit(1);
这个语句是退出程序。
如果在try块或者catch块里出现了return ;
,也是先执行finally语句,再return。
示例:
public class Demo {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
//可能发生异常的代码放在try块里
try{
System.out.println("请输入被除数");
int num1 = input.nextInt();
System.out.println("请输入除数");
int num2 = input.nextInt();
System.out.println(String.format("%d / %d = %d",num1,num2,num1/num2));
//使用catch捕捉异常,多重catch块的排序是从子类到父类
}catch(InputMismatchException e){
System.err.println("被除数和除数必须是整数。");
e.printStackTrace(); //输出异常堆栈信息,打印错误输出流
}catch(ArithmeticException e){
System.err.println("除数不能为0。");
System.out.println(e.getMessage());//打印发生的异常的详细信息
//System.exit(1);//finally语句唯一不执行的情况
}catch(Exception e){
System.err.println("其他未知异常");
}finally{
System.out.println("程序结束");
input.close();
}
}
}
throws和throw
throws 声明某个方法可能抛出的各种异常,可以声明多个异常,多个异常用逗号隔开。必须写在方法参数列表后面,不能单独使用。
throw 位于方法内部,可作为语句单独出现,抛出一个异常对象。
示例:
class Person{
private String name = "";
private int age = 0;
private String sex = "男";
void setSex(String sex) throws Exception{//声明方法可能抛出一个异常
if("男".equals(sex) || "女".equals(sex)){
this.sex = sex;
}else{ //抛出一个异常
throw new Exception("性别必须是\"男\"或者\"女\"");
}
}
void print(){
System.out.println(this.name+"("+this.sex+","+this.age+"岁)");
}
}
public class Demo {
public static void main(String[] args) {
Person person = new Person();
try {
person.setSex("Male");
person.print();
} catch (Exception e) {
e.printStackTrace();
}
}
}
自定义异常
自定义的异常针对性更强。
步骤:1,定义异常类,继承于Exception或者RuntimeException;2,编写构造方法;3,实例化自定义异常对象;4,throw抛出。
自定义异常的四种构造方法:
class MyException extends Exception{
public MyException(){
super();
}
public MyException(String message){
super(message);
}
public MyException(String message,Throwable cause){
super(message,cause);
}
public MyException(Throwable cause){
super(cause);
}
}
示例:
class GenderException extends Exception{//自定义异常
public GenderException(String message){//编写构造方法
super(message);
}
}
class Person{
private String name = "";
private int age = 0;
private String sex = "男";
void setSex(String sex) throws GenderException{
if("男".equals(sex) || "女".equals(sex)){
this.sex = sex;
}else{ //实例化异常对象并抛出
throw new GenderException("性别必须是\"男\"或者\"女\"");
}
}
}
异常使用的原则
- 异常只能用于非正常情况
- 不要把过于庞大的代码块放在try中
- 在catch中指定具体的异常类型
- 需要对捕获的异常进行处理,能处理就不要throw
异常处理可以帮助程序员迅速定位问题,输出日志,调试程序,增强了程序的健壮性,安全性和可维护性。
网友评论