不就是Java吗之 认识异常

这篇具有很好参考价值的文章主要介绍了不就是Java吗之 认识异常。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

大家好 , Java 专栏本应该早就完成的
但是之前发表异常的文章的时候 , 超过当天发布文章限制了
所以那时候就没上传成功 , 真的深感抱歉
刚才发现竟然少文章了
另外祝大家新年快乐
大年初七别忘了吃面条
不就是Java吗之 认识异常,Java,java,jvm,开发语言

一、异常的概念与体系结构

1.1 异常的概念

在计算机程序运行的过程中,总是会出现各种各样的错误。

Java中,将程序执行过程中发生的不正常的行为叫做异常.

我们以前也见到过许多异常,比如

  1. 算数异常

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

    不就是Java吗之 认识异常,Java,java,jvm,开发语言

  2. 数组越界异常

    //数组越界异常
    public static void main(String[] args) {
        int[] array = {1,2,3};//只有三个元素
    
        System.out.println(array[100]);//访问下标为100的元素,数组中没有就会报错
    }
    

    不就是Java吗之 认识异常,Java,java,jvm,开发语言

  3. 空指针异常

    //空指针异常
    public static void main(String[] args) {
        int[] array = null;//先让数组什么都不指向
        array[1] = 99;//报错:因为数组根本没指向任何对象,操作数组就会发生空指针异常
    }
    

    不就是Java吗之 认识异常,Java,java,jvm,开发语言

那么我们可以看出来,每一个异常对应的都是一个类.

1.2 异常的体系结构

不就是Java吗之 认识异常,Java,java,jvm,开发语言

1.3 异常的分类

1.3.1 编译时异常(受查异常)

在编译期间发生的错误,叫做编译时异常(也叫受查异常)

1.3.2 运行时异常(非受查异常)

在程序执行期间发生的错误,叫做运行时异常(也叫非受查异常)

RunTimeException及其子类对应的异常.都叫做运行时异常

要注意:我们少写了个分号 括号这种算语法错误,不算异常

真正的异常是指程序变异之后得到class文件,再通过JVM执行发现错误

二、异常的处理

2.1 防御型编程

2.1.1 LBYL

在操作前就做好充分的检查,即:事前防御型,每做一步都要检查

形象一点就是:刚交往的男女生,男生想要牵手之前先问问,想要抱抱时候也要先问问

boolean ret = false;
ret = 登陆游戏();
if (!ret) {
    处理登陆游戏错误;
    return;
}
ret = 开始匹配();
if (!ret) {
    处理匹配错误;
    return;
}
ret = 游戏确认();
if (!ret) {
    处理游戏确认错误;
    return;
}
ret = 选择英雄();
if (!ret) {
    处理选择英雄错误;
    return;
}
ret = 载入游戏画面();
if (!ret) {
    处理载入游戏错误;
    return;
}
......

缺陷:正常流程和错误处理流程代码混在一起, 代码整体显的比较混乱。

2.1.2 EAFP

先进行操作,遇到问题再处理,即:事后认错性.

形象一点就是男女朋友,男生想亲亲,直接就霸王硬上攻,过后再说"宝宝我错了".

语法:

//捕获异常使用try...catch语句,把可能发生异常的代码放到try {...}中,然后使用catch捕获对应的Exception及其子类:
try {
    
} catch() {
    
} catch() {
    
}
...

刚才的例子接下来这么写

try {
  登陆游戏();
  开始匹配();
  游戏确认();
  选择英雄();
  载入游戏画面();
 ...
} catch (登陆游戏异常) {
  处理登陆游戏异常;
} catch (开始匹配异常) {
处理开始匹配异常;
} catch (游戏确认异常) {
处理游戏确认异常;
} catch (选择英雄异常) {
处理选择英雄异常;
} catch (载入游戏画面异常) {
处理载入游戏画面异常;
}
......

不就是Java吗之 认识异常,Java,java,jvm,开发语言

