异常(Exception)指的是:在程序的运行过程中,发生了不正常的现象,阻止了程序的运行。在没接触到Java关于异常处理的机制时,一般可能会尝试用 if-else
堵漏洞,但这样写会有诸多缺点:
- 代码臃肿,业务代码和处理异常的代码混在一起
- 可读性差
- 需要花费大量的经历来维护这个漏洞
- 很难堵住所有的漏洞
由于 if-else
处理异常缺点太多,所以Java专门出了一个异常处理机制:try-catch-finally
try-catch
public class Test {
public static void main(String[] args) {
try{
Scanner sc = new Scanner(System.in);
System.out.println("请录入第一个数:");
int num1 = sc.nextInt();
System.out.println("请录入第二个数:");
int num2 = sc.nextInt();
System.out.println("商:" + num1/num2);
}catch(Exception ex){
System.out.println("程序出现异常!");
}
System.out.println("感谢使用计算器");
}
}
程序执行结果为:
请录入第一个数:
3
请录入第二个数:
0
程序出现异常!
感谢使用计算器
把可能出现异常的代码放入 try
代码块中,然后将异常封装为对象,被 catch
后面的 ()
中的那个异常对象接收,接收以后执行 catch
后面的 {}
里面的代码,然后 try-catch
后面的代码该怎么执行就怎么执行。
注意事项如下:
-
try
中没有异常,catch
中代码不执行 -
try
中有异常,catch
进行捕获- 如果
catch
中异常类型和出现的异常类型匹配的话,对异常进行捕获,走catch
中的代码,try-catch
后面的代码该怎么执行还是怎么执行 - 如果
catch
中异常类型和出现的异常类型不匹配的话(比如Exception
换成ArithmeticException
),捕获失败,不走catch
中的代码,程序相当于遇到异常了,程序中断,后续代码不执行
- 如果
-
try
中如果出现异常,然后用catch
捕获成功的话,那么try
中后续的代码是不会执行的
catch中如何处理异常
catch
中处理异常的方式有多种:
-
什么都不写,什么都不做
public class Test { public static void main(String[] args) { try{ Scanner sc = new Scanner(System.in); System.out.println("请录入第一个数:"); int num1 = sc.nextInt(); System.out.println("请录入第二个数:"); int num2 = sc.nextInt(); System.out.println("商:"+num1/num2); }catch(Exception ex){ } System.out.println("感谢使用计算器"); } }
程序执行结果为:
请录入第一个数: 3 请录入第二个数: 0 感谢使用计算器
-
输出自定义异常信息
public class Test { public static void main(String[] args) { try{ Scanner sc = new Scanner(System.in); System.out.println("请录入第一个数:"); int num1 = sc.nextInt(); System.out.println("请录入第二个数:"); int num2 = sc.nextInt(); System.out.println("商:" + num1/num2); }catch(Exception ex){ System.out.println("程序出现异常!"); } System.out.println("感谢使用计算器"); } }
程序执行结果为:
请录入第一个数: 3 请录入第二个数: 0 程序出现异常! 感谢使用计算器
-
打印异常信息
-
调用
toString()
方法,显示异常的类名(全限定路径)public class Test { public static void main(String[] args) { try{ Scanner sc = new Scanner(System.in); System.out.println("请录入第一个数:"); int num1 = sc.nextInt(); System.out.println("请录入第二个数:"); int num2 = sc.nextInt(); System.out.println("商:"+num1/num2); }catch(Exception ex){ System.out.println(ex.toString()); } System.out.println("感谢使用计算器"); } }
程序执行结果为:
请录入第一个数: 3 请录入第二个数: 0 java.lang.ArithmeticException: / by zero 感谢使用计算器
-
显示异常描述信息对应的字符串,如果没有就显示
null
public class Test { public static void main(String[] args) { try{ Scanner sc = new Scanner(System.in); System.out.println("请录入第一个数:"); int num1 = sc.nextInt(); System.out.println("请录入第二个数:"); int num2 = sc.nextInt(); System.out.println("商:"+num1/num2); }catch(Exception ex){ System.out.println(ex.getMessage()); } System.out.println("感谢使用计算器"); } }
程序执行结果为:
请录入第一个数: 3 请录入第二个数: 0 / by zero 感谢使用计算器
-
显示异常的堆栈信息,将异常信息捕获以后,在控制台将异常的效果展示出来,方便查看异常,但是后面代码该执行还是执行
public class Test { public static void main(String[] args) { try{ Scanner sc = new Scanner(System.in); System.out.println("请录入第一个数:"); int num1 = sc.nextInt(); System.out.println("请录入第二个数:"); int num2 = sc.nextInt(); System.out.println("商:"+num1/num2); }catch(Exception ex){ ex.printStackTrace(); } System.out.println("感谢使用计算器"); } }
程序执行结果为:
请录入第一个数: 3 请录入第二个数: 0 java.lang.ArithmeticException: / by zero at com.test.Test.main(Test.java:13) 感谢使用计算器
-
抛出异常
public class Test { public static void main(String[] args) { try{ Scanner sc = new Scanner(System.in); System.out.println("请录入第一个数:"); int num1 = sc.nextInt(); System.out.println("请录入第二个数:"); int num2 = sc.nextInt(); System.out.println("商:"+num1/num2); }catch(Exception ex){ throw ex; } System.out.println("感谢使用计算器"); } }
程序执行结果为:
请录入第一个数: 3 请录入第二个数: 0 Exception in thread "main" java.lang.ArithmeticException: / by zero at com.test.Test.main(Test.java:13)
-
try-catch-finally
总结一下 try-catch
后面的代码不执行的情况:
throw
抛出异常catch
中没有正常的进行异常捕获- 在
try
中遇到return
(后面代码会报错)
为了使 try-catch
后面的代码无论如何都执行,引入了 finally
语句。
public class Test {
public static void main(String[] args) {
try{
Scanner sc = new Scanner(System.in);
System.out.println("请录入第一个数:");
int num1 = sc.nextInt();
System.out.println("请录入第二个数:");
int num2 = sc.nextInt();
System.out.println("商:"+num1/num2);
}catch(Exception ex){
throw ex;
}finally {
System.out.println("感谢使用计算器");
}
}
}
程序执行结果为:
请录入第一个数:
3
请录入第二个数:
0
感谢使用计算器
Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.test.Test.main(Test.java:13)
注意事项如下:
-
return
和finally
的执行顺序是先执行finally
最后执行return
-
一般来说,关闭数据库资源、关闭IO流资源、关闭socket资源这类代码会放到
finally
中 -
有一句代码可以让finally中语句不执行
System.exit(0); // 终止当前的虚拟机执行
多重catch
try
中出现异常以后,可以将异常类型跟 catch
后面的类型依次比较,执行第一个与异常类型匹配的 catch
语句。
public class Test {
public static void main(String[] args) {
try {
Scanner sc = new Scanner(System.in);
System.out.println("请录入第一个数:");
int num1 = sc.nextInt();
System.out.println("请录入第二个数:");
int num2 = sc.nextInt();
System.out.println("商:" + num1 / num2);
} catch(ArithmeticException ex){
System.out.println("对不起,除数不可以为0");
}catch(InputMismatchException ex){
System.out.println("对不起,你录入的数据不是int类型的数据");
}catch(Exception ex){
System.out.println("对不起,你的程序出现异常");
} finally {
System.out.println("感谢使用计算器");
}
}
}
注意事项如下:
-
一旦执行其中一条
catch
语句之后,后面的catch
语句就会被忽略 -
在安排
catch
语句的顺序的时候,一般会将特殊异常放在前面(并列),一般化的异常放在后面。即先写子类异常(如ArithmeticException),再写父类异常(如Exception) -
在JDK1.7以后,可以并列用
|
符号连接异常类型。例如Integer
类中的getInteger()
方法:public static Integer getInteger(String nm, Integer val) { String v = null; try { v = System.getProperty(nm); } catch (IllegalArgumentException | NullPointerException e) { } if (v != null) { try { return Integer.decode(v); } catch (NumberFormatException e) { } } return val; }