Java学习笔记(十三)面向对象---异常

概述

对异常的理解

程序在运行过程当中出现不正常状况。是对问题的描述,将问题进行对象的封装。java

异常的由来

问题也是现实生活中一个具体的事物,也能够经过Java的类的形式进行描述,并封装成对象。数据库

对于问题的划分

一种是严重的问题,一种是非严重的问题。数组

  • 对于严重的:Java经过Error类进行描述。
    对于Error通常不编写针对性的代码对其进行处理。
  • 对于非严重的:Java经过Exception类进行描述。
    对于Exception可使用针对性的处理方式进行处理。
    不管Error仍是Exception都具备一些共性内容。
    好比:不正常状况的信息,引起缘由。jvm

    异常体系

Throwable
        |--Error
        |--Exception
            |--RuntimeException

异常体系的特色:
异常体系中的全部类以及被创建的对象都具有可抛性。ide

异常的处理

代码语句格式

try {
    须要被检测的代码
}
catch(异常类 变量) {
    处理异常的代码(处理方式)
}
finally {
    必定会执行的语句;
}

对异常的常见操做方法

String getMessage();
String toString();
void printStackTrace();函数

class Demo {
    int div(int x,int y) {
        return x/y;
    }
}
public class ExceptionDemo {
    public static void main(String[] args) {
        Demo d = new Demo();
        try {
            int z = d.div(1,0);
            System.out.println(z);
        }
        catch (Exception e) {  //Exception e = new ArithmeticExceptin();
            System.out.println(e.getMessage()); //  /by zero
            System.out.println(e.toString());   //  异常名称:异常信息
            e.printStackTrace();                //  异常名称:异常信息,异常出现的位置
            //(jvm默认的处理异常的机制就是在调用printStackTrace()方法)
        }
        System.out.println("over");
    }
}

运行结果this

/ by zero
java.lang.ArithmeticException: / by zero
java.lang.ArithmeticException: / by zero
    at Demo.div(ExceptionDemo.java:3)
    at ExceptionDemo.main(ExceptionDemo.java:10)
over

异常声明throws

  • throws关键字用来声明一个方法有可能会出现问题。
  • throws关键字能够将异常抛给调用者,能够层层向上抛,直到最后由Java虚拟机抛出。
    好比:
class Demo {
    int div(int x,int y) throws Exception {
        return x/y;
    }
}
public class ExceptionDemo1 {
    public static void main(String[] args) throws Exception {
        Demo d = new Demo();
        int y = d.div(1,0);
        System.out.println(y);
        System.out.println("over");
    }
}
  • 若是调用者对被调用方法抛出的异常不加处理会出现编译错误。
class Demo {
    int div(int x,int y) throws Exception {
        return x/y;
    }
}
public class ExceptionDemo2 {
    public static void main(String[] args) {
        Demo d = new Demo();
        int y = d.div(1,0);
        System.out.println(y);
        System.out.println("over");
    }
}

上述代码编译会提示:code

Error:(9, 22) java: 未报告的异常错误java.lang.Exception; 必须对其进行捕获或声明以便抛出

咱们对可能出现的异常加以处理:对象

class Demo {
    int div(int x,int y) throws Exception {
        return x/y;
    }
}
public class ExceptionDemo3 {
    public static void main(String[] args) {
        Demo d = new Demo();
        try {
            int y = d.div(1,0);
            System.out.println(y);
        }
        catch (Exception e) {
            System.out.println(e.toString());
        }
        System.out.println("over");
    }
}

运行结果:继承

java.lang.ArithmeticException: / by zero
over

对可能出现异常的div方法进行处理以后,程序能够正常编译运行。

多异常处理

1.声明异常时,声明为更为具体的异常,这样能够处理得更具体。
2.方法声明有几个异常,对应就有几个catch块。(不要定义多余的catch块)
若是多个catch块中的异常出现继承关系,父类异常catch块放在最下面。