优势:正常流程和错误流程是分离开的, 程序员更关注正常流程,代码更清晰,容易理解代码

Java中,异常处理主要的5个关键字:throw、try、catch、final、throws

2.2 异常的抛出

在编写程序时,如果程序中出现错误,此时就需要将错误的信息告知给调用者,比如:参数检测。
Java中,可以借助throw关键字,抛出一个指定的异常对象,将错误信息告知给调用者。具体语法如下:

throw new XXXException("异常产生的原因");//自定义异常会出现的多一些

举个栗子:

public class TestDemo1 {
    public static void func(int a) {
        if(a == 10) {
            throw new RuntimeException("a==10");
        }
    }
    public static void main(String[] args) {
        func(10);
    }
}

不就是Java吗之 认识异常,Java,java,jvm,开发语言

注意:

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

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

    不就是Java吗之 认识异常,Java,java,jvm,开发语言

  3. 如果抛出的是RuntimeException或者他的子类,那么我们可以不用处理,交给JVM帮我们处理

    不就是Java吗之 认识异常,Java,java,jvm,开发语言

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

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

2.3 异常的捕获

异常的捕获,也就是异常的具体处理方式,主要有两种:异常声明throws 以及 try-catch 捕获处理。

2.3.1 异常的声明

在方法的参数列表后面写 throws , 当方法中抛出编译时异常,用户不想处理该异常,此时就可以借助 throws 将异常抛
给方法的调用者来处理。即当前方法不处理异常,提醒方法的调用者处理异常。直到遇到某个 try ... catch 被捕获为止:

public class TestDemo1 {
    public static void func(int a) throws CloneNotSupportedException {
        if(a == 10) {
            throw new RuntimeException("a==10");
        }
    }
    public static void main(String[] args) {
        func(10);
    }
}

注意:

  1. throws必须跟在方法的参数列表之后

  2. 声明的异常必须是 Exception 以及 他的子类

    不就是Java吗之 认识异常,Java,java,jvm,开发语言

  3. 方法内部如果抛出了多个异常,throws 之后必须跟多个异常类型,之间用逗号隔开,如果抛出多个异常类型具有父子关系,直接声明父类即可。

    public class TestDemo1 {
        //throws:声明了一下异常,但是并没有处理异常
        public static void func(int a) throws RuntimeException,NullPointerException {
            if(a == 10) {
                throw new RuntimeException("a==10");
            } else {
                throw new NullPointerException("a == 其他");
            }
        }
        public static void main(String[] args) {
            func(10);
        }
    }
    
    
  4. 调用声明抛出异常的方法时,调用者必须对该异常进行处理,或者继续使用 throws 抛出

    public class TestDemo1 {
        public static void func(int a) throws RuntimeException,NullPointerException {
            if(a == 10) {
                throw new RuntimeException("a==10");
            } else {
                throw new NullPointerException("a == 其他");
            }
        }
        public static void main(String[] args) throws Exception {
            func(10);
        }
    }
    
    

2.3.2 try-catch捕获并处理

throws 对异常并没有真正处理,而是将异常报告给抛出异常方法的调用者,由调用者处理。如果真正要对异常进行处理,就需要try-catch

try {
 // 将可能出现异常的代码放在这里
} catch (要捕获的异常类型  e) {
 // 如果try中的代码抛出异常了,此处catch捕获时异常类型与try中抛出的异常类型一致时,或者是try中抛出异常的基类时,就会被捕获到
 // 对异常就可以正常处理,处理完成后,跳出try-catch结构,继续执行后序代码
} catch (要捕获的异常类型 e) {
 // 对异常进行处理
} finally {
 // 此处代码一定会被执行到
}
// 后序代码
// 当异常被捕获到时,异常就被处理了,这里的后序代码一定会执行
// 如果捕获了,由于捕获时类型不对,那就没有捕获到,这里的代码就不会被执行

//注意:try中的代码可能会抛出异常,也可能不会

