-
异常:就是程序在运行时出现不正常情况,
异常由来:问题也就是现实生活中一个具体的事物,也可以通过Java的类的形式进行描述,并封装成对象。其实就是Java对不正常情况进行描述后的对象体现。对于问题的划分:两种:一种是严重的问题,一种非严重的问题。
对于严重的,java通过Error类进行描述。
(一般不编写针对行的代码对其进行处理。)对于非严重的,Java通过Exception类进行描述。
(对于Exception可以进行针对性的处理方式进行处理。)无论Error后者Exception都具有一些共性内容。
比如:不正常情况的信息,引发原因。Throwable
|------Error
|------Exception
|------RuntimeException:除零,空指针,类型转换,数组越界等。
|------
class Demo
{
int div(int a, int b)
{
return a/b;
}
}
public class ExceptionDemp {
public static void main(String[] args)
{
Demo d = new Demo();
int x = d.div(4,0);
System.out.println("x = " + x);
System.out.println("OVER");
}
}
- 异常处理
java提供了特有的语句进行处理
try
{
需要被检测的代码;
}
catch(异常类 变量)
{
处理异常的代码:处理方式;
}
finally
{
一定会执行的代码;
}
class Demo
{
int div(int a, int b)
{
return a/b;
}
}
public class ExceptionDemp {
public static void main(String[] args)
{
Demo d = new Demo();
try {
int x = d.div(4,0);
System.out.println("x = " + x);
}
catch (Exception e) //Exception e = new ArithmeticException();
//多态:父类引用指向子类对象,只能调用父类方法,执行子类覆写的方法
{
System.out.println("除零了");
System.out.println(e.toString()); // 异常名称:异常信息
System.out.println(e.getMessage()); //异常信息
e.printStackTrace(); //异常名称:异常信息,异常出现的位置。
//其实JVM默认的异常处理机制,就是在调用printStackTrace
//打印异常的堆栈的跟踪信息。
}
System.out.println("OVER");
}
}
3. 对捕获的异常对象进行常见的方法操作
e.toString() // 异常名称:异常信息
e.getMessage() //异常信息
e.printStackTrace(); //异常名称:异常信息,异常出现的位置。
class Demo
{
int div(int a, int b) throws Exception //throws谁调用我谁处理,
//在功能上通过throws的关键字声明了该功能可能会出现问题
{
return a/b;
}
}
方法一:向上抛出
public class ExceptionDemp {
public static void main(String[] args) throws Exception //扔给JVM处理(谁调用我谁处理)
{
Demo d = new Demo();
int x = d.div(4,0);
System.out.println("x = " + x);
System.out.println("OVER");
}
}
方法二:处理
public class ExceptionDemp {
public static void main(String[] args) throws Exception //扔给JVM处理(谁调用我谁处理)
{
Demo d = new Demo();
try {
int x = d.div(4, 0);
System.out.println("x = " + x);
}
catch (Exception e)
{
System.out.println("除零了");
}
System.out.println("OVER");
}
}
-
对多异常的处理
a. 申明异常时,建议申明更为具体的异常,这样处理的可以更具体。
b. 对方声明几个异常,就对应几个catch块,不要定义多余的catch块
如果多个catch块中的异常出现继承关系,父类异常catch块放在最下面。建议在进行catch处理时,catch中一定要定义具体处理方式。
也不要简单定义一句e.printStackTrace(),
也不要简单的就书写一条输出语句。 -
自定义异常
因为项目中会出现特有的问题,而这些问题并未被Java所描述并封装对象。
所以对于这些特有问题可以安装java的对对象封装的思想。
将特有的问题,进行自定义的异常封装。当在函数内部出现了throw抛出异常对象,那么就必须要给对应的处理动作。
要么在内部try catch处理
要么在函数上throws声明让调用者处理。
一般情况下,函数内出现异常,函数上需要声明
public class FuShuException extends Exception
{
}
class Demo1{
int div(int a, int b) throws FuShuException
{
if(b < 0)
throw new FuShuException(); //函数内部抛出异常,方法上一定要声明
return a/b;
}
}
class ExceptionDemo2
{
public static void main(String[] args) {
Demo1 d = new Demo1();
try
{
int x = d.div(4,-1);
System.out.println("x = " + x);
}
catch (FuShuException e)
{
System.out.println(e.toString());
System.out.println("除数出现负数了");
}
}
}
发现打印的结果中只有异常的名称,却没有异常的信息
因为自定义的异常并没有定义信息。
如何自定义信息呢?
public class FuShuException extends Exception
{
private String msg;
FuShuException(String msg)
{
this.msg = msg;
}
public String getMessage()
{
return msg;
}
}
class Demo1{
int div(int a, int b) throws FuShuException
{
if(b < 0)
throw new FuShuException("除数中出现了负数的情况: / by 负数"); //函数内部抛出异常,方法上一定要声明
return a/b;
}
}
class ExceptionDemo2
{
public static void main(String[] args) {
Demo1 d = new Demo1();
try
{
int x = d.div(4,-1);
System.out.println("x = " + x);
}
catch (FuShuException e)
{
System.out.println(e.toString()); //异常名称:异常信息
System.out.println(e.getMessage()); //异常信息
System.out.println("除数出现负数了");
}
}
}
Exception已经定义好了。
因为父类中已经把异常信息的操作都完成了。
所以子类只要在构造时,将异常信息传递给父类通过super语句。
那么就可以直接通过getMessage方法获取自定义信息。
public class FuShuException extends Exception
{
FuShuException(String msg){
super(msg);
}
}
注意:自定义异常必须要继承Exception
原因:异常体系有一个特点,因为异常类和异常对象都被抛出。
他们都具备可拋性,这个可抛性时Throwable这个体系中独有的特点。
只有这个体系中的类和对象才可以被throw和throws操作。
throw和throws的区别:
throws使用在函数上,后面可以跟多个异常类,用逗号隔开
throw使用在函数内,后面跟的是异常对象。
-
RuntimeException,运行时异常(Exception特殊异常类,引发程序停止)
如果在函数内抛出该异常,函数上可以不用声明,编译一样通过。
如果在函数上声明了该异常,调用者可以不用处理,编译一样通过。
让程序停下来,让程序员修改代码。之所以不用在函数声明,是因为需要调用者处理。
当该异常发生,希望程序停止。因为在运行时,出现可无法继续运算的情况,希望停止程序后,对代码进行修改。自定义异常时:如果该异常的发生,无法再继续进行运算。
就让自定义异常继承RuntimeException。
对于异常分两种:
a. 编译时被检测的异常。(非RuntimeException)
b. 编译时不被检测的异常(运行时异常,RuntimeException以及其子类)
练习:
a. 老师用电脑上课
比如:电脑蓝屏,
电脑冒烟
要对问题进行描述,封装成对象
可是当冒烟发生后,出现讲课进度无法继续。
出现讲课问题:课时计划无法完成。
class LanPingException extends Exception
{
LanPingException(String msg){
super(msg);
}
}
class MaoYanException extends Exception
{
MaoYanException(String msg)
{
super(msg);
}
}
class NoPlansException extends Exception
{
NoPlansException(String msg)
{
super(msg);
}
}
class Computer
{
private int state = 3; //状态标识
public void run() throws LanPingException, MaoYanException
{
if(state == 2)
throw new LanPingException("蓝屏了");
if(state == 3)
throw new MaoYanException("冒烟了");
System.out.println("电脑运行");
}
public void reset()
{
state = 1;
System.out.println("电脑重启");
}
}
public class Teacher {
private String name;
private Computer cmpt;
Teacher(String name)
{
this.name = name;
cmpt = new Computer();
}
public void prelect() throws NoPlansException
{
try
{
cmpt.run();
}
catch (LanPingException e)
{
cmpt.reset();
}
catch (MaoYanException e)
{
test();
throw new NoPlansException("课时无法继续 原因:" + e.getMessage());
//throw 停止当前函数运行,相当于return
}
System.out.println("讲课");
}
public void test()
{
System.out.println("做练习");
}
}
class Test
{
public static void main(String[] args) {
Teacher t = new Teacher("毕老师");
try
{
t.prelect();
}
catch (NoPlansException e)
{
System.out.println(e.toString());
System.out.printf("换老师或者放假");
}
}
}
- finally关键字
一定会执行的代码,通常用于关闭资源。
class NoException extends Exception //数据库没有操作成功
{
}
public void method() throws NoException //SQLException{
{
/*
连接数据库;
数据库操作;//throw new SQLException();
关闭数据库;//该动作,无论数据操作是否成功,一定要关闭资源
*/
try
{
连接数据库;
数据操作;//throw new SQLException();
}
catch (SQLException e)
{
会对数据库进行异常处理;
throws new NoException(); //调用者可以识别
}
finally {
关闭数据库;
}
}
- 异常格式
第一种;
try
{
}
catch(Exception e)
{
}
第二种:
try
{
}
catch()
{
}
finally
{
}
第三种:
try
{
}
finally
{
}
class Demo
{
public void method()
{
try
{
throw new Exception();
}
catch(Exception e)
{
try
{
throw e;
}
catch()
{
}
}
}
}
注意:catch是用于处理异常。如果没有catch就代表异常没有被处理过,如果该异常是检测时异常。那么必须要声明或者处理。
- 异常在子父类中的体现:
a. 子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法,只能抛出父类异常或者该异常的子类。(父类范围大,子类的范围小于等于父类)
b. 如果父类方法抛出多个异常,那么子类在覆盖方法时,只能抛出父类异常的子类。
c. 如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常。
如果子类方法发生了新异常,就必须进行try处理,绝对不能抛。
练习:
有一个圆形和长方形
都可以获取面积。对于面积如果出现非法的数值,视为时获取面积出现的问题。
问题通过异常来表示。
现在对这个程序进行基本设计。
class NoValeException extends RuntimeException // Exception
{
NoValeException(String msg)
{
super(msg);
}
}
interface Shape
{
void getArea();
}
class Rec implements Shape
{
private int len, wid;
Rec(int len, int wid) //throws NoValeException
{
if(len <=0 || wid <=0)
throw new NoValeException("出现非法值");
this.len = len;
this.wid = wid;
}
public void getArea()
{
System.out.println(len*wid);
}
}
class Circle implements Shape
{
private int radius;
public static final double PI = 3.14;
Circle(int radius)
{
if(radius<=0)
throw new NoValeException("非法");
this.radius = radius;
}
public void getArea()
{
System.out.println(radius*radius*PI);
}
}
class Test2
{
public static void main(String[] args) {
Rec r = new Rec(3,4);
r.getArea();
/*
try{
Rec r = new Rec(-3,4);
r.getArea();
}
catch (NoValeException e)
{
System.out.println(e.toString());
}
System.out.println("OVER");
*/
Circle c = new Circle(-1);
r.getArea();
}
}
异常:将正常代码和异常处理代码分离开,方便处理和阅读。
总结
异常:是对问题的描述。将问题进行对象的风筝。
异常体系
Throwable
|---Error
|---Exception
|---RuntimeException
异常体系的特点:异常体系中的所有类记忆建立的对象都具备可抛性。
也就是说可以被throw和throws关键字所操作。也只有异常体系具备这个特点。
throw和throws的用法:
throw定义在函数内,用于抛出异常对象。
throws定义在函数上,用于抛出异常类,可以抛出多个用逗号隔开。
当函数内容有throw抛出异常对象,并未进行try处理,必须要在函数上声明,否则编译失败。
注意:RuntimeException除外。也就是说,函数内如果抛出RuntimeException异常,函数上可以不用声明。
如果函数声明了异常,调用者需要进行处理。处理方法可以throws可以try.
异常有两种:
编译时被检测异常
该异常在编译时,如果没有处理——没有抛也没有try,编译失败。
该异常被标识,代表这可以被处理。
运行时异常(编译时不检测)
在编译时,不需要处理,编译器不检查
该异常的发生,建议不处理,让程序停止,需要对代码进行修正。
异常处理语句:
try
{
需要被检测的代码;
}
catch()
{
处理异常的代码;
}
finally
{
一定会执行的代码;
}
有三种结合方式
第一种;
try
{
}
catch(Exception e)
{
}
第二种:
try
{
}
catch()
{
}
finally
{
}
第三种:
try
{
}
finally
{
}
注意:
a. finally中定义的通常是:关闭资源代码。因为资源必须关闭。
b. finally中只有一种情况不会执行。当执行到System.exit(0);finally不会执行。
自定义异常:定义类继承Exception或者RuntimeException
a. 为了让该自定义类具备可抛性。
b. 让该类具备操作异常的共性方法。
当要定义自定义异常的信息时,可以使用父类已经定义好的功能。
异常信息传递给父类的构造方法。
class MyException extends Exception
{
MyException(String msg)
{
super(msg);
}
}
自定义异常:按照java的面向对象思想,将程序中出现的特有问题进行封装。
异常的好处:
a. 将问题进行封装。
b. 将正常流代码和问题代码相分离,方便阅读。
异常的处理原则:
a. 处理方式有两种:try或者throws
b. 调用到抛出异常的功能时,抛出几个,就处理几个。
一个try对应多个catch.
c. 多个catch,父类的catch放到最下面。
d. catch内,需要定义针对性的处理方式。不要简单的定义printStackTrace,也不要输出语句,也不要不写。
当捕获到的异常,本功能处理不了,可以继续在catch中抛出。
try
{
ttrow new AException();
}
catch(AException e)
{
throw e;
}
如果该异常处理不了,但并不属于该功能的异常。
可以将异常转换后,在抛出和该功能相关的异常。
或者异常可以处理,当需要将异常产生的和本功能相关的问题提供出去。
让调用者知道并处理,也可以将捕获异常处理后,转换新的异常并抛出。
try
{
throw new AException();
}
catch(AException e)
{
//对AException处理
throw new BException();
}
异常的注意事项:
在子类覆盖时:
a. 子类抛出的异常必须时父类的异常的子类或者子集。
b. 如果父类或者接口没有抛出异常时,子类覆盖出现异常,只能try不能throws。
(子类不能抛出比父类多的异常)