Java基础-----异常部分学习笔记

一、异常的产生

1.1 异常与错误的概念:

java.lang.Throwable:类是java语言中所有错误的超类。

  1. Exception:编译期异常,进行编译(写代码)Java程序出现的问题。
    RuntimeException:运行期异常。
    异常相当于程序得了小毛病,处理掉就可以继续执行。
  2. Error:错误,相当于程序得了一个无法治愈的毛病,必须修改源代码,程序才能继续执行。
    在这里插入图片描述

1.2 Exception

exception例子:
parse是一个有异常的方法,执行之前必须抛出异常。
1、交给虚拟机处理(中断处理,把异常打印在控制台)

public class demo01 {
        public static void main(String[] args) throws ParseException {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); //用来格式化日期
            Date date = sdf.parse("1999-09-09"); //把字符串格式的日期解析为Date格式的日期。
        }
}

问题:parse中日期格式与设定的相同,运行不会报异常,但是不相同的时候就会报异常。比如改为:Date date = sdf.parse(“1999-0909”);
2、try,catch处理

public class demo01 {
        public static void main(String[] args) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); //用来格式化日期
            Date date = null; //把字符串格式的日期解析为Date格式的日期。
            try {
                date = sdf.parse("1999-0909");
            } catch (ParseException e) {
                e.printStackTrace();
            }
            System.out.println(date);
            System.out.println("继续执行");
        }
}

虽然控制台打印出异常,但是后续代码继续执行。

例子:
索引越界异常处理:

public class demo01 {
        public static void main(String[] args) {
            int[] arr = {1,2,3};
            try{
                System.out.println(arr[3]);
            }catch (Exception e){
                System.out.println(e);
            }
            System.out.println("继续执行");
        }
}

1.3 Error

error例子:

public class demo02 {
    /**
     *OutOfMemoryError: Java heap space错误
     */
    public static void main(String[] args) {
        int[] arr = new int[1024*1024*1024];
    }
}

内存溢出,创建的数组太大了,超出java分配的内存,必须修改源代码。

1.4 异常产生的过程

例子:
数组越界异常

public class demo02 {
    /**
     *OutOfMemoryError: Java heap space错误
     * 内存溢出,创建的数组太大了,超出java分配的内存
     */
    public static void main(String[] args) {
        int[] arr = {1,2,3};
        System.out.println(getElement(arr,3));
    }
    public static int getElement(int[] arr,int index){
       int ele = arr [index];
       return ele;
    }
}

1、首先访问数组中的3索引,发现没有这个,JVM检测出异常,并判断出异常原因。然后getElement方法中也没有这个异常处理,JVM把异常对象抛给main方法。
2、main方法接收到这个对象,也没有异常处理,然后继续抛给JVM处理。
3、JVM接收到对象,打印出异常,并且终止正在运行的程序。
在这里插入图片描述

二、异常处理

java异常处理的五个关键字:try、catch、finally、throw、throws。

2.1 抛出异常throw

throw关键字:

  1. 作用:
    可以使用throw关键字在指定的方法中抛出指定的异常。
  2. 使用格式:
    throw new xxxException(“异常产生的原因”);
  3. 注意:
    1.1、throw必须写在方法内部。
    1.2、throw关键字后边的new的对象必须是Exception或者Exception的子类对象。
    1.3、throw关键字p抛出指定的异常对象,我们就必须处理这个异常对象。
    *throw关键字后边创建的是RuntimeException或是RuntimeException的子类对象,我们可以不处理,默认交给JVM处理。
    *throw关键字后面创建的是编译异常(写代码的时候报错),我们就必须处理这个异常,要么throws,要么try…catch。
    例子:
    1、我们先对传递过来的值进行判断是否为null。
public class demo03Throw {
        public static void main(String[] args) {
            int[] arr = null;
            System.out.println(getElement(arr,0));
        }
        public static int getElement(int[] arr,int index){
            /*
            对传递过来的参数先进行校验
            判断是否为null
            */
            if ( arr == null){
                throw new NullPointerException("传递的数组的值为空");
            }
            int ele = arr [index];
            return ele;
        }
}

2、判断传递的index是否不在数组索引的范围内