举个栗子:

public class TestDemo2 {
 public static void main(String[] args) {
     int[] array = {1,2,3};
     try {
         array[100] = 0;
     } catch (NullPointerException e) {
         e.printStackTrace();
         System.out.println("捕获到了一个空指针异常");
     } catch (ArrayIndexOutOfBoundsException e) {
         e.printStackTrace();
         System.out.println("捕获到了一个数组越界异常");
     }

     System.out.println("其他业务逻辑");
 }
}

注意:

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

    public class TestDemo2 {
        public static void main(String[] args) {
            int[] array = {1,2,3};
            try {
                array[100] = 0;
                System.out.println("上面那行出现异常,这行是执行不了的");
            } catch (NullPointerException e) {
                e.printStackTrace();
                System.out.println("捕获到了一个空指针异常");
            } catch (ArrayIndexOutOfBoundsException e) {
                e.printStackTrace();
                System.out.println("捕获到了一个数组越界异常");
            }
    
            System.out.println("其他业务逻辑");
        }
    }
    
    

    不就是Java吗之 认识异常,Java,java,jvm,开发语言

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

    public class TestDemo2 {
        public static void main(String[] args) {
            int[] array = {1,2,3};
            try {
                array[100] = 0;//发生数组越界异常
                System.out.println("上面那行出现异常,这行是执行不了的");
            } catch (NullPointerException e) {//空指针异常
                e.printStackTrace();
                System.out.println("捕获到了一个空指针异常");
            } 
            System.out.println("其他业务逻辑");
        }
    }
    //try语句中发生的是数组越界异常,而我们的catch里面是空指针异常,数组越界异常就不能被捕捉到.最后一行的其他业务逻辑也就不能被打印了
    
  3. try 中可能会抛出多个不同的异常对象,则必须用多个 catch 来捕获

    public class TestDemo2 {
        public static void main(String[] args) {
            int[] array = {1,2,3};
            try {
                array[100] = 0;
            } catch (NullPointerException e) {
                e.printStackTrace();
                System.out.println("捕获到了一个空指针异常");
            } catch (ArrayIndexOutOfBoundsException e) {
                e.printStackTrace();
                System.out.println("捕获到了一个数组越界异常");
            }
    
            System.out.println("其他业务逻辑");
        }
    }
    
    

    如果多个异常的处理方式是完全相同, 也可以写成这样:

    public class TestDemo2 {
        public static void main(String[] args) {
            int[] array = {1,2,3};
            try {
                array[100] = 0;
            } catch (NullPointerException | ArrayIndexOutOfBoundsException e) {
                e.printStackTrace();
            }
            System.out.println("其他业务逻辑");
        }
    }
    

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

    public class TestDemo2 {
        public static void main(String[] args) {
            int[] array = {1,2,3};
            try {
                array[100] = 0;
            } catch (Exception e) {
                e.printStackTrace();
            } catch (ArrayIndexOutOfBoundsException e) {
                e.printStackTrace();
            }
        }
    }
    

    不就是Java吗之 认识异常,Java,java,jvm,开发语言

    正确写法:

    public class TestDemo2 {
        public static void main(String[] args) {
            int[] array = {1,2,3};
            try {
                array[100] = 0;
            } catch (ArrayIndexOutOfBoundsException e) {
                e.printStackTrace();
            } catch (Exception e) {//Exception可以捕捉到所有异常,所以我们可以拿它来兜底
                e.printStackTrace();
            }
        }
    }
    
  4. 可以通过一个 catch 捕获所有的异常,即多个异常,一次捕获(不推荐)

    public class TestDemo2 {
        public static void main(String[] args) {
            int[] array = {1,2,3};
            try {
                array[100] = 0;
            } catch (Exception e) {//Exception可以捕捉到所有异常,所以我们可以拿它来兜底,但是不能只有Exception
                e.printStackTrace();
            }
        }
    }
    
  5. 一个 try 里面只能同时处理一个异常

    public class TestDemo2 {
        public static void func(int a) throws RuntimeException {
            if(a == 10) {
                throw new RuntimeException("a == 10");
            }
        }
        public static void main(String[] args) {
            int[] array = {1,2,3};
            try {
                array[100] = 0;
                func(10);
            } catch (ArrayIndexOutOfBoundsException e) {
                e.printStackTrace();
            } catch (RuntimeException e) {
                e.printStackTrace();
            }
        }
    }
    

    不就是Java吗之 认识异常,Java,java,jvm,开发语言

  6. 编译时候的异常必须处理!运行时的异常可以不处理,交给 JVM 来处理~

    程序员处理了异常,就没啥事了.程序猿没处理, JVM 就帮我们处理了