class Demo {
    int div(int x,int y) throws ArithmeticException,ArrayIndexOutOfBoundsException {
        int[] arr = new int[x];
        System.out.println(arr[3]);
        return x/y;
    }
}
public class ExceptionDemo4 {
    public static void main(String[] args) {
        Demo d = new Demo();
        try {
            int y = d.div(2,0);
        }
        catch (ArithmeticException e) {
            System.out.println("被零除了");
        }
        catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("数组角标越界");
        }
    }
}

运行结果:

数组角标越界

上述代码中显然有两个一场出现,可是当方法中出现一个异常以后方法会中止运行,不会继续执行下去。

自定义异常

项目中会出现特有的问题,而这些问题并未被Java描述并封装对象。因此对这些特有的问题能够按照Java的对问题封装的思想,将特有的问题,进行自定义的异常封装。

需求:在本程序中,对于除数是负数,也视为是错误的。
当在函数内部出现了throw抛出异常对象,那么就必需要给对应的处理。
要么在内部使用try catch处理。
要么在函数上声明让调用者处理。

class FuShuException extends Exception {

}
class Demo {
    int div(int x,int y) throws FuShuException{
        if(y<0) {
            throw new FuShuException();//经过throw关键字手动抛出一个自定义异常对象
        }
        return x/y;
    }
}
public class ExceptionDemo5 {
    public static void main(String[] args) {
        Demo d = new Demo();
        try {
            int y = d.div(1,-1);
            System.out.println(y);
        }
        catch (FuShuException e) {
            System.out.println(e.toString());
            System.out.println("除数出现负数了");
        }
    }
}

运行结果

FuShuException
除数出现负数了

咱们能够发现以上的代码运行的结果中只有异常的名称,却没有异常的信息。由于咱们并未在自定义的异常中定义具体信息。

定义异常信息

由于父类中已经把异常信息的操做完成了。因此子类只要在构造时,将异常信息传递给父类经过super语句,就能够经过getMessage方法获取自定义的异常信息。

class FuShuException extends Exception {
    private int value;
    FuShuException(){
        super();
    }
    FuShuException(String message,int value) {
        super(message);
        this.value = value;
    }
    public int getValue() {
        return value;
    }
}
class Demo {
    int div(int x,int y) throws FuShuException{
        if(y<0) {
            throw new FuShuException("--被零除了--",y);//经过throw关键字手动抛出一个自定义异常对象
        }
        return x/y;
    }
}
public class ExceptionDemo5 {
    public static void main(String[] args) {
        Demo d = new Demo();
        try {
            int y = d.div(1,-1);
            System.out.println(y);
        }
        catch (FuShuException e) {
            System.out.println(e.toString());
            System.out.println("除数出现了负数:"+e.getValue());
        }
    }
}

运行结果:

FuShuException: --被零除了--
除数出现了负数:-1

注意

自定义异常必须是是自定义类继承Exception
异常体系中的异常类和异常对象都具有可抛性,这个可抛性是Throwable这个体系中独有的特色。只有这个体系中的类和对象才能够被throw和throws操做。

throw和throws的区别

  1. throws使用在函数上,throw使用在函数内。
  2. throws后面跟的是异常类,能够跟多个用逗号隔开。throw后跟的是异常对象。

RuntimeException

异常分两种

  1. 编译时被检测的异常。
  2. 编译时不被检测的异常(运行时的异常。RuntimeException以及其子类)

RuntimeException是Exception中的一个特殊的子类。
若是在函数内容中抛出异常,函数上能够不用声明。
若是在函数上声明了异常,调用者能够不用进行处理。

之因此不用在函数上声明是由于不须要让调用者处理,当该异常发生,程序但愿中止,对代码进行修正,而不是去让调用者处理。

自定义异常时,若是该异常发生,没法再继续进行运算,就让自定义异常继承RuntimeException。