public class demo03Throw {
        public static void main(String[] args) {
            int[] arr = null;
            int[] arr1 = {1,2,3};
            //System.out.println(getElement(arr,0));
            System.out.println(getElement(arr1,3));
        }
        public static int getElement(int[] arr,int index){
            /*
            对传递过来的参数先进行校验
            判断是否为null
            */
            if ( arr == null){
                throw new NullPointerException("传递的数组的值为空");
            }
            /*
            对index进行判断
            判断是否不在数组索引的范围内
            */
            if (index < 0 || index > arr.length-1){
                throw new ArrayIndexOutOfBoundsException("传递的数组索引越界");
            }
            int ele = arr [index];
            return ele;
        }
}

2.2 Objects非空判断

例子:

public class demo04Objects {
    public static void main(String[] args) {
        method(null);
    }
    public static void method(Object o){
        //对传递来的参数进行合法性判断
        /*if (o == null){
            throw new NullPointerException("传递的对象是空对象");
        }*/
        //Objects.requireNonNull(o);
        Objects.requireNonNull(o,"传递的对象为null");
    }
}

思想并没有怎么变,注意:Objects.requireNonNull的重载方法。

2.3 声明异常throws

throws关键字:异常处理的第一种方式,交给别人处理

  1. 作用:
    *当方法内部抛出异常对象的时候,那么我们就必须处理这个异常对象
    *可以使用throws关键字处理异常对象,会把异常对象声明抛出给方法的调用者处理,最终交给JVM处理。
  2. 使用格式:在方法声明中使用
    修饰符:返回值类型 方法名(参数列表)
throws(){
throw new AaaException("产生原因")throw new BbbException("产生原因")...
}
  1. 注意:
    *1、throws关键字必须写在方法声明处
    *2、throws关键字后面声明的异常必须是Exception或者是Exception的子类
    *3、方法内部如果抛出了多个异常对象,那么throws后面也必须声明多个异常。
    *4、调用了一个声明抛出异常的方法,我们就必须处理声明的异常。要么继续使用throws交给JVM处理,要么try…catch。
    例子:
    *方法抛出一个异常
public class demo05Throws {
    public static void main(String[] args) throws FileNotFoundException {
        readFile("d:\\a.txt");
    }
    /*
        定义一个方法,对传递的文件进行判断,在此固定文件路径。
     */
    public static void readFile(String fileName) throws FileNotFoundException {
        if (!fileName.equals("c:\\a.txt")){
            throw new FileNotFoundException("传递的文件路径不是c:\\a.txt");
        }
        System.out.println("读取文件");
    }
}

在readFile方法中抛出了异常,然后主方法调用readFile方法的时候还需要抛出异常。
*方法抛出多个异常

public class demo05Throws {
    //FileNotFoundException extends IOException,直接声明IOException就可
    public static void main(String[] args) throws FileNotFoundException,IOException {
        readFile("c:\\a.xt");
    }
        //定义一个方法,对传递的文件进行判断,在此固定文件路径。
    public static void readFile(String fileName) throws FileNotFoundException,IOException {
        if (!fileName.equals("c:\\a.txt")){
            throw new FileNotFoundException("传递的文件路径不是c:\\a.txt");
        }
        if (!fileName.endsWith(".txt")){
            throw new IOException("文件后缀名不对");
        }
        System.out.println("读取文件");
    }
}

FileNotFoundException extends IOException,直接声明IOException就可,可以把在方法上面抛出的FileNotFoundException 删除就行。

2.4 捕获异常try…catch

