java中异常类

异常

异常体系继承结构

 Throwable类是 Java 语言中所有错误或异常的超类,只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java throw 语句抛出。
    异常是对象,而对象都采用类来定义。异常的根类是 java.lang.Throwable。关系图如下:

    注意:类名 Error、Exception 和 RuntimeException 有时候容易引起混淆。这三种类都是异常,这里讨论的错误都发生在运行时。
    Throwable 类是所有异常类的根。所有的 Java 异常类都直接或者间接地继承自Throwable。可以通过继承 Exception 或者 Exception 的子类来创建自己的异常类。
    这些异常类可以分为三种主要类型:系统错误、编译时异常和运行时异常。

  • Exception :程序本身可以处理的异常,可以通过 catch 来进行捕获。Exception 又可以分为 Checked Exception (受检查异常,必须处理) 和 Unchecked Exception (不受检查异常,可以不处理)。
  • ErrorError 属于程序无法处理的错误 ,我们没办法通过 catch 来进行捕获不建议通过catch捕获 。例如 Java 虚拟机运行错误(Virtual MachineError)、虚拟机内存不够错误(OutOfMemoryError)、类定义错误(NoClassDefFoundError)等 。这些异常发生时,Java 虚拟机(JVM)一般会选择线程终止

1.系统错误(Error)

  • 系统錯误(system error) 是由 Java 虚拟机抛出的,用 Error 类表示。Error 类描述的是内部系统错误。这样的错误很少发生。如果发生,除了通知用户以及尽量稳妥地终止程序外,几乎什么也不能做。

OutOfMemoryError :内存耗尽 ;
NoClassDefFoundError :无法加载某个Class ;
StackOverflowError :栈溢出。

2.编译时异常(Exception)

  • 编译时异常:Exception及其子类(除了RuntimeException),在编译时期抛出的异常,在编译期间检查程序是否可能会出现问题,如果可能会有,则预先防范:捕获 声明。

Exception 则是编译时异常,它可以被捕获并处理。
某些异常是应用程序逻辑处理的一部分,应该捕获并处理。例如:

NumberFormatException :数值类型的格式错误;
FileNotFoundException :未找到文件;
SocketException :读取网络失败。
还有一些异常是程序逻辑编写不对造成的,应该修复程序本身。例如:

NullPointerException :对某个 null 的对象调用方法或字段;
IndexOutOfBoundsException :数组索引越界。

3.运行时异常(RuntimeException)


运行时异常(runtime exception) 是用 RuntimeException 类表示的,它描述的是程序设计错误,例如,错误的类型转换、访问一个越界数组或数值错误。运行时异常通常是由 Java 虚拟机抛出的。
RuntimeException是那些可能在 Java 虚拟机正常运行期间抛出的异常的超类,可能在执行方法期间抛出但未被捕获的 RuntimeException 的任何子类都无需在 throws 子句中进行声明,指的就是这些问题不需要提前被预防(本质上也可以的,只不过没必要),因为只有在真正运行的时候才能发现是否发生问题,一旦在运行期间发生了问题,则一般不会修正,程序直接中断

Checked Exception 和 Unchecked Exception 有什么区别?

Checked Exception 即 受检查异常 ,Java 代码在编译过程中,如果受检查异常没有被 catch或者throws 关键字处理的话,就没办法通过编译。

比如下面这段 IO 操作的代码:

 

除了RuntimeException及其子类以外,其他的Exception类及其子类都属于受检查异常 。常见的受检查异常有:IO 相关的异常、ClassNotFoundExceptionSQLException...。

Unchecked Exception不受检查异常 ,Java 代码在编译过程中 ,我们即使不处理不受检查异常也可以正常通过编译。

RuntimeException 及其子类都统称为非受检查异常,常见的有(建议记下来,日常开发中会经常用到):

  • NullPointerException(空指针错误)
  • IllegalArgumentException(参数错误比如方法入参类型错误)
  • NumberFormatException(字符串转换为数字格式错误,IllegalArgumentException的子类)
  • ArrayIndexOutOfBoundsException(数组越界错误)
  • ClassCastException(类型转换错误)
  • ArithmeticException(算术错误)
  • SecurityException (安全错误比如权限不够)
  • UnsupportedOperationException(不支持的操作错误比如重复创建同一用户)