class FuShuException extends RuntimeException{
    FuShuException(String message) {
        super(message);
    }
}
class Demo {
        int div(int x,int y) {  //函数上为声明异常也能够正常编译
            if (y < 0) {
                throw new FuShuException("--除数为负数--");//在函数内容中抛出异常
            }
            else if(y == 0){
                throw new ArithmeticException("--除数为零--");//在函数内容中抛出异常
            }
            return x/y;
        }
}
public class ExceptionDemo6 {
    public static void main(String[] args) {
        Demo d = new Demo();
        try {
            int y = d.div(1,-1);
        }
        catch (FuShuException e) {
            System.out.println(e.toString());
        }
        catch (ArithmeticException e) {
            System.out.println(e.toString());
        }
    }
}

finally

try {

}
catch () {

}
finally {

}

finally中存放的是必定会被执行(不管是否有异常)的代码,即便catch中有return语句。

finally只有一种状况不会被执行,当代码执行到System.exit(0);

例如:若是须要对数据库进行操做,不管有没有成功链接上数据库,在最后操做完成的时候,都须要断开数据库的链接,以释放有限的资源。

异常处理语句的另外一种格式

try {
    
}
finally {

}

异常在覆盖时的特色

  1. 子类在覆盖父类时,若是父类的方法抛出异常,那么子类的覆盖方法只能抛出父类的异常或者该异常的子类。子类程序在继承时不能抛出新的异常。
  2. 若是父类方法抛出多个异常,那么子类在覆盖方法时,只能抛出父类异常的子集。
  3. 若是父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不能够抛出异常若是子类方法发生了异常,就必需要进行try处理,不能够抛出。

异常的好处

  1. 将问题进行封装。
  2. 将正常流程代码和问题处理代码相分离,加强代码可读性。

    异常的处理原则

  3. 两种处理方式: try和throws
  4. 调用到抛出异常的功能时,抛出几个,就须要处理几个。一个try对应多个catch
  5. 多个catch须要将父类异常的catch放到最下面。
  6. catch内,须要定义针对性处理方式,不要简单地定义printStackTrace。
    • 当捕获到地异常,没法处理,能够继续在catch中抛出该没法处理的异常
    • 若是该异常处理不了,但并不属于该功能出现的异常,能够将该异常进行转换而后再抛出
    • 若是异常能够处理,但须要使抛出的异常和本功能相关,也能够对异常进行转换

异常练习

有圆形和长方形,均可以获取面积,对于面积,若是出现非法的数值,视为是获取面积出现问题。
出现的问题经过异常来表示。(使用异常能够,使问题处理代码和正常流程代码分开)

interface Shape {
    void getArea();
}
class InvaidValueException extends RuntimeException {//若是一个传入一个图形的参数有错误,咱们没法对其进行有效的处理,只抛出异常便可,因此继承RuntimeException
    InvaidValueException(String message) {
        super(message);
    }
}
class Rec implements Shape {
    private double len,wid;
    Rec(double len,double wid) {
        if(len <= 0 || wid <= 0)
                throw new InvaidValueException("非法值");
        this.len = len;
        this.wid = wid;
    }
    @Override
    public void getArea() {
        System.out.println(wid*len);
    }
}

class Circle implements Shape {
    private double r;
    public static final double PI = 3.14;
    Circle(double r)  {
        if(r <= 0)
            throw new InvaidValueException("非法值");
        this.r = r;
    }
    @Override
    public void getArea() {
        System.out.println(r*r*PI);
    }
}
public class ExceptionDemo7 {
    public static void main(String[] args) {
        Rec R = new Rec(1,2);
        R.getArea();
        Circle C = new Circle(-1);
        C.getArea();
        System.out.println("over");
    }
}

上述程序的运行结果为:

2.0
Exception in thread "main" InvaidValueException: 非法值
    at Circle.<init>(ExceptionDemo7.java:28)
    at ExceptionDemo7.main(ExceptionDemo7.java:41)
相关文章
相关标签/搜索