Java异常处理详解(全文干货,写得非常全,值得收藏)_java 异常_MrYuShiwen的博客-程序员秘密

技术标签: exception  java  异常处理  throw  # Java初级基础  throws  

一.初识Java异常

  1. 对异常的理解:异常:在Java语言中,将程序执行中发生的不正常情况称为“异常”。(开发过程中的语法错误和逻辑错误不是异常)
  2. Java程序在执行过程中所发生对异常事件可分为两类:
  • Error:Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源耗尽等严重情况。比如:StackOverflowError和OOM。一般不编写针对性 的代码进行处理。
  • Exception: 其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如:
    • 空指针访问
    • 试图读取不存在的文件
    • 网络连接中断
    • 数组角标越界
  1. 运行时异常和编译时异常
  • 运行时异常

    • 是指编译器不要求强制处置的异常。一般是指编程时的逻辑错误,是程序员应该积极避免其出现的异常。java.lang.RuntimeException类及它的子类都是运行时异常。
    • 对于这类异常,可以不作处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响。
  • 编译时异常

    • 是指编译器要求必须处置的异常。即程序在运行时由于外界因素造成的一 般性异常。编译器要求Java程序必须捕获或声明所有编译时异常。
    • 对于这类异常,如果程序不处理,可能会带来意想不到的结果。

在这里插入图片描述


二.Error和Exception

1.Error

代码示例一:java.lang.OutOfMemoryError(堆溢出)

public class ErrorTest {
    
    public static void main(String[] args) {
    
        //堆溢出:java.lang.OutOfMemoryError
        Long[] arr = new Long[1024*1024*1024];
    }
}

运行结果:
在这里插入图片描述

代码示例二:java.lang.StackOverflowError(栈溢出)

public class ErrorTest {
    
    public static void main(String[] args) {
    

        //栈溢出:java.lang.StackOverflowError
        main(args);
    }
}

运行结果:
在这里插入图片描述

2.Exception(运行时异常和编译时异常)

  • 运行时异常
    /* ******************以下是运行时异常****************** */
    //ArithmeticException
    @Test
    public void test1(){
    
        int num1 = 3;
        int num2 = 0;
        int num3 = 3 / 0;
    }

    //InputMismatchException
    @Test
    public void test2(){
    
        Scanner scanner = new Scanner(System.in);
        int i = scanner.nextInt();
        System.out.println(i);
        scanner.close();
    }

    //NumberFormatException
    @Test
    public void test3(){
    
        String str = "abcd";
        int num = Integer.parseInt(str);
    }

    //ClassCastException
    @Test
    public void test4(){
    
        Object obj = new Boolean(true);
        String str = (String)obj;
    }

    //IndexOutOfBoundsException
    @Test
    public void test5(){
    
        ArrayIndexOutOfBoundsException
        Byte[] bytes = new Byte[3];
        System.out.println(bytes[4]);
    }

    //NullPointerException
    @Test
    public void test6(){
    
        int[] arr = null;
        System.out.println(arr[1]);
    }

  • 编译时异常
/* ******************以下是编译时异常****************** */
    @Test
    public void test7(){
    
        File file = new File("a.txt");
        //java.io.FileNotFoundException
        FileInputStream fis = new FileInputStream(file);
        //java.io.IOException
        int date = fis.read();
        while (date != -1){
    
            System.out.println((char)date);
            date = fis.read();
        }

        fis.close();
    }

ps:对于编译时异常,我们需要异常处理


三.异常处理:抓抛模型

1.抓抛解释

  • 过程一:“抛”:程序在正常执行的过程中,一旦出现异常,就会在异常代码处生成一个对应异常类的对象, 并将此对象抛出;一旦抛出对象以后,其后的代码就不再执行。
    关于异常对象的产生:
    ① 系统自动生成的异常对象
    ② 手动的生成一个异常对象,并抛出(throw)
  • 过程二:“抓”:可以理解为异常的处理方式:① try-catch-finally ② throws

2.try-catch-finally的使用

try{
//可能出现异常的代码

}catch(异常类型1 变量名1){
//处理异常的方式1
}catch(异常类型2 变量名2){
//处理异常的方式2
}catch(异常类型3 变量名3){
//处理异常的方式3
}

finally{
//一定会执行的代码
}

