Java异常、try-catch、自定义异常

 一、异常

1、异常的概念:   

 异常指的是不正常, 指的是程序中出现了某些问题。

    在Java中,所有的问题都可以使用一个类来表示,这个类叫做Throwable。

    Throwable是Java中所有异常和错误的父类。

    Throwable

        |-- Error: 表示错误。 指的是不可挽回的严重问题。 相当于人得了绝症。

        |-- Exception:表示异常, 指的是可以挽回的轻微问题。 相当于人得了感冒,咳嗽。

2、异常产生的过程

 

public class Demo02Exception {

    public static void main(String[] args) {

        //定义一个数组

        int[] arr = new int[2];

        //调用getValue方法,获取数组中索引为10的元素

        int value = getValue(arr);

        System.out.println("value:" + value);

    }

 

    /*

        定义方法,用来获取数组中某个索引上的元素

     */

    public static int getValue(int[] arr) {

        int value = arr[10]; //JVM会自动创建一个异常对象,然后自动抛出.

        return value;

    }

}

3、throw 关键字

 

    如果想要手动的创建一个异常并且手动的抛出去,那么我们就可以使用throw关键字。

 

    格式:

        throw new 异常类名();

 

    注意:

        如果在某个方法内抛出异常,那么这个方法剩下的代码就都不会执行。

 

public class Demo03Throw {

    public static void main(String[] args) {

        //创建数组

        int[] arr = new int[2];

 

        int value = getValue(arr, 10);

 

        System.out.println("value:" + value);

    }

 

    /*

        定义方法,获取数组中指定索引的数据

     */

    public static int getValue(int[] arr, int index) {

        //在JVM自动抛出异常之前,我们对索引的取值范围进行检测, 如果索引的取值范围不合法,那么我们就手动抛出一个异常

        //索引的取值范围是: 0 ~ arr.length-1

        if(index < 0 || index > arr.length - 1) {

            //如果索引的取值范围不合法,那么我们就手动创建一个ArrayIndexOutOfBoundsException,并且手动抛出。

            //如果想要创建异常对象的使用给这个异常带上异常信息,那么可以在异常的构造方法位置传递异常信息

            String msg = "索引的取值范围必须是0到" + (arr.length - 1) + ", 您给的索引为:" + index;

            throw new ArrayIndexOutOfBoundsException(msg);

        }

        System.out.println("你好");

        return arr[index];

    }

}

 

4、Objects中的requireNonNull

    通过null去调用任何的属性和方法都会引发空指针异常

 

public class Demo04Exception {

    public static void main(String[] args) {

        //定义一个Object

        Object obj = null;

 

        //调用toString方法之前判断,如果obj是null,那么手动抛出一个异常

        /*

        if (obj == null) {

            throw new NullPointerException();

        }

        */

        Objects.requireNonNull(obj, "程序出现了空指针");

 

        obj.toString();//当代码执行到这一行,JVM会发现通过null调用了方法,那么此时JVM就会自动创建一个异常对象并抛出.

 

 

    }

}

 

5、throw: 手动的抛出一个异常。

    throws: 进行异常声明, 声明方法有可能会抛出异常。

 

    格式:

        修饰符 返回值类型 方法名(参数列表) throws 异常类名{

 

        }

 

    注意:

        1. 如果在一个方法内抛出了编译时异常,那么一定要进行异常的声明

        2. 如果调用了使用throws声明异常的方法,那么作为调用者要么处理异常(try..catch),要么也使用throws声明这个方法会抛出异常

        3. 当一个方法内抛出了运行时异常,可以使用throws进行异常声明,也可以不声明。

        4. 在一个方法内如果可能抛出多个异常,那么可以使用throws声明这些异常,也可以直接声明这些异常的父类异常。

 

public class Demo05Throws {

    public static void main(String[] args) throws IOException{

        method1();

    }

 

    public static void method1() throws IOException{

        throw new IOException();

    }

 

    public static void method2() {

        throw new NullPointerException();

    }

 

    public static void method3() throws Exception{

        int i = 0;

        if(i % 2 == 0) {

            throw new IOException();

        } else {

            throw new ClassNotFoundException();

        }

    }

}

 

6、

    如果代码出现异常之后不希望把这个异常往外,那么我们可以使用try...catch处理解决这个异常。

    格式:

        try {

            可能会出现异常的代码;

        } catch(要捕获的异常类名 变量名) {

            出现异常后执行的代码。

        }

    执行流程:

        如果try中代码没有问题,那么执行完try之后,会跳过catch继续往下执行。

        如果try中的代码有问题,并且catch捕获到了这个异常,那么就会直接进入到catch中执行。

        如果try中的代码有问题,但是catch没有捕获到这个异常,那么这个异常会依旧往外抛。

    异常处理有两种方式:

        1. 往外抛(甩锅): throw throws

        2. 解决问题: try...catch

 

 

