1、概念
- 异常就是指在程序的运行过程中所发生的不正常的事件,它会中断正在运行的程序
- 为了让程序能够正常的运行,我们可以用判断的方法解决,但是这样堵漏洞的方式有很多的弊端,并且还会让代码变得很臃肿,不仅花费了很大的精力,并且漏洞也很难堵完。
- 为了能简单的解决异常,引入了异常处理机制,来处理程序中的异常。
- 在处理异常的过程中,涉及到的关键词有 try catch finally throw throws
2、try-catch 以及try-catch-finally
try-catch语法:
try{ //会出现异常的代码块 }catch(IOException e ){ //catch 捕获异常 //异常的处理方式 }catch(Exception e ){ //异常的处理方式 // 打印堆栈中的异常信息用的是:e.printStackTrace(); }
- 可以写多个catch块来捕获多种异常 ,使用多个catch块捕获异常需要注意 ,异常的顺序是从小到大 , 也就是先写子类 再写父类。
- 虽然可以直接用一个Exception 完成所有的异常捕获,但是不推荐这样的使用方式,因为这样的程序阅读性会很差。
- try-catch的三种出现情况:
//1,代码正常运行,不出现异常 try{ System.out.println(9 / 3); //输出结果为3 }catch(Exception e){ e.printStackTrace(); //程序正常,不执行 } System.out.println("程序结束。"); //执行print方法 //2、try中出现异常,被catch捕捉到,catch处理异常 try{ System.out.println(9 / 0); //出现异常(java.lang.ArithmeticException) System.out.println("路过"); // 因为出现了异常,因此不再执行try中的代码 }catch(ArithmeticException e){ //catch捕获到异常 ArithmeticException(算术异常 ) e.printStackTrace(); //处理异常,程序能继续执行 } System.out.println("程序结束。"); //异常被处理,,因此可以打印出来 //3、try中出现异常,但是catch捕捉的异常类型不匹配 try{ int[] is = new int[]{12,23,12,1} ; for(int i = 0 ; i <= is.length ; i++){ //数组下标越界异常: System.out.println(is[i]); //java.lang.ArrayIndexOutOfBoundsException } }catch(ArithmeticException e){ //catch只能捕获到异常 ArithmeticException(算术异常 ) e.printStackTrace();//因此,异常没有被捕捉到,也就不能处理,程序被终止,不能继续向下执行 } System.out.println("程序结束。"); //不会被打印出来
- 对异常处理的常用方法
- void printStackTrace() 输出异常的堆栈信息
- String getMessage() 返回异常信息描述字符串,是printStackTrace()输出信息的一部分
try-catch-finally语法
- try-catch-finally中,try必须存在,而catch以及finally不一定都存在,但是其至少必须有一个和try搭配。
//1、三者都在 try{ //会出现异常的代码块 }catch(IOException e ){ //catch 捕获异常 //异常的处理方式 }finally{ //代码块,就是无论如何,都会执行的代码 } //2、只有try-finally try { //代码块 }finally { //必须执行的代码 }
总的来说,finally里面的代码,不管try里面的异常是否被处理,他都会被执行,他只在一种情况之下是不会被执行的,那就是在try代码块里面,退出了JVM虚拟机 ,退出的方法就是调用exit方法,System.exit(0),或者Runtim.getRuntim().exit(0)。
当try-catch中出现return时的情况。首先,finally里面的代码肯定会执行,至于其顺序是先返回结果,还是先执行finally里面的内容,下面做一总结:
//1、return在try中,没有异常情况: public static void main(String[] args){ //主函数,为了调用下面的方法 System.out.println(test()); } public static int test() { int a = 90 ; try { a++; return a ; }catch(Exception e) { System.err.println(e.getMessage()); }finally { a++ ; System.out.println("finally执行了"); } return a ; } //执行结果为: //finally执行了 //在这里,如国把finally的a++放到try之中,那么就是 return ++a ; //91 //虽然finally里面的代码执行了,但是return的值是finally改变之前的值 //2、return在try中,出现异常的情况: public static void main(String[] args){ //主函数,为了调用下面的方法 System.out.println(test()); } public static int test() { int a = 90 ; try { a++; //执行了a++ ,此时a为91 System.out.println(9/0); //这里出现了异常,因此try之中剩下的代码不会执行 System.out.println("======"); //未执行 return a ; //未执行 }catch(ArithmeticException e) { //捕获到异常 System.err.println(e.getMessage()); //处理了异常 }finally { a++ ; //执行了a++,此时的a为92 System.out.println("finally执行了"); } return a ; //此时的a为92 } //执行结果为: // / by zero // finally执行了 // 92 //3、return在try、catch之中都有,出现异常的情况: public static void main(String[] args){ //主函数,为了调用下面的方法 System.out.println(test()); } public static int test() { int a = 90 ; try { a++; //执行了a++ ,此时a为91 System.out.println(9/0); //这里出现了异常,因此try之中剩下的代码不会执行 System.out.println("======"); //未执行 return a ; //未执行 }catch(ArithmeticException e) { //捕获到异常 System.err.println(e.getMessage()); //处理了异常 a = a + 5 ; //此时的a为96 return a ; //return的值为finally改变之前的,和第一种的情况一样 }finally { a++ ; //执行了a++,此时的a为97 System.out.println("finally执行了"); } } // / by zero // finally执行了 // 96
总结:
try-catch-finally中 如果try中已经return了值 那么finally中对返回值的操作不会改变返回值
try-catch-finally中 如果try中已经return了值 但是在return之前发生了异常 最终的finally将改变返回值
3、异常的结构体系
- 父类开始 -> 一级一级的向下
- Object 超类
- Throwable
- error 仅靠程序无法处理的错误
- Exception 异常 ,可以通过程序处理的异常
- Checked 异常: 检查异常,必须处理的异常 ,如果不处理,编译时会报错
- SQLException
- ClassNotFoundException
- 。。。等
- RuntimeException :运行时异常,可依不被处理,编译时不会报错
- NullPointerException
- ArrayIndexOutOfBoundsException
- 。。。等
4、异常的声明抛出以及自定义异常
异常的声明:throws
在参数列表之后,声明某个方法可能抛出的各种异常,多个异常用逗号隔开
声明之后,之后调用的时候,需要继续声明异常,或者直接在main方法中声明,然后交给JVM处理
异常的抛出:throw
异常的抛出是在方法体之中抛出的
一次只能抛出一个异常;
public static void ma() throws ClassNotFoundException{ //该方法声明了异常 throw new ClassNotFoundException("这是一个类未找到异常") ; //抛出一个异常 } public static void main(String[] args) throws ClassNotFoundException{ ma() ; //调用有异常方法的时候,需要处理异常,用try-catch 或者 继续声明 }
throw以及throws的区别
- Throw 抛出异常,在方法体之中,一次只能抛出一个异常
- throws 声明异常,在方法参数列表之后,可以声明多个异常,异常之间用 , 隔开
自定义异常:当JDK提供的异常无法满足需求的时候,我们可以通过继承Throwable、Exception、RuntimeException等这些父类来自定义异常,调用父类的构造方法来实现异常信息的打印
public class Student { private char sex ; public void setSex(char sex){ if(sex == '男' || sex =='女' ) { this.sex = sex; }else { throw new SexInputException("只能输入 男 或者 女") ; //抛出异常 } } //主函数 public static void main(String[] args) { Student student = new Student(); student.setSex('m'); } } //自定义的异常类 public class SexInputException extends RuntimeException{ public SexInputException(String massage) { super(massage) ; } }