说明:

  1. finally是可选的。
  2. 使用try将可能会出现异常的代码段包装起来,在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,根据此对象的类型,去catch中进行匹配
  3. 一旦try中的异常对象匹配到某一个catch时,就进入catch中进行异常的处理。一旦处理完成,就跳出当前的
    try-catch结构(在没有写finally的情况)。继续执行其后的代码
  4. catch中的异常类型如果没有子父类关系,则谁声明在上,谁声明在下无所谓。
    catch中的异常类型如果满足子父类关系,则要求子类一定声明在父类的上面。否则,报错
  5. 常用的异常对象处理的方式: ① String getMessage() ② printStackTrace()
  6. 在try结构中声明的变量,再出了try结构以后,就不能再被调用
  7. try-catch-finally结构可以嵌套
  8. finally中声明的是一定会被执行的代码。即使catch中又出现异常了,try中有return语句,catch中有return语句等情况。
  9. 像数据库连接、输入输出流、网络编程Socket等资源,JVM是不能自动的回收的,我们需要自己手动的进行资源的释放。此时的资源释放,就需要声明在finally中。

示例一:

@Test
public void test1(){
    
    String str = "abcd";
    int num = 1314;
    try {
    
        num = Integer.parseInt(str);

        System.out.println("进入try代码块!");
    }catch (NumberFormatException e){
    
        System.out.println("出现数值转换异常了!");
        System.out.println(e.getMessage());
        e.printStackTrace();
        System.out.println("该catch语句块将要执行完了!");
    } catch (NullPointerException e){
    
        System.out.println("出现空指针异常!");
    } catch (Exception e){
    
        System.out.println("出现异常了");
    }finally {
    
        System.out.println("执行finally语句了!");
    }
    System.out.println(num);
}

输出结果:

在这里插入图片描述

示例二:

    @Test
    public void test2(){
    
        File file = new File("a.txt");
        FileInputStream fis = null;
        try {
    
            fis = new FileInputStream(file);
            int date = fis.read();
            while(date != -1){
    
                System.out.println((char)date);
                date = fis.read();
            }


        } catch (FileNotFoundException e) {
    
            e.printStackTrace();
        }catch (IOException e){
    
            e.printStackTrace();
        }finally {
    
            System.out.println("执行finally语句了!");
            try {
    
                fis.close();
            } catch (IOException e) {
    
                e.printStackTrace();
            }
        }
    }

输出结果:
在这里插入图片描述

总结:

  • 使用try-catch-finally处理编译时异常,是得程序在编译时就不再报错,但是运行时仍可能报错。相当于我们使用try-catch-finally将一个编译时可能出现的异常,延迟到运行时出现。

  • 开发中,由于运行时异常比较常见,所以我们通常就不针对运行时异常编写try-catch-finally了。针对于编译时异常,我们说一定要考虑异常的处理。

3.throws + 异常类型的使用

  1. "throws + 异常类型"写在方法的声明处。指明此方法执行时,可能会抛出的异常类型。一旦当方法体执行时,出现异常,仍会在异常代码处生成一个异常类的对象,此对象满足throws后异常类型时,就会被抛出。异常代码后续的代码,就不再执行!

  2. try-catch-finally:真正的将异常给处理掉了。
    throws的方式只是将异常抛给了方法的调用者。 并没有真正将异常处理掉。

  3. 子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型(子类重写的方法也可以不抛出异常)

public class SuperClass {
    
    public void method() throws IOException {
    

    }
}

class SubClass extends SuperClass{
    
    //报错,子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型
//    public void method() throws Exception{
    
//
//    }

    public void method() throws FileNotFoundException{
    

    }
}

  1. 开发中如何选择使用try-catch-finally 还是使用throws?
    • 如果父类中被重写的方法没有throws方式处理异常,则子类重写的方法也不能使用throws,意味着如果
      子类重写的方法中有异常,必须使用try-catch-finally方式处理。
    • 执行的方法a中,先后又调用了另外的几个方法,这几个方法是递进关系执行的。我们建议这几个方法使用throws
      的方式进行处理。而执行的方法a可以考虑使用try-catch-finally方式进行处理。

代码示例:

public class ErrorThrows {
    
