异常:英文单词就是Exception,字面意思,可以理解为意外。
对于初学者我来说,现在的代码都是理想状态下,所以为了考虑一个代码的安全性以及健壮性,一个程序是离不开异常的。
【异常类继承关系】
Java中,所有异常的父类为Throwable
Throwable类有两个子类,Exception类和Error类
Error类:为无法处理的异常。字面意思,错误。一般出现这种情况,都是系统级错误,会反馈给JVM,来停下程序。
Exception类:为可处理异常。比如RuntimeException或是ArrayIndexOutOfBoundsException
Exception类中分两种:运行时异常或是非运行时异常(编译时异常)
运行时异常:RuntimeException。例如:NullPointException,ArrayIndexOutOfBoundsException等。
非运行时异常:除了RuntimeExpcetion之外的异常都是非运行时异常,异常类比较多。所以初学者的我,暂时只用Exception类
运行时异常,Java编译器不要求必须进行声明和捕获。
非运行时异常,Java编译器强制必须进行声明和捕获,不然编译不给通过。
那么看看异常在平常程序中起到的作用。
举个例子,我写了一个方法,计算长方形面积,形参为长和宽。理想状态下,输入3和4,得出12
但如果是-3呢?0呢?那么面积为-12?0?岂不是很恐怖
class Rectangle{
private double length;
private double width;
public void setLength(double length){
this.length=length;
}
public double getLength(){
return this.length;
}
public void setWidth(double width){
this.width=width;
}
public doube getWidth(){
return this.width;
}
public Rectangle(double length,double width){
this.length=length;
this.width=width;
}
public double getArea(){
return length*width;
}
}
class Demo{
public static void main(String[] args){
Rectangle r=new Rectangle(3.0,4.0);
System.out.println(r.getArea());
}
}
打印结果:
打印结果:12.0,那么如果将参数改成负数
代码修改:
class Demo{
public static void main(String[] args){
Rectangle r=new Rectangle(-3.0,4.0);
System.out.println(r.getArea());
}
}
打印结果:
打印结果:-12。居然有长方形的面积为0?
这时候如果调用者没看到,以为运行正常,没出错,那么导致的后果就是可能没人发现。
所以这时候将异常加入进来前,要么直接用异常子类,或是自定义异常类。
很多时候可使用异常子类,但如果你感觉异常子类并不能完好的反馈出异常信息,可以自定义异常类。
如果自定义异常类,那么就要考虑要继承关系:
【继承RuntimeException还是Exception类】
Exception:
如果在函数中抛出Exception类,就已经不是正常运行的异常了。
所以编译器会认为有隐患。需要声明或是捕获出来。
声明的意义就是为了告诉调用者这里有异常,进行处理。
RuntimeException:
RuntimeException之所以是Runtime是因为代码本身语法编译没有问题
异常的原因可能是因为传参错误或是其他逻辑问题。
不声明的意义就是不让调用者知道这里有异常,调用者可能传参或是逻辑错误时,立刻让程序停止,让调用者看到现象
将原本错误的参数或逻辑修改。
所以我们这里是为了让调用者知道自己传参的错误,那么我们应该继承于RuntimeException
【RuntimeException例子】
class Rectangle{
//code .........
public double getArea(){
if(width<=0 || length<=0){
throw new RuntimeException("你的长或宽有误,请及时修正");
}
return length*width;
}
}
//异常类继承与RuntimeException
class ValuesException extends RuntimeException{
public ValuesException(){
super();
}
public ValuesException(String message){
super(message);
}
}
class Demo{
public static void main(String[] args){
Rectangle r=new Rectangle(-3.0,4.0);
System.out.println(r.getArea());
}
}
【例子2】
class Person{
private String name;
private int age;
//code.....
public Person(String name,int age){
this.name=name;
this.age=age;
}
public String toString(){
if(age>=200 || age<=0){
throw new AgeException("你是神仙啊?");
}
return name+"'age is"+age;
}
}
class AgeException extends RuntimeException{
public AgeException(){
super();
}
public AgeException(String message){
super(message);
}
}
class Demo{
public static void main(String[] args){
Perosn p=new Person("lgb",1500);
System.out.println(p.toString());
}
}
但如果此时我将姓名调至1500,那岂不是很恐怖?
此时也是一样需要RuntimeException来修正。
【知识点】
抛出异常:throw new 异常类
声明:可以理解为汇报调用者异常,用throws 异常类,抛出什么异常对象,异常类就是什么
捕获:处理问题 ,try/catch,try是可能会出现异常的代码,catch为解决异常的代码
【Exception例子】
教师上Java课用电脑,是不是有可能出现电脑蓝屏的情况?电脑蓝屏老师可以处理吗?当然有,重启呗。。。
所以这个是可以解决的问题。而电脑蓝屏是运行时会出现的问题,所以应该写在run方法中,这个异常抛出后,要声明。
而调用者看到后。捕获即可
接下来,还有可能教师将水打翻了,电脑凉了。这个也是可以处理的,只不过只能间接性处理,做练习。但是问题本质还未解决
因为培训机构里面电脑坏了,只能给出间接处理,比如换电脑,或是做练习。电脑坏了并不会直接处理,只能汇报给维修公司。
那么就需要另一个异常。称为异常转换
/*
教师类
*/
class Teacher{
private String name;
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
//讲课方法
public void teach(Computer c)throws RepairException{
try{
c.run();
}catch(BlueScreenException e){
c.reset();
}catch(InletWaterException e){
c.test();
throw new RepairCompany("汇报维修公司");
}
System.out.println("讲课");
}
//重启方法
public void reset(){
System.out.println("电脑重启了");
}
//做练习方法
public void test(){
System.out.println("做练习吧");
}
}
/*
电脑类
*/
class Computer{
private int state;//如果state=1,电脑蓝屏,如果state=2,电脑进水
public void setState(int state){
this.state=state;
}
public int getState(){
return state;
}
public void run() throws BlueScreenException{
System.out.println("电脑开机了");
if(state==1){
throw new BlueScreenException("电脑蓝屏");
}
if(state==2){
throw new InletWaterException("电脑进水");
}
}
}
/*
测试类
*/
class Demo{
public static void main(String[] args){
Teacher t=new Teacher("lgb");
Computer c=new Computer();
//c.setState(1);
c.SetState(2);
try{
t.teach(c);
}catch(RepairCompanyExpcetion e){
e.printStackTrace();
}
}
}
/*
蓝屏异常类
*/
class BlueScreenException extends Exception{
public BlueScreenException(){
super();
}
public BlueScreenException(String message){
super(message);
}
}
/*
进水异常类
*/
class InletWaterException extends Exception {
public InletWaterException(){
super();
}
public InletWaterException(String message){
super(message);
}
}
/*
汇报维修公司类
*/
class RepairCompanyException extends Exception {
puhblic RepairCompanyException(){
super();
}
puhblic RepairCompanyException(String message){
super(message);
}
}
异常在继承或实现中的细节:
1.在子类继承父类的情况下,若父类声明异常,那么子类只能声明异常或异常的子类,或是不声明
2.当父类声明多个异常的情况下,子类可以声明多个中的任意组合,包括不声明
3.当父类未被声明异常,那么子类也无法声明异常
继承与接口的问题:
接口和父类没有声明异常,但是因为子类遇到了异常,需要抛出并声明异常。
解决:
因为父类和接口不一定会有声明(throws)异常,那么只能捕获(try catch),如果发现这个事情解决不了。可以先尝试间接性处理,然后异常转换成RuntimeException或者其子类并抛出,让调用者解决。(因为父类没声明异常,子类也无法声明,但是RuntimeException是可以在省略声明或捕获的异常的类,所以可以这么进行异常转换)