Exception:Java程序在运行时出现的不正常情况。Java就按照面向对象的思想对不正常进行行为描述和对象的封装。
问题分两种:
Throwable:定义了对于问题共性的功能。
Exception总结:
public class test {
public static void main(String[] args){
int[] arr = new int[1];
int[] arr1 = new int[1024*1024*10000000000000];//Error:过大的整数: 10000000000000
System.out.println(arr[1]); //抛出异常,ArrayIndexOutOfBoundsException
}
}
Throwable:定义了对于问题共性的功能。
public class test {
public static void main(String[] args){
int[] arr = new int[1];
System.out.println(arr[1]);//ArrayIndexOutOfBoundsException
/*
发生问题时,jvm就将这个已知的问题封装成了对象
throw ArrayIndexOutOfBoundsException(1);
将问题抛给调用者调用者main函数。
main没有针对性的处理方式。main就继续往外抛给调用者jvm,jvm就使用了默认的处理方式。
将问题的名称+信息+位置在控制台上显示出来。让调用者看到并结束程序。
*/
}
}
异常的处理有两种:
1. 遇到问题不进行具体的处理,而是继续抛给调用者。其实就是在函数上通过throws关键字声明异常。告诉调用者处理
在编写功能时,编写者知道该功能有可能发生问题。而这个问题很容易来自于调用者传递的参数。而导致功能无法运行。
这时发生的问题就应该让该调用者知道,并最好让调用者有预先的处理方式。
声明问题需要使用关键字。throws异常类,声明的目的:让调用者处理。
class Demo{
int div(int a, int b) throws Exception{
return a/b;//throw new ArithmeticException("/ by zero");抛给主函数里面的int num = demo.div(4,0); 这一行的调用者
}
}
public class test {
public static void main(String[] args){
Demo demo = new Demo();
int num = demo.div(4,0); // 调用者
System.out.println("num = "+num);
}
}
2. 针对性的处理方式:捕获!
try{
}
catch (异常类 变量){
// 这是真正的捕获,处理异常的代码‘
}
finally {
// 一定被执行的代码
}
示例:
class Demo{
int div(int a, int b) throws Exception{
return a/b;//throw new ArithmeticException("/ by zero");抛给主函数里面的int num = demo.div(4,0); 这一行的调用者
}
}
public class test {
public static void main(String[] args){
Demo demo = new Demo();
try{
int num = demo.div(4,0); // 调用者
System.out.println("num = "+num);
}
catch (Exception e){
// 这是真正的捕获,处理异常的代码
System.out.println("异常啦");
}
System.out.println("over");
}
}
输出:
异常啦
over
class Demo{
int div(int a, int b) throws Exception{
return a/b;//throw new ArithmeticException("/ by zero");抛给主函数里面的int num = demo.div(4,0); 这一行的调用者
}
}
public class test {
public static void main(String[] args){
Demo demo = new Demo();
try{
int num = demo.div(4,0); // 调用者
System.out.println("num = "+num);
}
catch (Exception e){ //Exception e = new ArithmeticException("/ by zero");
// 这是真正的捕获,处理异常的代码
System.out.println("异常啦");
System.out.println(e.getMessage());//异常信息
System.out.println(e.toString());//异常名+异常信息
e.printStackTrace();//名字+位置+信息 jvm默认处理收到异常就是调用这个方法。将信息显示在屏幕上
}
System.out.println("over");
}
}
输出
异常啦
java.lang.ArithmeticException: / by zero
/ by zero
at day11.Demo.div(test.java:5)
java.lang.ArithmeticException: / by zero
at day11.test.main(test.java:13)
over
throws 声明异常;
throw 抛出异常。
class Demo{
int div(int a, int b) throws Exception{ //throws 声明异常
if(b==0){
throw new ArithmeticException("不能除以0哦");//throw 抛出异常,自定义异常信息
}
return a/b;//throw new ArithmeticException("/ by zero");抛给主函数里面的int num = demo.div(4,0); 这一行的调用者
}
}
public class test {
public static void main(String[] args){
Demo demo = new Demo();
try{
int num = demo.div(4,0); // 调用者
System.out.println("num = "+num);
}
catch (Exception e){ //Exception e = new ArithmeticException("/ by zero");
// 这是真正的捕获,处理异常的代码
System.out.println("异常啦");
System.out.println(e.getMessage());//异常信息
/*System.out.println(e.toString());//异常名+异常信息
e.printStackTrace();//名字+位置+信息 jvm默认处理收到异常就是调用这个方法。将信息显示在屏幕上
*/
}
System.out.println("over");
}
}
输出
异常啦
不能除以0哦
over
throw和throws有什么区别?
异常体系的特殊情况:
Exception:
异常体系最大的特点就是体系中的类以及类产生的对象,都具备可抛性,可抛性的意思是可以被throw和throws所操作。
异常的原则:
1. 功能内部有异常throw抛出,功能上一定要throws声明。内部抛什么,功能上就声明什么。声明的目的就是为了让调用者处理,如果调用者不出处理,编译失败。
class Demo{
int div(int a, int b) // 这里应该加上throws Exception
{
if(b==0){
throw new ArithmeticException("不能除以0哦");
}
return a/b;
}
}
public class test {
public static void main(String[] args){
Demo demo = new Demo();
int num = demo.div(4,0); // 调用者 ,这里应该要处理异常
System.out.println("num = "+num);
System.out.println("over");
}
}
输出:
Error:(15, 27) java: 未报告的异常错误java.lang.Exception; 必须对其进行捕获或声明以便抛出
修改后的代码:
class Demo{
int div(int a, int b) throws Exception{
if(b==0){
throw new Exception("不能除以0哦");
}
return a/b;
}
}
public class test {
public static void main(String[] args){
Demo demo = new Demo();
try{
int num = demo.div(4,0); // 调用者
System.out.println("num = "+num);
}catch (Exception e){
System.out.println(e.toString());
}
System.out.println("over");
}
}
输出:
java.lang.Exception: 不能除以0哦
over
2.特殊情况:当函数内通过throw抛出了RuntimeException及其子类的异常对象时,函数上可以不用throws声明。不声明的目的就是不让调用者处理。让调用者的程序停止,要对代码进行修改。
Exception分两种:
public class test {
public static void main(String[] args){
int[] arr = new int[2];
System.out.println("element:"+getElement(arr,3));
}
//定义一个功能,返回一个整型数组中指定位置的元素
public static int getElement(int[] arr, int index){
if(arr == null){
throw new NullPointerException("数组实体不存在");
}
if(index<0||index>arr.length){
throw new ArrayIndexOutOfBoundsException(index+",角标不存在");
}
// NullPointerException和ArrayIndexOutOfBoundsException都属于RuntimeException的子类
int element = arr[index];
return element;
}
}
在自定义的程序中,如果有了问题,也可以像Java中的异常一样,对问题进行描述。
举例:
定义一个功能可以实现除法运算,但是除法不可以为负数。
//将负数为除数的问题描述
class FushuException extends RuntimeException{
FushuException(){
super();
}
FushuException(String message){
super(message);//父类已经处理了信息,子类只需要把信息传给父类即可
}
}
class Demo{
int div(int a, int b)
{
if(b<0){
throw new FushuException("负数不可以作为整数");
}
if(b==0){
throw new ArithmeticException("不能除以0哦");
}
return a/b;
}
}
public class test {
public static void main(String[] args){
Demo demo = new Demo();
try{
int num = demo.div(4,-1); // 调用者
System.out.println("num = "+num);
}catch (Exception e){
System.out.println(e.toString());
}
System.out.println("over");
}
}
小结
异常:其实就将问题封装成对象,并抛给调用者。
1.如果声明了,就需要调用者处理(继续声明 or 捕获)
什么时候声明?什么时候捕获?
举例:
毕老师用电脑上课。
class Computer{
public void run(){
System.out.println("电脑运行");
}
}
class Teacher{
private String name;
private Computer comp;
Teacher(String name){
name = this.name;
comp = new Computer();
}
//讲课
public void prelect(){
comp.run();
}
}
public class test {
public static void main(String[] args){
Teacher teacher = new Teacher("毕老师");
teacher.prelect();
}
}
上课过程中,会发生问题:比如电脑蓝屏,电脑冒烟了,需要对问题进行描述。
//是可以处理的异常,继承Exception
class LanPingException extends Exception{
LanPingException(){
super();
}
LanPingException(String message){
super(message);
}
}
class MaoYanException extends Exception{
MaoYanException(){
super();
}
MaoYanException(String message){
super(message);
}
}
class Computer{
private int state = 2;//0为正常状态
public void run() throws LanPingException, MaoYanException{
if(state == 1)
throw new LanPingException("电脑蓝屏了");
if(state == 2)
throw new MaoYanException("电脑冒烟了");
System.out.println("电脑运行");
}
public void reset(){
System.out.println("电脑重启");
state = 0;
}
}
class Teacher{
private String name;
private Computer comp;
Teacher(String name){
this.name = name;
comp = new Computer();
}
//讲课
public void prelect() throws MaoYanException{
try{
comp.run();
System.out.println("讲课");
}
catch (LanPingException e){
System.out.println(e.toString());
comp.reset();
//继续讲课
prelect();
}
catch (MaoYanException e){ //MaoYanException e = new MaoYanException();
System.out.println(e.toString());
exc();
throw e;//继续抛
}
}
public void exc(){
System.out.println("同学们自己练习");
}
}
public class test {
public static void main(String[] args){
Teacher teacher = new Teacher("毕老师");
try{
teacher.prelect();
}
catch (MaoYanException e){
System.out.println("换老师");
}
}
}
当Computer类中的state初始化为0,时输出结果:
电脑运行
讲课
当Computer类中的state初始化为1,时输出结果:
day11.LanPingException: 电脑蓝屏了
电脑重启
电脑运行
讲课
当Computer类中的state初始化为2,时输出结果:
day11.MaoYanException: 电脑冒烟了
同学们自己练习
换老师
请注意,老师讲课的函数prelect抛出LanPingException,这是不合适的,应该进一步抽象成NoPlanException,进行异常转换,封装本层异常,对外暴露对方能处理的异常。
//是可以处理的异常,继承Exception
class LanPingException extends Exception{
LanPingException(){
super();
}
LanPingException(String message){
super(message);
}
}
class MaoYanException extends Exception{
MaoYanException(){
super();
}
MaoYanException(String message){
super(message);
}
}
//课时无法进行
class NoPlanException extends Exception{
NoPlanException(){
super();
}
NoPlanException(String message){
super(message);
}
}
class Computer{
private int state = 2;//0为正常状态
public void run()throws LanPingException, MaoYanException{
if(state == 1)
throw new LanPingException("电脑蓝屏了");
if(state == 2)
throw new MaoYanException("电脑冒烟了");
System.out.println("电脑运行");
}
public void reset(){
System.out.println("电脑重启");
state = 0;
}
}
class Teacher{
private String name;
private Computer comp;
Teacher(String name){
this.name = name;
comp = new Computer();
}
//讲课
public void prelect() throws NoPlanException{
try{
comp.run();
System.out.println("讲课");
}
catch (LanPingException e){
System.out.println(e.toString());
comp.reset();
//继续讲课
prelect();
}
catch (MaoYanException e){ //MaoYanException e = new MaoYanException();
System.out.println(e.toString());
exc();
throw new NoPlanException("课时进度停止");//继续抛,异常转换
}
}
public void exc(){
System.out.println("同学们自己练习");
}
}
public class test {
public static void main(String[] args){
Teacher teacher = new Teacher("毕老师");
try{
teacher.prelect();
}
catch (NoPlanException e){
System.out.println(e.toString());
System.out.println("换老师");
}
}
}
输出结果:
day11.MaoYanException: 电脑冒烟了
同学们自己练习
day11.NoPlanException: 课时进度停止
换老师
再例子说明异常转换:封装本层异常,对外暴露对方能处理的异常。
import java.sql.SQLException;
class NoValueException extends Exception{
NoValueException(){
super();
}
NoValueException(String message){
super(message);
}
}
class App{
public void show(){
try{
new DBTool().oprate();
}catch (NoValueException e){ //不是直接将SQLException抛给数据库调用者,而是告诉他NoValueException
}
}
}
class DBTool{
public void oprate() throws NoValueException{
//连接数据库
try{
throw new SQLException();
//数据操作throw new SQLException
}catch (SQLException e){
//解决了数据库异常
}
//关闭数据库
}
}
public class DBTest {
}
try
catch
finally
finally的作用是:无论是否有异常发生,都要对资源进行释放。资源释放的动作就是在finally 代码块中的。
public class ExceptionDeom {
public static void main(String[] args){
try{
int num = 4/0;
System.out.println("num:"+num);
}catch (Exception e){
System.out.println(e.toString());
return ;
//System.exit(0); //退出jvm。只有这种情况,finally也不执行
}finally {
System.out.println("finally");//一定会被执行的代码
}
System.out.println("over");
}
}
输出
java.lang.ArithmeticException: / by zero
finally
over
try{
}
catch(){
}
finally{
}
的几种组合方式。
1. 没有资源需要释放,仅仅是处理异常
try{
}
catch(){
}
2. 一个try多个catch,一般对应的是被调用的函数,抛出多个异常的情况,分别处理。
try{
}
catch(){
}
catch(){
}
catch(){
}
注意:在多catch语法上的特殊地方,如果catch中的异常类存在子父类。父类的catch一定要放在子类的下面,否则编译失败。
3. 不一定要处理异常,但是有资源需要释放
try{
}
finally{
}
函数必须声明异常
public void show() throws Exception{ //必须申明异常
try{
throw new Exception();
}finally {
}
}
有catch,函数show就不需要声明异常
public void show() {
try{
throw new Exception();
}catch (Exception e){
}
finally {
}
}
覆盖时:
package day11;
/*
Exception
-----------AException
----------------------AAException
-----------BException
*/
class AException extends Exception{
AException(){
super();
}
AException(String message){
super(message);
}
}
class AAException extends AException{
AAException(){
super();
}
AAException(String message){
super(message);
}
}
class BException extends Exception{
BException(){
super();
}
BException(String message){
super(message);
}
}
class Fu{
void show() throws AException{
System.out.println("fu show");
throw new AException("A 异常");
}
}
class Zi extends Fu{
void show() throws AException{//或者抛出AAException, 但是不能抛出BException
System.out.println("zi show");
throw new AException("A 异常");
}
}
class Tool{
void method(Fu f){
try {
f.show();
}catch (AException e){
System.out.println(e.toString());
}
}
}
public class ExceptionDemo7 {
public static void main(String[] args){
Tool tool = new Tool();
tool.method(new Zi());
/*
输出
zi show
day14.AException: A 异常
*/
}
}
注意:有一种情况,只能try不能throws
被覆盖的方法没有抛出异常。
那么子类在覆盖时,子类方法中发生了异常,就只能try,无法throws声明。
interface Inter{
void show();
}
class Demo implements Inter{
public void show(){ // 这里不能用throws声明异常
try {
throw new Exception();
}
catch (Exception e){
throw new RuntimeException("");
//将编译时检测异常,转换成运行时的异常,这样就可以不用声明异常
}
}
}