1、异常简介
Java 异常是程序中的某些错误,是Java 提供的一种面对程序运行错误时 提供的 应对机制。
在程序运行时抛出异常可以使程序不中断的运行下去,开发或维护人员能够了解异常的起因、异常的发生处以及抛出了什么异常。
异常结构:
error :出现error 基本上是硬件出错,说明程序崩了
exception:出现异常基本上是 编码、环境、用户操作或者输入问题
runtimeException 运行时异常:Java虚拟机会自动抛出,绝大部分都说明了代码本身有问题
checkException 检查异常:需要手动添加捕获及处理语句
-----
运行时异常和检查异常的区别:
运行时异常又叫非检查异常,一般情况下不需要程序员主动的捕获,但是一旦抛出了异常,就会一层层往上抛,如果最上层也没有相应的处理代码,此时程序就会中断。也因此,若想进程一直持续运行,那么对于所有可能会抛出异常的代码块,都要给他加上try catch 捕获并作出相应的异常处理机制。
检查异常是Java编译器强制要求必须要显示捕获的异常。
2、try catch finally 语句块
try:可能抛出异常的语句
catch: 异常处理的信息,可以打印异常日志、输出系统提示啥的;有可能一段代码会抛出多个异常,这时可以用多个catch块来捕获异常,catch块要遵循先子类后父类异常的原则
finally: 最终执行的,可用来关闭资源等
3、关于在finally前return
finally 是在try catch 语句块中的return “执行完之后,返回调用前” 执行的;
如果try catch finally 中都没有return ,那会调用在最后面的return
public static void main(String[] args){ //finally在前面的return “执行完之后,返回调用前执行”, 一定会执行! int test1 = testTryCatch(); System.out.println(test1); /** * 不捕获异常: * 我是finally语句块,最终执行的是我 1 * 捕获异常: * java.lang.ArrayIndexOutOfBoundsException: 2 at test.TestException.testTryCatch(TestException.java:65) at test.TestException.main(TestException.java:8) 我是catch块,我捕获异常了 我是finally语句块,最终执行的是我 0 */ } public static int testTryCatch(){ int[] nums = new int[2]; nums[0] = 1; try{ //System.out.println(nums[2]); return nums[0]; }catch(Exception e){ e.printStackTrace(); System.out.println("我是catch块,我捕获异常了"); //在catch块中return,后面还有finally的情况下,先把return的值执行了或者说先行保留, //等finally执行完在返回给这个方法的调用 return nums[0] = 0; }finally { System.out.println("我是finally语句块,最终执行的是我"); } }
4、异常抛出
throws:声明将要抛出何种类型的异常,在类或方法中声明,返回给上层调用者处理异常;throws exception1,exception2
throw:将产生异常的动作抛出,表示这个动作,相当于try catch; throw new exception("产生异常了");
public static void main(String[] args){ //这里属于起始调用者,就直接自己处理异常即可, //如果不是起始调用者或者处理不了异常代码,就继续throw异常,并在方法名上声明要抛出 try { testThrowException(); } catch (Exception e) { e.printStackTrace(); } /** * java.lang.Exception at test.TestException.testThrowException(TestException.java:78) at test.TestException.main(TestException.java:12) */ } //在方法内部会抛出异常的时候,在方法头要声明这个方法会抛出异常,有多个异常的话就用逗号隔开 //在调用这个方法的时候,要么自己try catch处理这个异常,要么在调用这个方法的方法声明处声明会抛出异常,丢给起始调用者处理异常 public static void testThrowException() throws Exception{ if(true){ throw new Exception(); } }
注意抛出和捕获的区别:
抛出就是我发现这个异常,谁调用我,就把这个异常丢给谁来处理
捕获就是,我发现这个异常,我自己来处理
通常情况下,如果要调用可能会抛出异常的方法或代码块,就用try catch来被捕获处理这段调用代码,此时,一旦调用方法抛出异常,就会被trycatch捕获并且处理,这样主程序就不会中断了。
5、自定义异常
一般情况下,直接继承Exception的会是检查性异常
直接继承RuntimeException 的当然是运行时异常
如果只是在已有异常的基础上修改某些逻辑,则可以直接继承该异常
6、异常链
把捕获的异常包装成新的异常,在新的异常里面添加对原始异常的引用,在把新异常抛出,类似链式反应,一个导致另外一个,这种就叫异常链。
(所以一般在程序抛出异常时,最下面的那个cause by 往往是直接原因)
public static void main(String[] args){ //因为把自定义异常包装成了RuntimeException,所以这里就不需要自己显示捕获异常了 testChainException(); /** * 可见这里执行之后先抛出运行时异常,下面的Caused by 才是原本自定义的异常 * 也因为这个原因,在Java代码编写中,一般抛出异常,最下面的才是最主要的原因 * * Exception in thread "main" java.lang.RuntimeException: 把自定义异常包装成运行时异常! at test.TestException.testChainException(TestException.java:88) at test.TestException.main(TestException.java:33) Caused by: test.TestSelfException: 自定义异常:就是异常了! at test.TestException.testSelfException(TestException.java:77) at test.TestException.testChainException(TestException.java:86) ... 1 more */ } /** * 自定义异常 * @throws TestSelfException */ public static void testSelfException() throws TestSelfException{ if(true){ throw new TestSelfException("自定义异常:就是异常了!"); } } /** * 异常链 */ public static void testChainException(){ try { testSelfException(); } catch (TestSelfException e) { RuntimeException rte = new RuntimeException("把自定义异常包装成运行时异常!"); rte.initCause(e); throw rte; } }
7、应用总结
最好是在打印异常的同时加上业务回滚之类的,具体的看具体业务