异常-Java学习日记
异常:就是程序不正常的情况
ava中程序的异常:Throwable
Error:严重的问题,这样的情况,我们一般不做处理,因为这样的问题一般不是程序本身带来问题,而是外界导致。
Exception:
编译时期异常:除了RuntimeException以外的异常都是编译时期异常,这样的异常必须做处理,
如果不处理程序无法运行,编译无法通过
运行时期异常:RuntimeException 这样的 问题我们可以不做处理,因为这是你自己的问题,通常情况下,出现这样的问题一般都是
因为代码的逻辑不够严谨导致的。
出现问题后,如果我们没有做任何处理,JVM会提供一个默认的处理方式,可以看到出现了什么异常,出现异常的信息,以及出现问题的代码行
public class ExceptionDemo1 { public static void main(String[] args) { //运行时期异常 int[] arr = {11,22,33,44,55}; System.out.println(arr[1]); System.out.println(arr[5]); System.out.println("hello"); } } /* 运行结果 22 Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5 at com.shujia.lc.day22.ketang.ExceptionDemo1.main(ExceptionDemo1.java:27) */
异常处理方案
1、try…catch…finally
2、throws
try…catch…finally处理格式:
try{
可能会出现问题的代码;
}catch(异常的类名 变量名){
针对出现的问题做处理;
}finally{
一般情况下,这里写释放资源;
}
变形格式:
try{
可能会出现问题的代码;
}catch(异常的类名 变量名){
针对出现的问题做处理;
}
注意:
1、try里面的代码如果出现问题,try里面的代码就会停在那一行,然后JVM会自动识别是什么问题,去catch匹配对应的异常,匹配到后
执行对应的处理方式(catch大括号中的代码),如果没有匹配到,JVM会执行默认的处理方式,而默认的处理方式会将程序停止,后面的代码都不会执行
2、try里面的代码越少越好,确定不会出错的代码就不要try里面写了。
3、catch里面必须要有内容,哪怕就写了一个简单输出语句提示
public class ExceptionDemo2 { public static void main(String[] args) { int a = 10; int b = 0; try { System.out.println(a / b); } catch (ArithmeticException ae) { System.out.println("你的除数为0了"); } System.out.println("world"); System.out.println("hello"); } } /* 运行结果 你的除数为0了 world hello */
处理一个异常和处理多个异常
处理多个异常的方案:
1、对每一个异常都写一个try...catch...
2、写一个try,多个catch
try{
...
}catch(){
...
}catch(){
...
}
注意事项:
1、多个异常使用try..catch处理的时候,catch可以写一个,里面写最大的父类Exception,但是如果这么写了,try里面
无论出现什么错误,都会匹配到这里的catch,这样的做的话,所有的问题处理方式都是一种处理,没法区分,不推荐这么做
2、多个catch之间可以是继承关系,但是,要把父类的catch写在最后,因为出现问题匹配catch的顺序是自上而下的。
3、JDK1.7之后出现了处理异常的新方案:
try{
放上可能会出现问题的代码;
}catch(异常类名1|异常类名2|异常类名3|... 变量名){
处理问题的代码;
}
注意:
1)新特性处理的方式并不太好,因为多种异常的处理方式统一是一种
2)新特性的处理catch中的异常只能是平级关系,不能是继承关系
public class ExceptionDemo3 { public static void main(String[] args) { //编译时期异常 String s = "2022-04-06 14:35:00"; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // try { // Date date = sdf.parse(s); // System.out.println(date); // }catch (ParseException pe){ // System.out.println("日期转换出错了!!!"); // } // // int[] arr = {11,22,33,44,55}; // try { // System.out.println(arr[5]); // }catch (ArrayIndexOutOfBoundsException aiob){ // System.out.println("取了不该取的索引"); // } System.out.println("==============================================="); //第二种处理方式:写一个try,多个catch // try { // Date date = sdf.parse(s); // int[] arr = {11, 22, 33, 44, 55}; // System.out.println(arr[5]); // }catch (ParseException ae){ // System.out.println("日期处理格式"); // }catch (Exception ae){ // System.out.println("取了不该取的索引"); // } System.out.println("==============================================="); //JDK1.7try..catch处理新方式 try { Date date = sdf.parse(s); int[] arr = {11, 22, 33, 44, 55}; System.out.println(arr[5]); }catch (ParseException|ArrayIndexOutOfBoundsException e){ System.out.println("出错啦!!"); } System.out.println("你好!!!"); } }
在前面案例中,我们处理异常的方式都是输出一句话,告诉我们出了什么问题,但是呢,对比发现,并没有默认处理方式来的直接和清楚
try..catch..的处理过程是,当try中的代码出现了问题的时候,JVM会帮助我们生成一个异常对象,然后把这个对象跑出来,与catch中的
类型进行匹配,如果匹配到了,就走对应的处理方式。
异常中需要了解的几个方法:
1、getMessage()
获取异常信息,返回字符串。
2、toString()
获取异常类名和异常信息,返回字符串。
3、printStackTrace()
获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void
public class ExceptionDemo4 { public static void main(String[] args) { String s = "2020-04-06"; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // try { // Date date = sdf.parse(s); // System.out.println(date); // }catch (ParseException pe){ // ParseException pe = new ParseException(); //// System.out.println("日期转换异常"); //// String message = pe.getMessage(); //// System.out.println(message); // //// String s1 = pe.toString(); //// //此对象的类的name(全路径名) //// //": "(冒号和一个空格) //// //调用此对象中的getLocalizedMessage()方法,底层调用的还是getMessage()方法。 //// System.out.println(s1); // // pe.printStackTrace(); // } try { Date date = sdf.parse(s); } catch (ParseException e) { e.printStackTrace(); } System.out.println("你好!!"); } }
有些时候,我们可以对异常去做处理,但是呢,有些时候,我们根本就没有权限去处理这些异常。
或者说, 我们处理不了,就不处理了,交给更高权限的去处理。
为了解决这样出错的问题,Java针对这种情况,就提供了另一种处理方案:抛出
格式:
throws 异常类名
注意:这个格式必须跟在方法的小括号后面,大括号前面。
注意:
1、尽量不要在main方法上面抛出,因为main方法是由JVM调用的,如果出问题了,依旧是走默认的处理方式,
而默认的处理方式,会将程序终止,后续代码不会执行,推荐能try..catch就try..catch
(为了上课方便,后面的课程我就大部分在方法上抛出了)
2、编译时期异常抛出,调用者必须要做处理,因为不做就没办法通过编译,就无法运行
3、运行时期异常抛出,调用者可以不做处理,但是运行出了问题,程序终止,后续代码不会执行
(推荐运行前检查代码逻辑,其次可以像处理编译时期异常一样try..catch)
throw: 在方法内部抛出,后面跟上具体的异常对象
(面试题:throw与throws的区别)}
throws:
用在方法的声明后面,后面跟的是异常的类名
异常的类名可以是多个,多个类名之间使用逗号隔开
表示将异常抛出,交给调用者去处理
throws表示的是一种可能性,并不一定会发生这些异常
throw:
用在方法的内部,后面跟的是异常的对象;
只能是一个对象,不能抛出多个
表示抛出异常,由方法内部的语句体去做处理
throw表示的是方法内部一定会出现某种异常,是确定的。
public class ExceptionDemo5 { public static void main(String[] args) { try { function(); } catch (ParseException e) { e.printStackTrace(); }catch (ArithmeticException ae){ ae.printStackTrace(); } // function(); // function2(); // try { // function3(); // }catch (ArithmeticException ae){ // ae.printStackTrace(); // } System.out.println("你好!!!"); } public static void function3() { int a = 10; // int b = 2; int b = 0; if (b != 0) { System.out.println(a/b); }else { System.out.println("除数为0"); //在方法内部抛出,抛出的是一个具体的对象,表示一定会出现这样的问题 throw new ArithmeticException(); } } public static void function2() throws ArithmeticException { int a = 10; // int b = 2; int b = 0; // if(b!=0){ // System.out.println(a/b); // }else { // System.out.println("除数为0"); // } // try { // System.out.println(a/b); // }catch (ArithmeticException ae){ // ae.printStackTrace(); // } System.out.println(a / b); } public static void function() throws ParseException,ArithmeticException { String s = "2020-04-06 16:08:00"; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date date = sdf.parse(s); int a = 10; int b = 0; System.out.println(a / b); } }
处理异常的格式:
1、try...catch...
2、try...catch...catch
3、try...catch...catch...finally
4、try...catch..finally
注意:
1、无论try里面的代码会不会报错,都会执行finally中的语句
特殊情况:在执行finally之前,程序就已经退出
public class ExceptionDemo6 { public static void main(String[] args) { String s = "2020-04-06 16:45:00"; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); try { Date date = sdf.parse(s); System.exit(0); //这个语句就是结束程序运行 } catch (ParseException e) { e.printStackTrace(); } finally { //通常情况下,这里面放的是释放资源的代码 System.out.println("这是finally中的语句"); } System.out.println("你好!!"); } }
如果方法中有try..catch..finally,并且,在catch中有return语句,结果会是什么样子呢?
在finally之前执行还是在finally之后执行呢?在finally执行中间
面试题:finally,final,finalize他们三个你认识吗,他们什么什么区别?
回答:都认识,但是他们三个之间没有任何关系,只是长得像罢了。finally是在异常处理中遇到,一般是用于释放资源的
final是java中的一个关键字,他可以修饰类,成员变量,成员方法,修饰类,类不能被继承,修饰成员变量,
变量变常量,修饰成员方法,方法不能被重写;finalize是Object类中的一个方法名,该方法是用于垃圾回收的
但是什么时候回收不确定。
public class ExceptionDemo7 { public static void main(String[] args) { System.out.println(fun()); // a = } public static int fun(){ int a = 20; int b = 0; try { a = 30; System.out.println(a/b); a = 40; // 这一行肯定不会执行 }catch (ArithmeticException ae){ a = 60; // ae.printStackTrace(); return a; //当程序走到这里的时候,方法其实已经有了一个返回值路径,返回的就是60。 //但是程序此刻还没有结束,所以依旧会走finally中的语句 }finally { a = 50; System.out.println(a); // return a; } return a; // 这里其实是为了语法的正确,加了return } }
异常在继承关系中的使用:
1、子类重写父类方法时,子类的方法必须抛出相同的异常或父类异常的子类。(父亲坏了,儿子不能比父亲更坏)
2、如果父类抛出了多个异常,子类重写父类时,只能抛出相同的异常或者是他的子集,子类不能抛出父类没有的异常
3、如果被重写的方法没有异常抛出,那么子类的方法绝对不可以抛出异常,如果子类方法内有异常发生,
那么子类只能try,不能throws