    public static void method1() throws IOException {
    
        File file = new File("a.txt");
        FileInputStream fileInputStream = new FileInputStream(file);
        
        int data = fileInputStream.read();
        while(data != -1){
    
            System.out.println((char)data);
            data = fileInputStream.read();
        }
        fileInputStream.close();
    }
    
    public static void method2() throws IOException {
    
        method1();
    }
    
    public static void method3() throws IOException {
    
        method1();
    }

    public static void main(String[] args) {
    
        try {
    
            method3();
        } catch (IOException e) {
    
            e.printStackTrace();
        }
    }
}

4.手动抛出一个异常类对象(throw关键字使用)

代码示例:

public class ReturnException {
    
    static void method1(){
    
        try{
    
            System.out.println("进入方法1");
            throw new RuntimeException("手动抛出异常");
        }catch (Exception e){
    
            e.printStackTrace();
            System.out.println(e.getMessage());
        } finally {
    
            System.out.println("执行finally语句了!");
        }
    }

    public static void main(String[] args) {
    
        method1();
    }
}

输出结果:
在这里插入图片描述


四.自定义异常类

自定义异常类,有如下三步骤:

  1. 继承于现有的异常结构:RuntimeException 、Exception
  2. 提供全局常量:serialVersionUID
  3. 提供重载的构造器

自定义异常类:

public class MyExceptionClass extends Exception{
    

    static final long serialVersionUID = -5641210210148784L;

    public MyExceptionClass() {
    
    }

    public MyExceptionClass(String message) {
    
        super(message);
    }
}

手动抛出上述自定义的异常类对象:

public class MyExceptionTest {
    

    static void method1() throws MyExceptionClass {
    
        Scanner scanner = new Scanner(System.in);

        System.out.println("请输入大于0的数据:");
        double next = scanner.nextDouble();
        if(next >0){
    
            System.out.println("您输入的数据为:"+next);
        }else {
    
            throw new MyExceptionClass("您输入的数据不满足要求!");
        }
    }

    public static void main(String[] args) {
    
        try {
    
            method1();
        } catch (MyExceptionClass myExceptionClass) {
    
            myExceptionClass.printStackTrace();
        }
    }
}

运行结果:
在这里插入图片描述

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/MrYushiwen/article/details/109814008

智能推荐

linux把没有执行权限的文件变为可执行_此文件没有执行权限,是否添加权限并运行_Amazing_deron的博客-程序员秘密

上传文件到linux主机后,如果需要执行上传的文件,需要修改文件的权限。否则会弹出提示:permission denied。更改权限的命令是chomdchmod的语法格式如下:chmod [who] [opt] [mode] 文件/目录名其中who表示对象,是以下字母中的一个或组合: u:表示文件所有者 g:表示同组用户 o:表示其它用户 a:表示所有用户 opt则是...

100019. 【NOI2017模拟6.26】A_Marcus0_O的博客-程序员秘密

题目大意给出一个大小为n的树,求合法路径个数 一个路径被称为合法当且仅当其路径上没有两个数使得其中的一个数为另外一个数的倍数 n的范围为100000题解不妨分两种情况对每一个限制(u,v)所能造成的影响进行讨论 设dfn[u]< dfn[v],dfn[a]< dfn[b](我们设一类(a,b)因为收到了这个限制的影响不能成为合法的路径) case 1: v在u的子树内,不妨设g为这条路径中

SiriKit 新变化:高品质的 Siri 媒体交互_程序员大咖的博客-程序员秘密

Python实战社群Java实战社群长按识别下方二维码,按需求添加扫码关注添加客服进Python社群▲扫码关注添加客服进Java社群▲作者:wiilen,iOS 开发者。来源公众号丨老司...

多线程之Master-Worker工作模式学习_小博的博客-程序员秘密

Master-Worker设计模式介绍Master-Worker模式是常用的并行设计模式。核心思想是,系统由两个角色组成,Master和Worker,Master负责接收和分配任务,Worker负责处理子任务。任务处理过程中,Master还负责监督任务进展和Worker的健康状态;Master将接收Client提交的任务,并将任务的进展汇总反馈给Client。各角色关系如下图Master...

canvas 生成图片模糊_canvas画出来的图模糊_qzo_smile的博客-程序员秘密