public class Demo06TryCatch {

    public static void main(String[] args) {

        try {

            Object obj = null;

            obj.toString();

            System.out.println("1. try...end");

        } catch (ArrayIndexOutOfBoundsException e) {

            System.out.println("2. catch代码...");

        }

        System.out.println("3. main...end");

    }

}

7、try...catch...finally

    格式:

        try {

            【A】可能出现异常的代码

        } catch(要捕获的异常类 变量名) {

            【B】出现异常后执行的代码

        } finally {

            【C】一定会执行的代码

        }

 

    finally 代码块无论如何都会执行。

 

    执行流程:

        如果try中的代码没有出现问题,那么执行流程为: 【A】【C】

        如果try中的代码有问题,并且catch捕获到了,执行流程为: 【A】【B】【C】

        如果try中的代码有问题,但是catch没有捕获到, 执行流程为: 【A】【C】 抛出异常

 

    finally 代码块的作用一般用于释放资源。 比如后期IO流释放资源,JDBC释放连接等等。

 

 

public class Demo07TryCatchFinally {

    public static void main(String[] args) {

        try {

            System.out.println("1. try...start");

            Object obj = null;

            obj.toString();

            System.out.println("2. try...end");

        } catch (ArrayIndexOutOfBoundsException e) {

            System.out.println("3. catch");

        } finally {

            System.out.println("4. finally");

        }

    }

}

 

8、如果在方法内抛出了运行时异常,那么我们可以处理,也可以不处理。 如果不处理假如代码运行到这里,这个异常依旧会抛给调用者

    如果在方法内抛出了编译时异常,那么必须要处理。 要么try...catch解决掉问题。 要么使用throws声明这个方法会抛出异常。

 

    总结:

        运行时异常可以处理,也可以不处理。 编译时异常必须处理。

 

 

public class Demo08Exception {

    public static void main(String[] args) {

        method1();

    }

 

    public static void method1() {

        throw new RuntimeException();

    }

 

    public static void method2() {

        try {

            throw new Exception();

        } catch (Exception e) {

 

        }

    }

 

}

 

 

9、在try...catch处理异常时,可以写多个catch去捕获多个异常。

    try {

        可能会出现问题的代码

    } catch(要捕获的异常 变量名) {

        出现异常执行的代码;

    } catch(要捕获的异常 变量名) {

        出现异常执行的代码;

    } catch(要捕获的异常 变量名) {

        出现异常执行的代码;

    }

 

    如果try中的代码出现了问题,哪个catch先捕获到,那么就执行哪个catch中的代码。 剩下的catch都不在执行了

 

    注意:

        如果有多个catch,那么捕获的父类异常不能写在子类异常的前面

 

 

public class Demo09TryCatchCatch {

    public static void main(String[] args) {

        try {

            Object obj = null;

            obj.toString();

            System.out.println("1. try");

        } catch (ArrayIndexOutOfBoundsException e) {

            System.out.println("2. ArrayIndexOutOfBoundsException");

        } catch (NullPointerException e) {

            System.out.println("3. NullPointerException");

        } catch (ClassCastException e) {

            System.out.println("4. ClassCastException");

        } catch (Exception e) {

            System.out.println("5. Exception");

        }

 

    }

}

 

10、finally关键字

 

public class Demo10TryCatchFinally {

    public static void main(String[] args) {

        int value = method();

        System.out.println("value:" + value);

    }

 

 

    /*

        1. 当执行到try中的return的时候,会先把要返回的值给保存起来,留作以后返回结果的时候使用。  要返回的结果是10

        2. 因为后面有finally代码块,所以并不能直接返回,必须先要执行完finally代码块才能返回。 此时去执行finally

        3. 执行finally的时候把i的值变成了20.

        4. 执行完finally之后,再返回结果,返回的是之前已经保存好的10

     */

    public static int method() {

        int i = 10;

        try {

            return i;//10

        } catch (Exception e) {

            System.out.println("catch");

        } finally {

            i = 20;

            System.out.println("finally....");

        }

        return 0;

 

    }

 

}

 

 

11、Throwable中的常用方法:

 

        String toString(): 返回异常信息的详细描述

        String getMessage():  返回异常信息的简短描述

        void printStackTrace():将异常信息打印到控制台。 (最详细)

 

    上面这些方法不是用来创建对象后直接调用的, 这些方法要用在catch中。

    当catch捕获到异常对象后,可以通过上面的方法获取到异常的信息。

 

