Java异常

一、异常概念

在Java中,将程序执行过程中发生的不正常行为称为异常。

java当中描述异常,是根据类来进行描述的,不同的类代表不同的异常

public class test {
    public static void main(String[] args) {
        System.out.println(10/0);//算数异常

        int[] array = null;
        System.out.println(array.length);//空指针异常
    }
}

Error(错误)和Exception(异常)继承了throwable(最顶层)这个类

Error错误是Java虚拟机无法解决的严重问题,例如:JVM的内部错误,栈溢出错误导致的资源耗尽等

Exception分两个大类,分为运行时异常或非受查异常和编译时异常或受查异常

注意语法错误不算是异常

运行时异常是在程序运行起来后报错,例如算数异常,空指针异常

编译时异常就是程序编译的时候就报错,比如实现克隆对象,重写后仍然报错

实现Cloneable接口和声明throws CloneNotSupportedException异常后,则可以编译成功

class Person implements Cloneable{
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class test {
    public static void main(String[] args) throws CloneNotSupportedException{
        Person person = new Person();
        Person person1 = (Person)person.clone();
    }
}

二、异常的处理

先操作,遇到问题再解决,即:事后认错型

有五个关键字:throw,  try,  catch,  final,  throws

要达到处理异常前提要抛出异常

1、抛出异常

1、程序本身触发异常,例如输出10/0,触发了算数异常

2、手动抛出异常,使用throw

异常都是一个类,因此需要new

throw new xxxException("异常产生的原因")

 例如:手动抛出空指针异常

public class test2 {
    public static void func(int[] array){
        if(array==null){
            throw new RuntimeException();
        }
    }
    public static void main(String[] args) {
        int[] array = null;
        func(array);
    }
}

异常由JVM处理,退出code是1,因此程序不是正常结束的

点开 RuntimeException,发现它是继承Exception这个类的

还可以传参数打印

还可以写成NullPointerException

 

空指针异常继承了运行时异常,因此只要继承RuntimeException就都是运行时异常

只要是继承Exception就是编译异常,除了RuntimeException本身

注意:1. throw必须写在方法体内部

2. 抛出的对象必须是Exception或者Exception的子类对象

3. 如果抛出的是RunTimeException或者RunTimeException的子类,则可以不用处理,直接交给JVM来处理

4. 如果抛出的是编译时异常,用户必须处理,否则无法通过编译

5. 异常一旦抛出,其后的代码就不会执行

抛出异常

public class test2 {
    public static void func(int[] array) throws Exception{//声明异常
        if(array==null){
            throw new Exception("传参数"+array);//抛出异常
        }
    }
    public static void main(String[] args) throws Exception{//声明异常,将异常给到JVM
        int[] array = null;
        func(array);
    }
}

2、通过try catch处理异常

public class test {
    public static void func(int[] array) {
        if(array==null){
            throw new NullPointerException("传参数"+array);
        }
    }
    public static void main(String[] args) {
        try{
            int[] array = null;
            func(array);
        }catch(NullPointerException e){
            System.out.println("捕获到异常,可以开始处理");
            e.printStackTrace();
        }
        System.out.println("异常处理完,程序继续执行");
    }
}