什么异常可以不处理,什么异常一定要处理

 RuntimeException、Error 以及它们的子类都称为免检异(unchecked exception )。所有其他异常(编译时异常)都称为必检异常(checked exception), 意思是指编译器会强制程序员检査并通过 try- catch 块处理它们,或者在方法头进行声明。

    在大多数情况下,免检异常都会反映出程序设计上不可恢复的逻辑错误。例如,如果通过一个引用变量访问一个对象之前并未将一个对象陚值给它,就会抛出 NullPointerException异常;如果访问一个数组的越界元素,就会抛出IndexOutOfBoundsException 异常。这些都是程序中必须纠正的逻辑错误。免检异常可能在程序的任何一个地方出现。为避免过多地使用 try-catch 块,Java 语言不强制要求编写代码捕获或声明免检异常。

Java规定:

必须捕获的异常,包括 Exception 及其子类,但不包括 RuntimeException 及其子类,这种类型的异常称为Checked Exception。
不需要捕获的异常,包括 Error 及其子类, RuntimeException 及其子类。

处理异常方式

2.1 JVM默认处理异常的方式

这种方式就是我们直接一直向上抛出之后最后就是jvm进行处理。
如果程序出现了问题,我们没有做任何处理,最终JVM 会做默认的处理,处理方式有如下两个步骤:
把异常的名称,错误原因及异常出现的位置等信息输出在了控制台
程序停止执行


2.2 try - catch方式处理异常 

  • 定义格式


try {
    可能出现异常的代码; 
} catch(异常类名 变量名) {
     异常的处理代码; 
}


 

  • 执行流程

  1. 程序从 try 里面的代码开始执行
  2. 出现异常,就会跳转到对应的 catch 里面去执行
  3. 执行完毕之后,程序还可以继续往下执行
  • 示例代码

 public class ExceptionDemo01 { 
    public static void main(String[] args) { 
        System.out.println("开始"); method(); 
        System.out.println("结束"); 
    }
    public static void method() { 
        try {
            int[] arr = {1, 2, 3}; 
            System.out.println(arr[3]); 
            System.out.println("这里能够访问到吗"); 
        } catch (ArrayIndexOutOfBoundsException e) { 
            // System.out.println("你访问的数组索引不存在,请回去修改为正确的索引"); 
            e.printStackTrace(); 
        } 
    } 
}

 这种方式处理异常就是直接就在本方法中进行处理,不交给其他调用者进行处理。

 2.3 throws方式处理异常

  • 格式

public void 方法() throws 异常类名 { 

}
 

这种方式处理异常方式就是我自己不处理,交给调用者进行处理,调用者如何处理呢,还是两种方式try catch 或者继续向上抛出交给其他调用者处理,如果一直抛的话,最后就是jvm最后进行处理(默认处理)。

  • 示例代码

/*
    throws 异常类名;
    这个格式是跟在方法的括号后面的
 */
public class ExceptionDemo {
    public static void main(String[] args) {
        System.out.println("开始");
//        method();
        try {
            method2();
        }catch (ParseException e) {
            e.printStackTrace();
        }
        System.out.println("结束");
    }

    //编译时异常
    public static void method2() throws ParseException {
        String s = "2048-08-09";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date d = sdf.parse(s);
        System.out.println(d);
    }

    //运行时异常
    public static void method() throws ArrayIndexOutOfBoundsException {
        int[] arr = {1, 2, 3};
        System.out.println(arr[3]);
    }

}
 

为什么要抛出异常?什么时候要抛出异常?

 为什么要捕获异常?

编译时程序有可能会出现异常,如果出现异常,程序就会中断,但是你不想程序中断的话,就可以选择
捕获异常,做出处理,让程序可以运行下去。
例子:比如程序中有3行代码,第2行有异常。

