前言
异常层次结构图:
一、概述
1.异常机制:程序在执行过程中发生了不正常的情况。
代码演示:
public class ExceptionText { public static void main(String[] args) { int a=100; int b=0; System.out.println(a/b); } }
运行结果:
没有正确输出,抛出了被 0 除异常
通过以上示例,我们看到 java 给我们提供了这样一个体系结构,当出现问题的时候,它会告诉我们,并且把错误的详细信息也告诉我们了,这就是异常的体系结构,这样我们的程序更健壮,我们可以把这个信息,再进行处理以下告诉用户。从上面大家还可以看到,java 异常都是类,在异常类中会携带一些信息给我们,我们可以通过这个类把信息取出来
2.java提供异常处理机制,将不正常情况输出在控制台,供程序员参考,修改代码,提高代码的健壮性!!!
3.例如常见的:ArrayIndexOutOfBoundsException异常、ClassCastException异常、NullPointerException异常
4.异常在java中以类和对象的形式存在每个类可以创建对象。
5.Throwable下有两个分支:Error(不可处理,直接退出JVM)和Exception(可处理的)
Exception下有两个分支:Exception的直接子类:编译时异常(要求程序员在编写程序阶段必须预先对这些异常进行处理,如果不处理编译器报错)。RuntimeException:运行时异常。(在编写程序阶段程序员可以预先处理,也可以不处理)
6.编译时异常(受控异常)和运行时异常(非受控异常),都是发生在运行阶段。
7.编译时异常和运行时异常的区别?
编译时异常一般发生的概率比较高。
举个例子:
你看到外面下雨了,倾盆大雨的。
你出门之前会预料到:如果不打伞,我可能会生病(生病是一种异常)。
而且这个异常发生的概率很高,所以我们出门之前要拿一把伞。
“拿一把伞”就是对“生病异常”发生之前的一种处理方式。
对于一些发生概率较高的异常,需要在运行之前对其进行预处理。
运行时异常一般发生的概率比较低。
举个例子:
小明走在大街上,可能会被天上的飞机轮子砸到。
被飞机轮子砸到也算一种异常。
但是这种异常发生概率较低。
在出门之前你没必要提前对这种发生概率较低的异常进行预处理。
如果你预处理这种异常,你将活的很累。
二、异常处理
Java中异常处理有两种方式:
在方法声明的位置上,使用throws关键字,抛给上一级。谁调用我,我就抛给谁。抛给上一级。
public class ExceptionText { public static void main(String[] args) throws Exception{ int a=100; int b=0; divide(a,b); } public static void divide(int a, int b) throws Exception{ int c = a / b; System.out.println(c); } }
使用try…catch语句进行异常的捕捉。
public class ExceptionText { public static void main(String[] args){ int a=100; int b=0; try { divide(a,b); } catch (Exception e) { e.printStackTrace(); } } public static void divide(int a, int b) throws Exception{ int c = a / b; System.out.println(c); }
注意:
1.Java中异常发生之后如果一直上抛,最终抛给了main方法,main方法继续向上抛,抛给了调用者JVM,JVM知道这个异常发生,只有一个结果。终止java程序的执行。
2.try语句中某一行出现异常该行后续代码不执行try…catch捕获后,后续代码可执行。
try…catch和finally概述
语法格式:
try { }catch(OneException e) { }catch(TwoException e) { }finally { }
try 中包含了可能产生异常的代码
try 后面是 catch,catch 可以有一个或多个,catch 中是需要捕获的异常
finally 表示:不管是出现异常,还是没有出现异常,finally 里的代码都执行,finally 和 catch
可以分开使用,但 finally 必须和 try 一块使用
try { }finally { }
catch(异常1 | 异常2 |异常3 |......)
jdk8新特性!!
示例代码(1):
public class ExceptionText { public static void main(String[] args){ int a=100; int b=0; try { divide(a,b); //上一行代码有异常,直接进入catch里面!! System.out.println("我能执行吗?"); } catch (Exception e) { System.out.println("被0除了!!"); } } public static void divide(int a, int b) throws Exception{ int c = a / b; System.out.println(c); } }
运行结果:
被0除了!!
示例代码(2):
public class ExceptionText { public static void main(String[] args){ int a=100; int b=0; try { divide(a,b); //上一行代码有异常,直接进入catch里面!! System.out.println("我能执行吗?"); } catch (Exception e) { System.out.println("被0除了!!"); }finally { System.out.println("finally执行了!!"); } } public static void divide(int a, int b) throws Exception{ int c = a / b; System.out.println(c); } }
运行结果:
被0除了!! finally执行了!!
throws与try…catch如何选择?
需要上报异常使用throws,需要捕获异常时使用try…catch进行捕获!!
finally重要面试题:
示例代码(3):
public class FinallyText { public static void main(String[] args) { System.out.println(n()); } public static int n(){ int i=100; try { return i; }finally { i++; } } }
运行结果:你们猜猜?有兴趣的铁子评论区讨论讨论一番哦!!!
final、finalize 和 finally区别详述。
final: 是一个关键字,表示最终的,不变的,可修饰属性、方法等!
finalize: 是Object类的一个方法,无需程序员调用,JVM垃圾回收器GC调用。
finally: 与try一起使用,异常处理机制中,finally语句块一定执行!!
三、异常中两个迷人的方法
取得异常描述信息:getMessage()
示例代码(4):
public class ExceptionText01 { public static void main(String[] args) { int a=100; int b=0; try { int c=a/b; System.out.println(c); }catch (ArithmeticException e){ //e 是一个引用,它指向了堆中的 ArithmeticException //通过 getMessage 可以得到异常的描述信息 System.out.println(e.getMessage()); } } }
运行结果:
/ by zero
找不同:找一找下面的结果和上面的结果有什么不同?
取得异常的堆栈信息(比较适合于程序调试阶段):printStackTrace();
示例代码(5):
public class ExceptionText01 { public static void main(String[] args) { int a=100; int b=0; try { int c=a/b; System.out.println(c); }catch (ArithmeticException e){ //e 是一个引用,它指向了堆中的 ArithmeticException //通过 printStackTrace 可以打印栈结构 e.printStackTrace(); } } }
运行结果:
比较比较两个方法在运行结束后,各有什么不同呢!!!
四、手动抛异常
话不多说,直接上代码!!!
示例代码(6):
public static void main(String[] args) { int ret = method1(1000, 10); if (ret == -1) { System.out.println("除数为 0"); } if (ret == -2) { System.out.println("被除数必须为 1~100 之间的数据"); } if (ret == 1) { System.out.println("正确"); } } private static int method1(int value1, int value2){ if (value2 == 0) { return -1; } if (!(value1 >0 && value1<=100)) { return -2; } int value3 = value1/value2; System.out.println("value3=" + value3); return 1; }
运行结果:
被除数必须为 1~100 之间的数据
将以上代码与以下代码作比较,找不同!!
示例代码(7):
public static void main(String[] args) { try { int ret = method1(1000, 10); System.out.println(ret); }catch(Exception iae) { //可以采用 Exception 拦截所有的异常 System.out.println(iae.getMessage()); } } private static int method1(int value1, int value2){ if (value2 == 0) { //手动抛出异常 throw new IllegalArgumentException("除数为 0"); } if (!(value1 >0 && value1<=100)) { //手动抛出异常 throw new IllegalArgumentException("被除数必须为 1~100 之间的数据"); } int value3 = value1/value2; return value3; }
运行结果:
被除数必须为 1~100 之间的数据
我们不难看出,使用throw抛出异常的形式来编写代码,代码会变得更加美观,更加高大上,更加无懈可击,换句话说,代码不会太Low!!!(小编建议大家以后可以多多使用)
throws 和 throw 的区别?
thorws 是声明异常,throw是抛出异常
五、神奇的自定义异常
第一步:编写一个类,继承Exception或RunTimeException.
第二步:提供两个构造方法。
示例代码(8):
public class MyException extends Exception{ public MyException() { } public MyException(String s) { super(s); } }
小试牛刀:
编写程序模拟用户注册:
1、程序开始执行时,提示用户输入“用户名”和“密码”信息。
2、输入信息之后,后台java程序模拟用户注册。
3、注册时用户名要求长度在[6-14]之间,小于或者大于都表示异常。
代码演示:
用户注册类:
/** *用户登录 * @username 用户名 * @password 密码 * 当用户名为null,用户名要求长度在[6-14]之间,小于或者大于都表示异常。 */ class UserService { public void register(String username, String password) throws MyException { if (null==username || username.length() <= 6 || username.length() >= 14) { throw new MyException("输入有误,请输入6~14之间的用户名"); } System.out.println("恭喜你注册成功!!"); } }
自定义异常类:
public class MyException extends Exception{ public MyException() { } public MyException(String s) { super(s); } }
测试类:
public class ExceptionText { public static void main(String[] args) { Scanner input = new Scanner(System.in); System.out.println("请输入用户名:"); String str = input.nextLine(); System.out.println("请输入密码:"); String passWord = input.next(); UserService userService = new UserService(); try { userService.register(str, passWord); } catch (MyException e) { // e.printStackTrace(); System.out.println(e.getMessage()); } } }
运行结果1:
请输入用户名: 小马 请输入密码: 123456 输入有误,请输入6~14之间的用户名
运行结果2:
请输入用户名: 鹅厂小马前来报到 请输入密码: 123456789 恭喜你注册成功!!