 1. try块内抛出异常位置之后的代码将不会被执行

2. 如果抛出异常类型与catch时异常类型不匹配,即异常不会被成功捕获,也就不会被处理,继续往外抛,直到 JVM收到后中断程序----异常是按照类型来捕获的

3. try中可能会抛出多个不同的异常对象,则必须用多个catch来捕获----即多种异常,多次捕获,并且catch后最好写具体触发的异常

如果异常之间具有父子关系,一定是子类异常在前catch,父类异常在后catch,否则语法错误

由于 Exception 类是所有异常类的父类. 因此可以用这个类型表示捕捉所有异常,用于保底,写最后

3、finally

在写程序时,有些特定的代码,不论程序是否发生异常,都需要执行,比如程序中打开的资源:网络连接、数据库 连接、IO流等,在程序正常或者异常退出时,必须要对资源进进行回收。另外,因为异常会引发程序的跳转,可能导致有些语句执行不到,finally就是用来解决这个问题的。

public class test {
    public static void func(int[] array) {
        if(array==null){
            throw new NullPointerException("传参数"+array);
        }
    }
    public static void main(String[] args) {
        try{
            int[] array = null;
            func(array);
        }catch(NullPointerException e){
            System.out.println("捕获到异常,可以开始处理");
            e.printStackTrace();
        }finally {
            System.out.println("finally执行了");
        }
    }
}

不管是否发生异常,finally一定会被执行,善后,一般用来释放资源

public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        try{
            int a = scanner.nextInt();
            System.out.println(a/0);
        }catch(ArithmeticException e){
            e.printStackTrace();
            System.out.println("处理异常");
        }finally{
            System.out.println("finally执行了");
            scanner.close();//关闭资源
        }
    }

看下列代码,返回值是什么 

    public static int func(int a){
        try{
            int ret = a/10;
            return ret;
        }catch(NullPointerException e){
            System.out.println("NullPointerException");
        }finally{
            return 99;
        }
    }

 

发现结果是finally返回的值,因此尽量避免在finally写返回值

 public static int getData(){
            Scanner sc = null;
            try{
                sc = new Scanner(System.in);
                int data = sc.nextInt();
                return data;
            }catch (InputMismatchException e){
                e.printStackTrace();
            }finally {
                System.out.println("finally中代码");
            }
            System.out.println("try-catch-finally之后代码");
            if(null != sc){
                sc.close();
            }
            return 0;
        }
        public static void main(String[] args) {
            int data = getData();
            System.out.println(data);
        }

上述程序,如果正常输入,成功接收输入后程序就返回了,try-catch-finally之后的代码根本就没有执行,即输入流就没有被释放,造成资源泄漏。

 public static void func() {
        int[] arr = {1, 2, 3};
        System.out.println(arr[100]);
    }
    public static void main(String[] args) {
        try {
            func();
        } catch (ArrayIndexOutOfBoundsException e) {
            e.printStackTrace();
        }
        System.out.println("after try catch");
    }

数组越界,未在func里处理异常,就向上传递找到合适的方法处理,此题目就是main调用func,main就来处理,如果main也处理不了,就交给JVM处理,程序就会异常终止

4、总结异常处理流程

程序先执行 try 中的代码

如果 try 中的代码出现异常, 就会结束 try 中的代码, 看和 catch 中的异常类型是否匹配.

如果找到匹配的异常类型, 就会执行 catch 中的代码 如果没有找到匹配的异常类型, 就会将异常向上传递到上层调用者.

无论是否找到匹配的异常类型, finally 中的代码都会被执行到(在该方法结束之前执行).

如果上层调用者也没有处理的了异常, 就继续向上传递.

一直到 main 方法也没有合适的代码处理异常, 就会交给 JVM 来进行处理, 此时程序就会异常终止.

三、自定义异常类

Java 中虽然已经内置了丰富的异常类, 但是并不能完全表示实际开发中所遇到的一些异常,此时就需要维护符合我 们实际情况的异常结构.

创建异常类,需要继承,如果是继承Exception,那么这个异常类就是编译时异常也叫受查异常

如果继承的是RunTimeException,则是运行时异常又叫非受查异常

public class UserNameException extends RuntimeException{
//实现两个构造方法
    public UserNameException(){

    }
    public UserNameException(String msg){
        super(msg);
    }
}
public class Login {
    private String userName = "admin";

    public  void loginInfo(String userName) throws UserNameException{
        if (!this.userName.equals(userName)) {
            throw new UserNameException("用户名错误!");
        }
        System.out.println("输入正确");
    }

    public static void main(String[] args) {
        Login login = new Login();
        try {
            login.loginInfo("a");
        } catch (UserNameException e) {
            e.printStackTrace();
        }finally{
            System.out.println("finally执行了");
        }
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值