29、异常

定义

程序出现了不正常,不该有的错误的状况
在这里插入图片描述

分类

抛出(问题)类: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; //到不了的代码
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值