java学习(三)-异常机制

异常
  • 什么是异常:

    • 程序运行过程中出现的错误
  • 异常总览:
    在这里插入图片描述

  • Throwable:

    • java语言中所有异常或错误的超类
    • 两个子类:
      • Error:错误类:是指在程序中了严重问题,不改代码,运行不了
      • Exception:异常类:程序一般问题,可以通过处理规避掉
  • 常见的Exception:

    • NullPointerException:空指针异常
    • IndexOutOfBoundsException:越界异常
    • ClassCastException:类型转换错误
    • RuntimeException:运行期错误
    • ConcurrentModificationException:并发修改异常
  • 常见的Error:

    • OutOfMemoryError:内存超限:比如:int[] a = new int[1000000000];

Throwable详解:
  • java语言中所有异常或错误的超类
  • 所有继承自Throwable的子类(java自带),都默认使用Throwable的方法(子类基本不实现)
  • 其包括如下方法:
方法描述
public Throwable()默认构造函数
public Throwable(String message)指定消息构造函数,后面该message,可通过getMessage获取
public Throwable(String message,Throwable cause)可以由message+旧的Throwable对象,构造新的Throwable
public Throwable(Throwable cause)由老的构造,生成新的Throwable
public String getMessage()获取message(简易的)
public String getLocalizedMessage()创建本地化描述,如果不做任何子类实现,其等于getMessage
public Throwable getCause()返回cause
public Throwable initCause(Throwable cause)初始化cause,只能初始化一次
public String toString()详细描述(jdk文档说是简单描述)
public void printStackTrace()将throwable及其追踪输出至标准输出流
public void printStackTrace(PrintStream s)将此 throwable 及其追踪输出到指定的输出流。
public void printStackTrace(PrintWriter s)将此 throwable 及其追踪输出到指定的 PrintWriter。

JVM对异常的处理:
  • 示例,比如除0异常:
public class Test4 {
    public static void main(String[] args) {
        int a = 1 / 0;
    }
}
  • 输出:
// 异常的类,以及原因
Exception in thread "main" java.lang.ArithmeticException: / by zero
//出现异常的位置(行)
    at Test3.testZero(Test3.java:27)  
  • 说明:
    • 异常也是对象(万物皆对象),JVM发现发生了“除法的除0异常”,将异常封装为java.lang.ArithmeticException:new ArithmeticException(“/ by zero")
    • 异常向外抛出,抛到main方法的调用者,即:JVM,此时JVM停止程序,并将异常打印到控制台

异常的详细程度:
  • e.printStackTrace() > e.toString() > e.getMessage()
public class Test4 {
    public static void main(String[] args) {
        try {
            div(1, 0);
        } catch (Exception e) {
            System.out.println("==================== e.getMessage:简要 ====================");
            System.out.println(e.getMessage());
            System.out.println("==================== e.toString:较详细 ====================");
            System.out.println(e.toString());
            System.out.println("==================== e.getMessage:非常详细 ====================");
            e.printStackTrace();
        }
    }

    private static int div(int a, int b){
        return a / b;
    }
}
  • 输出:
==================== e.getMessage:简要 ====================
/ by zero
==================== e.toString:较详细 ====================
java.lang.ArithmeticException: / by zero
==================== e.getMessage:非常详细 ====================
java.lang.ArithmeticException: / by zero
    at Test4.div(Test4.java:16)
    at Test4.main(Test4.java:4)

异常的继承:
  • 一般继承如下:并且,基本都使用RuntimeException
/**
 * 一般继承时,都覆写空构造器、以及带有message的构造器
 */
class YRuntimeException extends RuntimeException {
    public YRuntimeException() {
        super();
    }

    public YRuntimeException(String message) {
        super(message);
    }
}


异常的捕获:
  • 多个异常:
private void testExp() {
    // 方式1:
    try {
        method();
    } catch (NullPointerException | ArithmeticException e) {
        System.out.println(e.toString());
    }
    // 方式2:
    try {
        method();
    } catch (ArithmeticException e) {
        System.out.println(e.toString());
    } catch (NullPointerException e) {
        System.out.println(e.toString());
    }
}
  • 如果多个异常,并且这些异常有父子关系,则父类需要写到最后,否则编译失败
class ExceptionParent extends Exception {
}

class ExceptionSon extends  ExceptionParent {
}

class TestException {
    public static void main(String[] args) {
        try {
            throw new ExceptionParent();
        } catch (ExceptionParent e) {
            // 这样写,编译器会报错,因为parent异常已经可以捕获了
        } catch (ExceptionSon e) {

        }
    }
}

Error的捕获
  • 因为Error的Exception是两个不同的实现类,故捕获的方式不一样:
class TestY {
    public static void main(String[] args) {
        try {
            int[] a = new int[1000000000];
            // 这里会报OutOfMemoryError,只能用Error或者Throwable捕获
        } catch (Error e) {
            System.out.println("捕获到异常了");
            System.out.println(e.toString());
        }
    }
}

异常抛出:
  • throw:方法内部,手动抛出异常
  • throws:方法上,声明本方法抛出的异常类型,调用此方法的必须进行处理
  • 运行时异常:RuntimeException或者其子类:
    • 特点:运行时异常,方法上不需要throws声明,调用者也不需要处理
class XException extends Exception {
}
class YRuntimeException extends RuntimeException {
}

class TestE {
    // 只需要抛出XEception即可,RuntimeException及其子类不需要抛出
    public void show(int a) throws XException{
        if (a == 0) {
            throw new XException();
        } else {
            throw new YRuntimeException();
        }
    }
}

finally
  • finally中代码快一定会执行,格式:
    • try catch finally
    • try finally
  • 正常场景:try catch finally都有返回
class TestFinally1 {
    public static void main(String[] args) {
        System.out.println(show());  // 输出为3
    }

    private static int show() {
        try {
            return 1;
        } catch (Exception e) {
            return 2;
        } finally {
            return 3;   // finally最终返回的是3
        }
    }
}
* 过程分析:执行到return 1;时,jvm先预留,不直接返回。等到finlly执行完成后,再返回。此时发现finally里有返回,则按照finally返回,故输出为3.
  • 正常场景:finally无返回:
class TestFinally1 {
    public static void main(String[] args) {
        System.out.println(show1());   // 返回为1
    }

    private static int show1() {
        try {
            return 1;              // 最后返回这里
        } catch (Exception e) {
            return 2;
        } finally {
            System.out.println("no return);   // 首先,会打印这里
        }
    }
}

输出:

no return
1
  • 异常场景:无finally,最终按照catch中返回
private static int showException() {
    try {
        int a = 1 / 0;
        return 1;
    } catch (Exception e) {
        return 2;              // 最终方法返回的是这里
    } 
}
  • 异常场景:有finally:则按照finally中返回
private static int showException() {
    try {
        int a = 1 / 0;
        return 1;
    } catch (Exception e) {
        return 2;
    } finally {
        return 3;           // 最终返回的是这里:3
    }
}

注意:这里逻辑比较绕,但最好不要在finally中写return

继承关系中方法的异常处理:
  • 父类方法没有异常,则子类继承的方法也不能有:
class A {
    public void show() {
    }
}

class B extends A {
    // 正确写法:
    @Override
    public void show() {
    }
    // 错误写法:
//    @Override
//    public void show() throws ExceptionSon{
//    }
}
  • 父类方法有异常,则子类:
    • 可以不写
    • 或者声明为该异常的子类(异常的父类会报错)
class AException extends Exception {
}

class BException extends AException {
}

class A {
    public void show() throws AException{
    }
}

class B extends A {
    // 正确写法1:不抛异常
//    @Override
//    public void show() {
//    }
    // 正确写法2:抛出为父类异常的子类
    @Override
    public void show() throws BException{
    }
    // 错误写法:抛出的异常比父类要高
//    @Override
//    public void show() throws Exception{
//    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值