2.3.3 finally

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

语法:

try {
    // 可能会发生异常的代码
} catch (异常类型  e) {
    // 对捕获到的异常进行处理
} finally {
    // 此处的语句无论是否发生异常,都会被执行到
}

// 如果没有抛出异常,或者异常被捕获处理了,这里的代码也会执行

举个栗子:

public static void main(String[] args) {
        int[] array = {1,2,3};
        try {
            array[100] = 0;
        } catch (ArrayIndexOutOfBoundsException e) {
            e.printStackTrace();
        } finally {
            System.out.println("finally里面的这句话一定会被执行");
        }
    }

不就是Java吗之 认识异常,Java,java,jvm,开发语言

那么有一个问题:既然 finallytry-catch-finally 后面的代码都会执行,那为什么还要有 finally 呢?

finally 一般是用来做资源清理的扫尾操作的

public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        try {
            int a = scanner.nextInt();
            System.out.println(10/a);
        } catch (ArithmeticException e) {
            System.out.println("捕捉到了算术异常");
            e.printStackTrace();
        } finally {
            scanner.close();//正常我们使用scanner就需要在最后close的
            System.out.println("finally语句一定会被执行,所以这里面会执行一些关闭资源的语句");
        }
    }

当我们只有一个资源进行中的时候,我们也可以这么写

public static void main(String[] args) {
        try(Scanner scanner = new Scanner(System.in)) {
            int a = scanner.nextInt();
            System.out.println(10/a);
        } catch (ArithmeticException e) {
            System.out.println("捕捉到了算术异常");
            e.printStackTrace();
        } finally {
            //这种情况就可以不用关闭资源了
            System.out.println("finally语句一定会被执行,所以这里面会执行一些关闭资源的语句");
        }
    }

那么我们看这样一道题:

public static int func1() {
    try{
        return 10;
    } finally {
        return 20;
    }
}
public static void main(String[] args) {
    System.out.println(func1());
}

输出结果是多少?

不就是Java吗之 认识异常,Java,java,jvm,开发语言

2.4 异常的处理流程

关于 “调用栈”

方法之间是存在相互调用关系的, 这种调用关系我们可以用 “调用栈” 来描述. 在 JVM 中有一块内存空间称为 “虚拟机栈” 专门存储方法之间的调用关系. 当代码中出现异常的时候, 我们就可以使用 e.printStackTrace(); 的方式查看出现异常代码的调用栈.

如果本方法中没有合适的处理异常的方式, 就会沿着调用栈向上传递.如果向上一直传递都没有合适的方法处理异常, 最终就会交给 JVM 处理, 程序就会异常终止

//这种就是抛出异常,有捕捉的
public static void func3(int a) throws ArithmeticException {
    if(a == 10) {
        throw new ArithmeticException("a == 10");
    }
}
public static void main(String[] args) {
    try {
        func3(10);
    } catch (ArithmeticException e) {
        e.printStackTrace();
    }
}
//这种就是我们没有捕获异常,JVM帮我们直接把程序终止掉了
public static void func3(int a) throws ArithmeticException {
    if(a == 10) {
        throw new ArithmeticException("a == 10");
    }
}
public static void main(String[] args) {
    func3(10);
    System.out.println("这句话因为我们没有处理异常,JVM会帮我们直接把程序终止,这句话就执行不到了");
}