2.4.1 try…catch:自己处理捕获异常
			try{
                可能异常的代码
            catch(定义一个异常的变量,接收try中抛出的异常对象){
            异常处理的逻辑,产生异常对象之后怎么处理。
            一般在工作中,会把异常的的信息记录日志
            }
            ...
            catch(异常类名 变量名)

注意:
1、try中抛出多个异常对象,那么用catch来处理这些异常
2、如果try产生了异常,那么就会执行catch中的异常逻辑,执行完try…catch之后继续执行后续代码。
例子:

public class demo06TryCatch {
    public static void main(String[] args) {
        try {
            readFile("d:\\a.MP4");
        }catch (IOException e){
            System.out.println("传递的文件后缀不是.txt");
        }
        System.out.println("继续执行中...");
    }
    public static void readFile(String fileName) throws IOException {
        if (!fileName.endsWith(".txt")){
            throw new IOException("文件后缀名不对");
        }
        System.out.println("读取文件");
    }
}
2.4.2 Throwable类定义的异常处理方法

1、String getMessage() 返回此throwable的简短描述
2、String toString() 返回此throwable的详细消息字符串
3、void printStackTrace() JVM打印异常对象,默认此方法,异常信息是最全面的。
例子:

public class demo06TryCatch {
    public static void main(String[] args) {
        try {
            readFile("d:\\a.MP4");
        }catch (IOException e){
            //System.out.println("传递的文件后缀不是.txt");
            System.out.println(e.getMessage());
            System.out.println(e.toString());
            e.printStackTrace();
        }
        System.out.println("继续执行中...");
    }
    public static void readFile(String fileName) throws IOException {
        if (!fileName.endsWith(".txt")){
            throw new IOException("文件后缀名不对");
        }
        System.out.println("读取文件");
    }
}

2.5 finally代码块

finally代码块:

  • 无论程序出不出异常,我们都需要执行这段代码。
  • 一般用于资源释放。
  • x
    例子:
public class demo07TryCatchFinally {
    public static void main(String[] args) {
        try {
            //可能会产生异常的代码
            readFile("c:\\a.xt");
        } catch (IOException e) {
            //异常的处理逻辑
            e.printStackTrace();
        }finally {
            System.out.println("资源释放");
        }
    
    public static void readFile(String fileName) throws IOException {
        if (!fileName.endsWith(".txt")){
            throw new IOException("文件后缀名不对");
        }
        System.out.println("读取文件");
    }
}

2.6 异常的注意事项

  • 多个异常使用捕获又该如何处理呢?

1.多个异常分别处理。

public class demo08Exception {
    public static void main(String[] args) {
        try {
            int[] arr = {1,2,3};
            System.out.println(arr[3]);  
        }catch (ArrayIndexOutOfBoundsException e){
            System.out.println(e);
        }
        try {
            List<Integer> list = Arrays.asList(1, 2, 3);
            System.out.println(list.get(3));
        }catch (IndexOutOfBoundsException e){
            System.out.println(e);
        }
        System.out.println("继续执行...");
    }
}

2.多个异常一次捕获,多次处理。

public class demo08Exception {
    public static void main(String[] args) {
        try {
            int[] arr = {1,2,3};
            System.out.println(arr[3]);
            List<Integer> list = Arrays.asList(1, 2, 3);
            System.out.println(list.get(3));
        }catch (ArrayIndexOutOfBoundsException e){
            System.out.println(e);
        }catch (IndexOutOfBoundsException e){
            System.out.println(e);
        }
        System.out.println("继续执行...");
    }
}

一个try多个catch注意:

  • catch里面定义的异常变量,如果有子父关系,那么子类的异常变量必须写在上面,否正就会报错。
  • 比如ArrayIndexOutOfBoundsException继承了IndexOutOfBoundsException,将ArrayIndexOutOfBoundsException的catch放在下面,就会报错。原因就是继承关系,下面写了一句废话,最高级的就是Exception。

3.多个异常一次捕获,一次处理。

public class demo08Exception {
    public static void main(String[] args) {
        try {
            int[] arr = {1,2,3};
            System.out.println(arr[3]);
            List<Integer> list = Arrays.asList(1, 2, 3);
            System.out.println(list.get(3));
        }catch (Exception e){
            System.out.println(e);
        }
        System.out.println("继续执行...");
    }
}
	一般使用一次捕获多次处理的方式,格式如下:
try{
	编写可能会出现异常的代码
}catch(异常类型A e){try中出现A类型的异常,就用该catch来捕获
	处理异常的代码
	//记录日志/打印异常信息/继续抛出异常
}catch(异常类型B e){try中出现B类型的异常,就用该catch来捕获
	处理异常的代码
	//记录日志/打印异常信息/继续抛出异常
}
  • 运行时异常被抛出可以不处理,即不捕获也不声明抛出。直接给虚拟机处理。
  • 如果finally有return语句,永远返回finally中的结果,避免该情况。
    *finally通常用于资源回收
public class demo09Finally {
    public static void main(String[] args) {
        System.out.println(getA());
    }
    public static int getA(){
        int a = 10;
        try {
            return a;
        }catch (Exception e){
            System.out.println(e);
        }finally {
            a = 100;
            return a;
        }
    }
}
  • 如果父类抛出了多个子异常,子类覆盖父类方法时,只能抛出相同的异常或者是他的子类或者不抛出异常。
  • 父类方法没有抛出异常,子类重写父类该方法的时候也不抛出异常。此时子类产生该异常,只能捕获处理,不能声明抛出。
public class Fu {
    public void show01() throws NullPointerException,ClassCastException{}
    public void show02() throws IndexOutOfBoundsException{}
    public void show03() throws IndexOutOfBoundsException{}
    public void show04(){}
}
class Zi extends Fu{
    //子类重写父类方法的时候,抛出和父类相同的异常。
    public void show01() throws NullPointerException,ClassCastException{}
    //子类重写父类方法的时候,抛出父类异常的子类
    public void show02() throws ArrayIndexOutOfBoundsException{}
    //子类重写父类方法时候,不抛出异常。
    public void show03(){}
    //父类方法没有抛出异常,子类也不可以抛出异常。
    ///public void show04()throws Exception{}
    //此时子类产生的异常只能捕获处理。
    public void show04(){
        try {
            throw new Exception("编译期异常");
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2.7 自定义异常类

自定义异常类:

  • java提供的异常类不够使用。
    格式:
public class xxxException extends Exception | RuntimeException{
       添加一个空参的构造方法。
       添加一个异常信息的构造方法
}
  • 注意:
    *自定义异常类一般都是Exception结尾,说明该类是一个异常类。
    *必须继承的是Exception 或者 RuntimeException类
    *继承Exception:自定义的异常类就是一个编译期异常类
    *继承RuntimeException:就是一个运行期异常类,无需处理,交个给虚拟机处理做中断处理。
    例子:
public class registerException extends Exception {
    //添加一个空参构造方法
    public registerException(){
    }
    /*
    	添加一个带异常信息方法,
	    查看源码发现,所有的异常类都有一个异常信息的构造方法,
	    方法内部会调用父类带异常信息的构造方法,让父类来处理.
    */
    public registerException(String message){
        super(message);
    }
}

练习:
要求:模拟用户注册,如果用户名已经存在,则抛出异常并提示:该用户已经被注册。
分析:

  • 使用数组保存已经注册过的用户名。
  • 用Scanner获取用户注册的用户名。
  • 定义一个方法,对用户输入注册的用户名进行判断。
  • 遍历存储已经注册过用户名的数组,获取每一个用户名。
  • 使用获取到的用户名和用户输入的用户名机比较
    *true:用户名已经存在,抛出异常。
    *false:继续遍历
    *如果循环结束没找到重复的,提示注册成功。

方法一:使用throws抛出异常
定义异常类:registerException

public class registerException extends Exception {
    //添加一个空参构造方法
    public registerException(){
    }

    //添加一个带异常信息方法,
    //查看源码发现,所有的异常类都有一个异常信息的构造方法,方法内部会调用父类带异常信息的构造方法,让父类来处理
    public registerException(String message){
        super(message);
    }
}

创建registerMyException调用registerException

public class registerMyException {
    //使用数组保存数据
    static String[] usernames = {"张三","李四","王五"};
    public static void main(String[] args) throws registerException {
        //使用Scanner获取输入的用户名
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入您要注册的用户名:");
        String username = sc.next();
        checkUserName(username);
    }
    //定义一个方法,对用户输入的用户名进行判断
    public static void checkUserName(String username) throws registerException {
        for (String name : usernames) {
            //使用获取到的用户名与现有的比较
            if (name.equals(username)){
                //用户名已经存在,抛出异常
                throw new registerException("该用户已经被注册");
            }
        }
        //如果循环结束没找到重复的,提示注册成功。
        System.out.println("恭喜您,注册成功!!!");
    }
}

方法二:使用try…catch捕获异常…代码就不放了很简单。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值