参考文件:https://blog.csdn.net/qq_41887214/article/details/123173072https://juejin.cn/post/6844903828916011022https://www.jb51.net/html5/815034.html在解决这个问题之前,必须了解以下背景知识:1.关于屏幕的一些基础知识:物理像素(DP)物理像素也称设备像素,我们常听到的手机的分辨率及为物理像素,比如 iPhone 7的物理分辨率为750 * 1334。屏

慌了,老大让我将线上的服务器升配,咋搞?_2c4g 数据库_尹吉欢的博客-程序员秘密

在业务高速发展的时候,后端的压力慢慢变大,服务器扩容在所难免。今天就聊聊扩容相关的问题。首先我们看数据库的扩容,到底是加实例还是直接升配?在创业初期,基本上都是单库的形式。比如最开始是4C8G的配置,到了某天数据库扛不住了,但是数据量其实没那么大,只是请求量上来了而已,或者由于研发写了很多复杂的Sql导致数据库性能下降了。数据库加实例这个时候最快的解决方式就是扩容了,首先我们来看加实例的方式,比如我们可以加N个从节点来提高查询的性能,可以对库进行垂直拆分或者水平拆分。以上这些都是提高性能的方式,但

随便推点

C++ 隐式的类类型转换_weiyuanzhang123的博客-程序员秘密

内容来源于C++ Primer 5,作为笔记。如果构造函数只接受一个实参,则它实际上定义转换为此类类型的隐式转换机制,有时我们把这种构造函数称作转换构造函数。能通过一个实参调用的构造函数定义了一条从构造函数的参数类型向类类型隐式转换的规则。只允许一步类类型转换类类型转换不是总有效抑制构造函数定义的隐式转换在要求隐式转换的程序上下文中,我们可以通过将构造函数声明为explicit加以阻止。关键字explicit只对一个实参的构造函数有效。需要多个实参的构造..

求求你们,别消费程序员了!_stormzhangV的博客-程序员秘密

最近一段时间,微博、朋友圈都被程序员刷屏了。先是微博上充斥着各种程序员格子衫的段子,紧接着又有各种程序员穿搭指南被刷屏了,虽然比较幽默,但是幽默中暗示程序员没品、秃头,然后再加上邋遢、情商低、没女朋友等等都跟程序员联系在一起,被各个行业津津乐道,不了解的还以为程序员是这个世界奇葩的物种一样,今天我得好好说道说道。真的,程序员哪有那么神秘、那么奇葩,我们不过就是普通人而已,如果非要说有什么特别的...

tcode search_sap_menu 根据关键字搜索SAP menu_汪子熙的博客-程序员秘密

Created by Jerry Wang, last modified on Dec 25, 2014例如想搜索SAP menu 里所有其描述包含了关键字"ABAP"的entry:按照返回结果里包含的层次结果即可快速查找到对应的SAP menu:...

技术洪流面前,程序员更应关注趋势_架构师成长营的博客-程序员秘密

作者丨ThoughtWorks编辑丨小智技术雷达是 ThoughtWorks 每半年发布一期的技术趋势报告,它不仅是一份持续的技术成熟度评估,其产生还源于 ThoughtWorks 另一个更大宏大的使命—IT 革命。技术雷达自 2010 年创办以来,已经走过 10 年、累计发布 21 期。它比那些我们能在市面上见到的其他技术行情和预测报告更加具体、更具可操作性,因为它不仅涉及到新技术大...

Golang正确大文件下载方式,避免OOM_golang 下载大文件_编程之禅的博客-程序员秘密

​ 今天在golang http下载一个大文件时,报错OOM,通过堆栈发现时读取文件内容时申请内存超过系统内存大小,导致进程被杀。一、错误实现方式func downloadFile() { file, err := os.OpenFile("xxx.txt", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666) if err != nil { return } defer func() { _ = file.Close() }() rsp, err

前端 移动端去除右侧白边_可爱的橙子大爷的博客-程序员秘密

昨天在写移动端的时候遇到了白边,怎么都弄不掉,代码里没有出现特别宽的宽度,找了很多方法,都没有用,最后用css一句话解决了,overflow-x: hidden;它的意思是: 裁剪 div 元素中内容的左/右边缘;希望对你有用,有用记得点赞哦...

推荐文章

热门文章

相关标签