不就是Java吗之 认识异常,Java,java,jvm,开发语言

2.5 异常处理流程总结

  1. 程序先执行 try 中的代码
  2. 如果 try 中的代码出现异常, 就会结束 try 中的代码, 看和 catch 中的异常类型是否匹配.
  3. 如果找到匹配的异常类型, 就会执行 catch 中的代码
  4. 如果没有找到匹配的异常类型, 就会将异常向上传递到上层调用者.
  5. 无论是否找到匹配的异常类型, finally 中的代码都会被执行到(在该方法结束之前执行).
  6. 如果上层调用者也没有处理的了异常, 就继续向上传递.
  7. 一直到 main 方法也没有合适的代码处理异常, 就会交给 JVM 来进行处理, 此时程序就会异常终止.

三、自定义异常类

在一个大型项目中,可以自定义新的异常类型,但是,保持一个合理的异常继承体系是非常重要的。

语法:

  1. 自定义一个异常类,继承 Exception 或者 RunTimeException

    继承自 Exception 的异常默认是受查异常
    继承自 RuntimeException 的异常默认是非受查异常.

  2. 在这个异常类当中,实现一个带有一个参数( String )的构造方法,参数代表报错原因

//用户名错误,我们设计出来的异常类
public class UserNameError extends RuntimeException {
    public UserNameError(String message) {
        super(message);
    }
}

//密码错误,我们设计出来的异常类
public class PasswordError extends RuntimeException {
    public PasswordError(String message) {
        super(message);
    }
}

例如,我们实现一个简易的用户登录功能

我们先来自定义异常类

//用户名错误,我们设计出来的异常类
public class UserNameError extends RuntimeException {
    public UserNameError(String message) {
        super(message);
    }
}

//密码错误,我们设计出来的异常类
public class PasswordError extends RuntimeException {
    public PasswordError(String message) {
        super(message);
    }
}

再来写我们的测试逻辑

public class Login {
    private String userName = "admin";
    private String pass = "123456";

    public void LoginInfor(String userName,String password) throws UserNameError,PasswordError {
        if(!this.userName.equals(userName)) {//不相等的情况
            throw new UserNameError("用户名错误");
        }
        if(!this.pass.equals(password)) {//不相等的情况
            throw new PasswordError("密码错误");
        }
        //走到这里,代表登陆成功
        System.out.println("登陆成功");
    }

    public static void main(String[] args) {
        try {
            Login login = new Login();
            login.LoginInfor("admin","avd");
        } catch (UserNameError e) {
            System.out.println("用户名错误");
            e.printStackTrace();
        } catch (PasswordError e) {
            System.out.println("密码错误");
            e.printStackTrace();
        }
    }
}

至此 , Java 基础部分已经分享完毕 , 多线程以及文件操作等难度稍微有点高的内容我会放到 JavaWeb 阶段跟大家再来分享
不就是Java吗之 认识异常,Java,java,jvm,开发语言文章来源地址https://www.toymoban.com/news/detail-816775.html