public class Demo11ThrowableMethod {

    public static void main(String[] args) {

        try {

            int[] arr = new int[2];

            System.out.println(arr[10]);

        } catch (ArrayIndexOutOfBoundsException e) { //异常对象其实是用变量e捕获的,所以这些方法要通过变量e去调用

            //System.out.println(e.toString()); //java.lang.ArrayIndexOutOfBoundsException: 10

            //System.out.println(e.getMessage()); //10

            e.printStackTrace();

        }

 

        System.out.println("end...");

    }

}

 

12、

在继承关系中,方法重写时异常的注意事项

 

    如果父类方法中抛出了异常,子类方法可以抛,也可以不抛。 如果子类方法往外抛, 要么和父类方法的异常相同,要么是父类方法异常的子类异常

    如果父类方法没有抛出异常,那么子类方法在重写的时候也不能抛。只能try...catch

 

 

    上面的限制只适用于编译时异常,并不适用于运行时异常。

package cn.itcast.demo01;

 

import java.io.FileNotFoundException;

import java.io.IOException;

import java.text.ParseException;

import java.text.SimpleDateFormat;

import java.util.Date;

 

/*

    在继承关系中,方法重写时异常的注意事项

 

    如果父类方法中抛出了异常,子类方法可以抛,也可以不抛。 如果子类方法往外抛, 要么和父类方法的异常相同,要么是父类方法异常的子类异常

    如果父类方法没有抛出异常,那么子类方法在重写的时候也不能抛。只能try...catch

 

 

    上面的限制只适用于编译时异常,并不适用于运行时异常。

*/

public class Zi extends Fu{

    @Override

    public void method() throws FileNotFoundException{

 

    }

 

    @Override

    public void function() {

        String str = "2011-11-11";

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        Date date = null;

        try {

            date = sdf.parse(str);

        } catch (ParseException e) {

 

        }

        System.out.println(date);

    }

}

 

 

package cn.itcast.demo01;

 

 

import java.io.IOException;

 

public class Fu {

    public void method() throws IOException{

 

    }

 

    public void function() {

 

    }

}

 

 

13、自定义异常

 

如何自定义异常?

        认贼作父

 

    如果定义一个类,去继承一个异常类,那么这个类也就变成了异常类。

 

    如果这个类继承的是编译时异常类,那么我们自定义的这个异常就是编译时异常。

 如果这个类继承的是运行时异常类,那么我们定义的这个异常,就是运行时异常。

 

public class RegistException extends RuntimeException{

    //定义有参构造,用来给出异常信息

    public RegistException(String msg) { //msg = "注册失败"

        //调用父类构造方法,传递异常信息

        super(msg);

    }

}

 

 

package cn.itcast.demo02;

 

import java.text.ParseException;

import java.text.SimpleDateFormat;

 

public class Demo01Regist {

 

    //定义一个数组,当做数据库,里面保存的是已经存在的用户名

    static String[] users = {"jack", "rose", "tom"};

 

    public static void main(String[] args) {

        //定义一个要注册的用户名

        String username = "rose";

 

        //调用regist方法注册

        //regist方法如果注册失败,在这个方法内部会抛出异常。

        //如果注册成功,就不会抛出。

        //所以可以使用trycatch捕获处理异常,如果没有捕获到异常,表示注册成功

        //如果捕获到了异常,就表示注册失败,说明这个方法内部遇到问题

 

        try {

            regist(username);

            System.out.println("注册成功");

        } catch (RegistException e) {

            System.out.println(e.getMessage());//获取到简短的异常信息并直接打印到控制台

        } catch (Exception e) { //为了保证程序的健壮性,进行捕获,捕获漏掉的异常

            System.out.println("出现了其他异常");

        }

    }

 

    /*

        定义一个方法,用来进行注册。

        参数传递要注册的用户名。

        在方法内进行判断,如果该用户名已经注册了,那么就直接抛出异常

        如果没有被注册,就不抛出异常,表示整个过程没有问题。

     */

    public static void regist(String username) {

        //判断users这个数组中是否包含我们要注册的用户名,如果保存,表示已经存在,那么就注册失败(抛出异常)

        //遍历users,拿users中的每一个元素和要注册的用户名进行比较

        for(String thisUser : users) {

            //thisUser表示的就是users中的每一个用户名

            //如果我们要注册的用户名和遍历到的用户名相同,那么表示已经存在。

            if(username.equals(thisUser)) {

                //如果用户名已经存在,那么抛出异常,表示过程出现了问题

                //throw new RuntimeException("注册失败");

                throw new RegistException("注册失败");

            }

        }

    }

}

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值