【Java异常 14】
一、异常
1、异常结构图
二、ERROR
堆栈异常:StackOverflowError
一般发生在方法递归调用(递归调用一般都有一个结束条件,否则就会发生无限递归调用,不停的发生压栈,导致堆栈溢出)
内存溢出:申请了太多内存,而没有释放导致溢出
三、Exception异常
异常的本质?:
1、异常模拟的是现实世界中的不正常的一类事件
2、异常在Java中采用类和对象的形式存在
例如:
java.lang.NullPointerException;一类空指针事件
java.lang.NullPointerException e=0x12; 真是发生在某个空指针异常事件(JVM会创建异常对象)
3、异常在Java中的作用,可以提高程序的健壮性。
======第一个异常:运算异常========
“Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.JavaStudy.studyYiChang0527.ExceptionTest01.main(ExceptionTest01.java:11)”
1、异常对象中肯定携带详细的异常信息
2、该程序由JVM将异常信息打印到工作台
3、异常信息很详细,程序员可以通过抛出的异常,修改自己的程序,达到程序的健壮性
package com.JavaStudy.studyYiChang0527; /** java.lang.ArithmeticException(运算异常),此异常是运行时异常而非编译异常,如果是编译异常的话编译器就无法通过 出现异常的运算条件时,才会抛出运算异常 ArithmeticException是runtimeException的子类 */ public class ExceptionTest01 { public static void main(String[] args){ // int a = 5; // int b = 0; // System.out.println(a/b); //运行结果:Exception in thread "main" java.lang.ArithmeticException: / by zero // int a = 5; int b = 0; if(b==0){ System.out.println("b不能为0"); return; } System.out.println(a/b); //执行结果:b不能为0 } }
四、异常的详细分类
异常主要分为:错误ERROR,受控异常(编译异常),非受控异常(运行异常)。
错误(ERROR):如果应用程序出现ERROR,那么将无法恢复,只能重新启动应用程序,最典型的错误:OutOfMemaryError
受控异常(编译异常):出现这种异常必须显示的处理,不显示处理Java程序将无法通过
非受控异常(运行异常):此种异常可以不用显示处理。
编译时异常发生的几率较高。
要求程序在编译阶段就进行处理
如果不处理程序将无法通过。
五、异常的第一种处理方式:throws
throws(抛出):在方法声明位置上使用throws关键字,如果想让调用程序知道该异常发生了,被调用的程序应该使用throws关键字进行上抛
只要JVM知道了该异常发生了,则一定会打印异常信息,并且结束程序的运行。
========找不到文件异常========
package com.JavaStudy.studyYiChang0527; import java.io.FileInputStream; import java.io.FileNotFoundException; /** * @Author wufq * @Date 2020/5/27 11:14 */ public class ExceptionTest02 { public static void main(String[] args) throws FileNotFoundException { //创建一个文字节流 FileInputStream file = new FileInputStream("/Users/wufq/Desktop/11.txt"); /* 因为11.txt文件不存在,在用到FileInputStream类的构造方法时就会抛出"找不到文件"异常,所以JVM在处理的时候就需要抛出此异常到控制台 */ } }
执行结果:
Exception in thread "main" java.io.FileNotFoundException: /Users/wufq/Desktop/11.jpj (No such file or directory)
at java.io.FileInputStream.open0(Native Method)
2、深入throws(逐层上抛)
package com.JavaStudy.studyYiChang0527; import java.io.FileInputStream; import java.io.FileNotFoundException; public class ExceptionTest02 { public static void main(String[] args) throws FileNotFoundException { ExceptionTest02 t = new ExceptionTest02(); t.m3(); } public void m3() throws FileNotFoundException { m2(); } public void m2() throws FileNotFoundException { m1(); } public void m1() throws FileNotFoundException { FileInputStream file = new FileInputStream("/Users/wufq/Desktop/11.jpj"); } }
六、处理异常的第二种方式
捕捉:try...catch...如果不想让调用程序知道该异常发生,被调用的程序应该使用try...catch...进行捕捉异常
语法格式:
try{
可能出现异常的语句
Java语句1;//如果该语句出现异常,则try语句块停止执行,直接进入catch语句块执行。
Java语句2;
}catch(异常类型1 变量名){
处理异常的Java语句
}catch(异常类型2 变量名){
处理异常的Java语句
}
1、catch语句是可以编写多个的
2、catch语句只执行一次,整个try...catch...就结束了
3、catch可以捕捉多个异常,但是必须从上到下,从小到大捕捉
package com.JavaStudy.studyYiChang0527; /** * @Author wufq * @Date 2020/5/27 17:23 */ public class ExceptionTest03 { public static void main(String[] args){ int a = 5; int b = 0; try{ //try里面是出现异常的代码,不出现异常的代码最好不用放到try里面 int c =a/b; //当0被除异常,程序流会执行到catch(ArithmeticException e)语句,被0除的表达式永远不会被执行 System.out.println(c); //e是一个引用,数据类型为ArithmeticException(继承运行异常) }catch(ArithmeticException e){ System.err.println(e.getMessage()); //getMessage()是ArithmeticException类的方法,用于返回详细的字符串 } System.out.println(a); } }
package com.JavaStudy.studyYiChang0527; /** * @Author wufq * @Date 2020/5/28 09:42 */ public class ExceptionTest04 { public static void main(String[] args){ int a = 10; int b = 0; try{ int c = a/b; System.out.println(c); }catch(ArithmeticException e){ e.printStackTrace(); } System.out.println(a); } }java.lang.ArithmeticException: / by zero at com.JavaStudy.studyYiChang0527.ExceptionTest04.main(ExceptionTest04.java:13) =====执行结果====
java.lang.ArithmeticException: / by zero
at com.JavaStudy.studyYiChang0527.ExceptionTest04.main(ExceptionTest04.java:13)
七、自定义异常
1、自定义非受控异常(即:编译异常)
package com.JavaStudy.studyYiChang0527; public class ExceptionTest05 { public static void main(String[] args){ try{ m(10,0); }catch (Mexception e){ e.printStackTrace(); }catch (Exception e){ e.printStackTrace(); } } //自定义子类的异常 /* throws是方法声明处的关键字,抛出的是异常类型 方法体异常的抛出用的是throw,抛出的是异常对象 */ public static void m (int value1,int value2) throws Mexception{ if(value2 == 0){ throw new Mexception("除数为0"); } int value3 = value1/value2; System.out.println(value3); } } //自定义非受控异常 class Mexception extends RuntimeException{ //缺省构造器 Mexception(){ super(); //super()子类调用父类的构造方法并给父类赋值 } Mexception(String message){ super(message); } }
2、自定义受控异常(即:编译异常)
package com.JavaStudy.studyYiChang0527; /** * @Author wufq * @Date 2020/5/28 14:54 */ public class ExceptionTest06 { public static void main(String[] args){ //受控异常(编译异常)和非受控异常(运行异常)的区别就在于:编译异常不加异常的抛出或者捕捉时,是编译不成功的, // 但是运行异常就算是不加异常抛出或者捕捉也是可以编译成功的 try { mothod(10,0); } catch (MyException e) { e.printStackTrace(); }catch (Exception e){ e.printStackTrace(); } } public static void mothod(int value1,int value2) throws Exception { if(value2 == 0 ){ throw new Exception("除数为0"); } int value3 = value1/value2; System.out.println(value3); } } //自定义受控异常(编译异常) class MyException extends Exception{ MyException(){ super(); } MyException(String message){ super(message); } }
举例:结合业务场景自定义异常
package com.JavaStudy.studyYiChang0527; /** * @Author wufq * @Date 2020/5/28 17:28 * 判断一个name长度是否满足6位来进行异常的抛出 */ public class ExceptionTest07 { public static void main(String[] args){ String name = "复仇者联盟4";//执行结果:注册成功 // String name = "复仇者联盟";//执行结果:IllegalNameException: 长度不足6位,注册失败! UserService user = new UserService(); try { user.register(name); System.out.println("注册成功,欢迎"+name+"登录"); } catch (IllegalNameException e) { e.printStackTrace(); } } } class UserService{ public void register(String name) throws IllegalNameException { if(name.length()<6){ //方法体内的异常抛出用throw,并且抛出的是对象 throw new IllegalNameException("长度不足6位,注册失败!"); } } } //自定义一个名字无效异常,编译异常 class IllegalNameException extends Exception{ IllegalNameException(){ super(); } IllegalNameException(String message){ super(message); } }
八、finally语句
异常处理机制中的finally语句块
在finally语句块中的程序是一定会执行的
package com.JavaStudy.studyYiChang0527; /** * @Author wufq * @Date 2020/5/29 14:36 */ public class ExceptionTest08 { public static void main(String[] args){ int a=10; int b = 0; try{ int c = a/b; }catch (Exception e){ e.printStackTrace(); }finally { System.out.println("------finally语句--------"); } //异常被处理了,可以执行到此语句 System.out.println("test"); } } ====执行结果==== java.lang.ArithmeticException: / by zero ------finally语句-------- test at com.JavaStudy.studyYiChang0527.ExceptionTest08.main(ExceptionTest08.java:13)
通常会在finally语句里面写一些关闭流的语句 或者释放资源的语句
1)try和finally可以连用,如果有异常并不会处理异常,但是finally里面的语句一定会被执行
package com.JavaStudy.studyYiChang0527; /** * @Author wufq * @Date 2020/5/29 14:50 */ public class ExceptionTest09 { public static void main(String[] args){ int a=10; int b = 0; try { int c = a / b; }finally { System.out.println("finally....."); } //不会执行到此语句,因为异常没有被处理 System.out.println("test"); } } ====执行结果==== finally..... Exception in thread "main" java.lang.ArithmeticException: / by zero at com.JavaStudy.studyYiChang0527.ExceptionTest09.main(ExceptionTest09.java:13)
2)遇到return后方法停止执行后,finally仍然会执行
package com.JavaStudy.studyYiChang0527; /** * @Author wufq * @Date 2020/5/29 14:59 */ public class ExceptionTest10 { public static void main(String[] args){ try{ return; }finally { System.out.println("finally....."); } } } ====执行结果===== finally..... Process finished with exit code 0
3)退出JVM虚拟机,finally就不会被执行了
package com.JavaStudy.studyYiChang0527; /** * @Author wufq * @Date 2020/5/29 15:04 */ public class ExceptionTest11 { public static void main(String[] args){ try{ System.exit(0);//退出jvm虚拟机 }finally { System.out.println("finally....."); } } } ====执行结果==== Process finished with exit code 0
4)多个异常的处理方式
try调出的快捷方式:option+commond+t
package com.JavaStudy.studyYiChang0527; import java.io.FileInputStream; import java.io.IOException; /** * @Author wufq * @Date 2020/5/29 15:14 */ public class ExceptionTest12 { public static void main(String[] args){ //FileInputStream流被称为文件字节输入流,意思指对文件数据以字节的形式进行读取操作 FileInputStream file = null; try { file = new FileInputStream("/Users/wufq/Desktop/abcd"); //文件找不到异常 int a =file.read();//输入输出流异常 System.out.println(a);//97--->ACSII中a==97 } catch (IOException e) { e.printStackTrace(); } } }