到了这里,关于不就是Java吗之 认识异常的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java基础常考知识点(基础、集合、异常、JVM)

    作者: 逍遥Sean 简介:一个主修Java的Web网站游戏服务器后端开发者 主页:https://blog.csdn.net/Ureliable 觉得博主文章不错的话,可以三连支持一下~ 如有需要我的支持,请私信或评论留言! 本文收集Java核心的面试常考知识点,码起面试之前复习!!! JDK(Java SE Development Kit) ,

    2024年02月07日
    浏览(55)
  • Java语言-----泛型的认识

    目录 一.什么是泛型 二.泛型类的使用 2.1泛型类的定义  2.2泛型类的数组使用 三.泛型的上界  四.泛型的方法 五.泛型与集合 😽个人主页: tq02的博客_CSDN博客-C语言,Java领域博主  🌈梦的目标:努力学习,向Java进发,拼搏一切,让自己的未来不会有遗憾。  🎁欢迎各位→点

    2023年04月23日
    浏览(45)
  • 快速认识,后端王者语言:Java

    Java作为最热门的开发语言之一,长居各类排行榜的前三。所以,就算你目前不是用Java开发,你应该了解Java语言的特点,能用来做什么,以备不时之需。 Java 是一种高级、多范式编程语言,以其编译为独立于平台的字节码的能力而闻名。 它是由 Sun Microsystems 的 James Gosling 于

    2024年02月05日
    浏览(35)
  • 由浅到深认识Java语言(9):Eclipse IDE简介

    该文章Github地址:https://github.com/AntonyCheng/java-notes 在此介绍一下作者开源的SpringBoot项目初始化模板(Github仓库地址:https://github.com/AntonyCheng/spring-boot-init-template CSDN文章地址:https://blog.csdn.net/AntonyCheng/article/details/136555245),该模板集成了最常见的开发组件,同时基于修改配置

    2024年03月25日
    浏览(44)
  • Java语言----异常处理(看了必会)

    目录 一.异常的概述 二.异常类的层次结构和种类 二.异常的基本用法 2.1异常的捕捉 2.2异常处理代码实现 三.抛出异常 3.1 throw 3.2 throws 四.finally的进一步详解 五.自定义异常类 总结 😽个人主页:tq02的博客_CSDN博客-C语言,Java领域博主  🌈理想目标:努力学习,向Java进发,拼搏

    2023年04月11日
    浏览(58)
  • Java后端开发中Java 8,JVM和JDK的关系

    Java8(也就是Java1.8)是Java编程语言的一个主要版本,正式名称为Java Platform, Standard Edition 8 (Java SE 8)。Java 8在2014年3月发布,引入了许多新特性,如Lambda表达式、新的日期时间API、接口中的默认和静态方法等。Java 8的引入使得Java程序可以更加简洁、易读,同时提高了编程效率。

    2024年04月08日
    浏览(42)
  • JVM执行引擎——为什么Java是半编译半解释语言

            起初设计者的初衷是将字节码文件翻译为机器语言的指令来执行即可,就诞生了解释器。但是采用一行行来解释的 效率比较低 ,JIT编译器会将编译后的机器码做一个缓存的操作,放在方法区的JIT代码缓存中,是否需要启用JIT编译器直接将字节码编译为机器码,则

    2024年02月15日
    浏览(49)
  • Java开发环境简介(JDK、JRE、JVM)

    目录 1、Java开发环境 2、JDK和JRE 3、JDK下载和安装 3.1 下载 3.2 安装 3.3 配置path环境变量 JDK8配置方案1:只配置path ⭐JDK8配置方案2:配置JAVA_HOME+path(推荐) path配置小结 JDK17配置方案:自动配置 4、Java核心机制:JVM 补充:Java字节码 JVM的优点 JVM的缺点 JVM的运行过程 5、Java程序

    2024年02月21日
    浏览(45)
  • Java开发 - 你不知道的JVM优化详解

    代码上的优化达到一定程度,再想提高系统的性能就很难了,这时候,优秀的程序猿往往会从JVM入手来进行系统的优化。但话说回来,JVM方面的优化也是比较危险的,如果单单从测试服务器来优化JVM是没有太大的意义的,不同的服务器即使环境相同,访问流量方面也是不一样

    2024年02月07日
    浏览(41)
  • JAVA后端开发面试基础知识(一)——JVM

    Class loader(类装载) 根据给定的全限定名类名(如: java.lang.Object)来装载class文件到 Runtime data area中的method area。 Execution engine(执行引擎) 执行classes中的指令。 Native Interface(本地接口) 与native libraries交互,是其它编程语言交互的接口。 Runtime data area(运行时数据区域) 这就是我们常说

    2024年03月10日
    浏览(58)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包