如果不处理第1行代码的异常,那么第3行代码就执行不了;
如果处理的第2行代码的异常后,程序就可以继续执行第3行代码。

抛出异常和捕获异常的区别?


抛出异常:如果程序出现了异常,没有办法将具体的异常打印出来,不做任何处理;程序中断。 

捕获异常:如果程序出现了异常,就能够详细的打印是什么原因导致了异常并且能够做出相应的处理,能够显示详细的日志,程序不中断。

编译异常和运行异常的区别?什么时候要抛出异常? 


编译时异常必须要进行处理,两种处理方案:try…catch …或者 throws,如果采用throws 这种方案, 将来谁调用谁处理 ,处理用到try…catch…捕获或者抛出一层层往上抛,最终抛给虚拟机
运行时异常可以不处理,出现问题后,需要我们回来修改代码

throw和throws的区别

throws

  • 用在方法声明后面,跟的是异常类名
  • 表示抛出异常,由该方法的调用者来处理
  • 表示出现异常的一种可能性,并不一定会发生这些异常

throw

  • 用在方法体内,跟的是异常对象名
  • 表示抛出异常,由方法体内的语句处理
  • 执行 throw 一定抛出了某种异常

throw就是主动抛出一个异常 , 要很确信这个代码一定会发生异常,我们才会直接主动抛出去,用在方法体中。对于throws用在方法上 这是这个方法可能会抛出异常,也可能不会抛出异常,如果抛出了异常则交给我们调用者进行处理。

总结:

  1. throw 是语句抛出一个异常;throws 是方法抛出一个异常;
  2. throw语法:throw <异常对象>
  3. throws语法:[<修饰符>]<返回值类型><方法名>([<参数列表>])[throws<异常类>]

public class ThrowTest {
    public static void main(String[] args) {
        try {
            // 调用声明抛出 Checked 异常的方法,要么显式捕获该异常
            // 要么在 main 方法中再次声明抛出
            throwChecked(-3);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        // 调用声明抛出 Runtime 异常的方法既可以显式捕获该异常
        // 也可不理会该异常
        throwRuntime(3);
    }
    
    public static void throwChecked(int a) throws Exception{
        if (a > 0){
            //自行抛出 Exception 异常
            //该代码必须处于 try 块里,或处于带 throws 声明的方法中
            throw new Exception("a 的值大于 0,不符合要求");
        }
    }
    
    public static void throwRuntime(int a){
        if( a > 0) {
            // 自行抛出 RuntimeException 异常,既可以显式捕获该异常
            // 也可完全不理会该异常,把该异常交给该方法调用者处理
            throw new RuntimeException("a 的值大于 0,不符合要求");
        }
    }
}
 

throw使用限制

try 块里,或处于带 throws 声明的方法中

throw 必须是直接实现或者间接继承hrowable类的子类的对象

实现自定义异常类

1、自定义异常类继承Exception类

/**
 * 自定义异常类
 */
public class MyException extends Exception {
    //异常信息
    private String message;

    //构造函数
    public MyException(String message){
        super(message);
        this.message = message;
    }

    //获取异常信息,由于构造函数调用了super(message),不用重写此方法
    //public String getMessage(){
    //    return message;
    //}
}
 

2、在要抛出异常的函数使用throws关键字

/**
 * 在需要抛出异常的地方使用异常类
 */
public class UseMyException {
    private String name;
    private String password;

    public UseMyException(String name,String password){
        this.name = name;
        this.password = password;
    }

    public void throwException(String password) throws MyException{
        if (!this.password.equals(password)){
            throw new MyException("密码不正确!");
        }
    }
}
 

3、测试,使用try-catch处理异常

/**
 * 测试异常
 */
public class TestException {

    @org.junit.Test
    public void test(){
        UseMyException ex = new UseMyException("admin","123");
        try{
            ex.throwException("1234");
        }catch (MyException me){
            System.out.println("MyException:"+me.getMessage());
        }
    }
}

  • 9
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值