定义
程序出现了不正常,不该有的错误的状况
分类
抛出(问题)类:Throwable
严重性的问题Error:
程序员解决不了(内存溢出,硬盘坏道)
一般性的问题Exception:
编译器问题:
非RuntimeException:不修改,不能运行
运行时问题:
RuntimeException:程序员代码不够安全,不够严谨导致最终需要修改
处理
程序出现问题,程序员未作处理
没有,JVM给出提示
Exception in thread “main” java.lang.ArithmeticException: / by zero
at com.igeekhome.ExceptionDemo.ExceptionDemo.main(ExceptionDemo.java:49)
给出了异常全路径名:java.lang.ArithmeticException
具体问题点:/ by zero
出错的位置:
com.igeekhome.ExceptionDemo.ExceptionDemo.main(ExceptionDemo.java:49)
程序结束
如何处理
方案一:
1、格式
try{
可能出现异常的代码
}catch(异常类名 异常类对象){
解决异常的方案
}
2、完整格式
try{
可能出现异常的代码
}catch(异常类名 异常类对象){
解决异常的方案
}finally{
释放资源或者做最终的处理
}
注意点:
1、try里的代码越少越好(检查代码质量是否有问题,Java会浪费更多内存和资源关注此代码区域)
2、可能出现的异常才放到try里
3、catch里面必须要有内容,否则隐藏了异常
特殊格式:
1、一个异常的处理
2、多个异常的处理
每一个异常,都创建try…catch
写一个try,多个catch
try{
}catch(异常类名1 异常对象1){
}catch(异常类名2 异常对象2){
}
……
3、多个异常处理简单方式
try{
}catch(异常类名1 | 异常类名2 | 异常类名3 ... e){
}
条件:
1、多个异常是平级关系
2、有共同的处理方案
4、最终处理方式
try{
}catch(){
}finally{
释放资源或者做最终的处理
}
try catch的全部格式:
1、try catch finally
2、try catch
3、try finally
4、try catch catch
5、try catch catch finally
6、单独只有一个全都不可以
7、没有try的全都不可以
finally(最后的):
被finally控制的语句体一定会被执行
例外:在finally之前写了退出jvm的语句,肯定不执行
例如:
int a = 11;
int b = 0;
String string = "2017-12-22";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
try {
System.out.println(simpleDateFormat.parse(string));
System.out.println(a / b);
} catch (ParseException e) {
e.printStackTrace();
} catch (ArithmeticException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
注意:
1、try里面出现异常,会抛出异常,和catch去进行匹配,从上到下一个一个匹配,有匹配的,就执行catch里的处理
然后结束try…catch语句,继续try…catch后面的代码
2、若必须有Exception处理,它必须放到最后,否则它全包了,他之后的异常都无效(编译不通过)
3、能明确知道报的哪个异常类就明确,放到靠前位置,实在不知道会报什么异常,但是觉得有可能报,就写Exception的处理,放到最后
4、平级关系的异常谁前谁后无所谓,如果出现父子关系的异常,必须子前父后
方案二:
throws
程序员不想处理异常,将其抛出,抛给调用者去处理
调用者有可能处理:try catch
如果也不处理:将其再抛出
最后没有程序员去处理,jvm去处理
格式:
throws 异常类名
throws 放在方法的括号后面
注意点:
1、尽量不要让main抛异常
2、编译异常抛出,将来调用者必须处理(不要抛到main)
3、运行异常,编译期间不出错,也不需写throws,但是最后,还是要解决问题:去处理
4、某个方法throws多个异常,并且有父子关系话,调用者处理时,只需要catch父类即可
例如:
public static void main(String[] args) {
try {
method();
} catch (ParseException e) {
e.printStackTrace();
}
try {
method2();
} catch (ArithmeticException e) {
e.printStackTrace();
}
}
public static void method() throws ParseException {
String string = "2017-12-22";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
System.out.println(simpleDateFormat.parse(string));
}
public static void method2() {
int a = 11;
int b = 0;
System.out.println(a/b);
}
方案三:
throw:如果有异常,需要抛出的话,抛出的是真正的异常对象(throws后跟异常类名)
throws和throw区别:
throws:
放在方法名括号后,后面跟的是异常类名
后面可以跟多个异常类名,逗号隔开
表示抛出异常,由方法调用者来处理
表示的是异常的一种可能性,并不一定会发生
throw:
放在方法体里,后面跟的是异常对象
只能抛出一个异常对象
表示抛出异常,由方法体内的语句处理
throw是实实在在的抛出了异常对象
非运行时异常需要方法名后加throws,运行时不用
例如:
public static void main(String[] args) {
// 调用者调用别人的代码,运行之前,还不知道会抛出异常
try {
method(11, 0);
} catch (Exception e) {
System.out.println("除数不能为0");
}
try {
method2();
} catch (DataFormatException e) {
e.printStackTrace();
}
}
public static void method(int a, int b) {
if (b == 0) {
throw new ArithmeticException();
} else {
System.out.println(a / b);
}
}
public static void method2() throws DataFormatException {
String string = "2017-12-22";
SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
sDateFormat.parse(string);
} catch (ParseException e) {
//你知道问题所在,但是你解决不了,你就上抛
throw new DataFormatException();
}
}
自定义异常
Java不可能做到所有异常都定义
所以程序员会根据业务逻辑创建项目里的异常类
两种方式创建异常类:
1、继承Exception:编译期间会要求捕获异常
2、继承RuntimeException
例如:
public class ExaminationException extends RuntimeException {
public ExaminationException(String message){
super(message);
}
}
public class ScoreBeyondRangeException extends Exception {
public ScoreBeyondRangeException(String message){
super(message);
}
}
public class Teacher {
public void checkScore(int score) throws ScoreBeyondRangeException {
if (score>100||score<0) {
throw new ScoreBeyondRangeException("录入分数不正确");
} else {
System.out.println("录入分数正确");
}
}
public void examination(int a,int b){
if (b==0) {
throw new ExaminationException("除数不能为0");
} else {
System.out.println("两数相除得:"+a/b);
}
}
}
public class Student {
public static void main(String[] args) {
System.out.println("请输入学生分数:");
Scanner scanner=new Scanner(System.in);
int score=scanner.nextInt();
Teacher teacher=new Teacher();
try {
teacher.checkScore(score);
} catch (ScoreBeyondRangeException e) {
e.printStackTrace();
}
System.out.println("--------------------------------");
try {
teacher.examination(10, 0);
} catch (ExaminationException e) {
e.printStackTrace();
}
}
}
异常的注意点
1、如果父类方法抛出一个或多个异常时,子类重写父类方法时,子类方法必须抛出与父 类相同的异常类或者父类抛出异常类的子类
2、如果被重写的父类方法没有抛出异常,子类一定不能抛出异常,如果子类重写方法里必须有异常,自己处理掉,只能try catch finally
面试题
final、finally、finalize()的区别:
final
修饰类:类不能被继承
修饰方法:方法不能被重写
修饰变量:常量
finally
异常处理的最后一部分
用于释放资源等
最后被一定被执行(在finally之前写了退出jvm的语句,肯定不执行)
finalize()
当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法
如果在catch里面有return语句,请问finally的代码还执行吗?
例如:
int a = 21;
try {
System.out.println(a / 0);
a = 20;
} catch (Exception e) {
a = 30;
return a;
/*
* catch 里的return a; 已经形成了getInt的返回值,此时a为30,那就返回30
* 发现finally存现,继续走finally代码(如果代码里没有return),虽然对a进行重新赋值为40,但是不起作用
* (如果代码里有return语句,就返回新的值)
*/
} finally {
a = 40;
return a;
}
// return a; //到不了的代码