【Java挠头】Java异常、捕获、处理、throw、throws等绝妙剖析

简介: 【Java挠头】Java异常、捕获、处理、throw、throws等绝妙剖析

–本文摘要–

   1、本文的目标读者:是接触过Java异常,但是仅限于书本和一些例题,某一天写着写着会突然觉得“‘异常’没什么意义,Java不是已经帮我们处理了嘛?”的这些朋友。

   2、本文的内容摘要:讲述日常开发中如何看待‘异常’这个概念,讲述在一个中型web项目中,我们如何处理‘异常’。

   【版权声明】归CSDN账户[征途黯然.]/公众号[三黄工作室]原创,禁止任何网站与个人采集或转载。

一、本文结构


image.png

  读完本文,你一定能解开如下困惑:


1)Java自己会报错,而且很多网站(比如xx大学的官网)路径错误时,就会报一堆Java错误,网站中这些错误给用户的提示,都在报Java原始的错误信息,那还要学异常处理的意义何在?

2)throw和throws有何区别?在方法里面throw错误不是有病嘛?throws在方法名那一行定义到底完成了哪些功能?

3)一个正规项目中,异常多种多样,开发者是不是要写很多异常处理?

4)夏天到了,小姐姐们会不会因为没有男朋友而产生exception,要不要我去处理一下?【哈哈】

二、大学官网让我觉得‘异常处理毫无意义’


   💻言归正传。

   当年刚学Java的异常,觉得Java真厉害啊,异常先捕获下来,分分钟处理掉。结果,一登学校官网,时不时给我报个变量‘xxx’没有赋值。当时我就在想,如果这种基础错误开发者都不做处理,那还要Java中还要‘捕获’这个概念干嘛?大家一起用Java自带的一大串异常报错不就好了。

三、Java异常


   基础的Java异常关系如下图3-1所示:

20210514200302423.png

  【首先】

   Exception是程序执行时发生的异常,Error是JVM运行错误(这是致命错误),无法处理。他们共有一个基类是Throwable,所以在日常开发中,我们对Exception写的多一点,因为Error是致命错误。

   异常可以理解为‘程序运行中一个小毛病’。发生Error,程序都跑不起来,何来小毛病一说呢。


   【其次】

   这里把RuntimeException贴出来的目的是,我们项目中用到的异常类型,我们一般都定义为RuntimeException类型。用RuntimeException的原因,在文章最后有介绍。

四、捕获与处理


   异常,是程序中导致程序中断的指令流。如果我们不去管它,那么发生了异常,程序就会中断,这是在日常项目中绝对不能发生的(得亏多少钱)。所以,我们要处理它,用一种合适的方式处理,所以用到了try-catch-finally语法。见下图4-1:

20210514202818779.png


   【图4-1解释】try-catch-finally语法就像是一个容器,程序执行时,代码C可能发生异常而导致程序中断。我们加一个容器来包含住代码C,这样无论它出错与否,起码不会让程序中断,连个return都不能执行。

  关于try-catch-finally初学者会产生很多疑问。⭐⭐比较突出的是:既然代码C出错了,如果代码D需要用到代码C里面的变量,我继续执行代码D有什么意义呢?

   这里引出我们在开发中使用异常捕获的目的,见下图4-2:

20210514213931140.png

  【捕获异常的意义】

   首先要保证捕获内容的原子性(抽象上的原子性),也就是try的内容尽量独立,不要被try外部引用,否则捕获是不完整的。


   【技术上的意义】

1、捕获异常,防止方法直接中断,否则可能连return都无法执行。

2、处理可能出错的变量。如果是该变量异常,我们在try之后,可以给变量设默认值,保证它在接下来可以良好运行。

3、回收空间,保证系统性能。如果一块空间出错,我们可以回收,防止性能消耗。


   【业务上的意义】

   我们在出现异常后,可以设计一个监听器来识别系统中所有的异常错误,对不同类型的异常,返回不同的信息给用户,这样可以保证用户看得懂(系统的友好性)。

五、throw与throws


   【throw】

   throw是在方法内部抛出一个异常(可以自定义,也可以是Java自带的异常类)。手动抛出的异常,只要类型相同,和系统自己产生的异常没差别,请看以下代码:

  @Test
    public void test001(){
        int a=2/0;
    }
    @Test
    public void test003(){
        throw new ArithmeticException("不可为零");
    }

  代码解释:int a=2/0;在Java中会报ArithmeticException错误,与手动throw一个ArithmeticException错误是等效的。两个测试函数的报错大致相同,见下图5-1:

2021051422072528.png

   关于throw初学者还是会产生很多疑问。⭐⭐大概是:为什么要在程序中自己抛出异常?不是应该避免程序中的异常嘛?

   这个问题的解答请看本文的最后一节。

   【throws】

   throws是在方法定义时,添加异常声明。throws可以声明多个异常类,声明的基本语法如下代码:

  @Test
    public void test001() throws  Exception,MyException{
        int a=2/0;
    }

   throws声明了本方法中可能出现的异常类。表示如果方法中真的产生了异常,Java程序不会立即中断,而是会把异常向上传递给上一级,让上一级来处理,而上层的方法必须处理这个异常,不处理会出现Error。

 而普通定义的方法,上层方法不是一定要定义try-catch机制。

    处理逻辑见下图5-2:

20210514231738491.png

六、日常开发中的异常处理


20210514235812151.png

⭐【第三节遗留问题】项目开发中,用RuntimeException的原因。


   【–解答–】RuntimeException类型的异常,支持开发者自定义处理,也支持开发者不处理,让Java来兜底。这样自由度高,开发简易,开发中我们大多使用RuntimeException类型来派生出自定义异常类型。


    ⭐【第五节遗留问题】为什么要在程序中自己抛出异常?不是应该避免程序中的异常嘛?


   【–解答–】我们在方法中抛出异常,提交给项目中的异常监听器来处理异常,分析异常中的类型,然后给用户返回对应的提示信息。

相关文章
|
1天前
|
Java
如何在 Java 中处理“Broken Pipe”异常
在Java中处理“Broken Pipe”异常,通常发生在网络通信中,如Socket编程时。该异常表示写入操作的另一端已关闭连接。解决方法包括:检查网络连接、设置超时、使用try-catch捕获异常并进行重试或关闭资源。
|
4天前
|
存储 安全 Java
如何避免 Java 中的“ArrayStoreException”异常
在Java中,ArrayStoreException异常通常发生在尝试将不兼容的对象存储到泛型数组中时。为了避免这种异常,确保在操作数组时遵循以下几点:1. 使用泛型确保类型安全;2. 避免生类型(raw types)的使用;3. 在添加元素前进行类型检查。通过这些方法,可以有效防止 ArrayStoreException 的发生。
|
5天前
|
人工智能 Oracle Java
解决 Java 打印日志吞异常堆栈的问题
前几天有同学找我查一个空指针问题,Java 打印日志时,异常堆栈信息被吞了,导致定位不到出问题的地方。
18 2
|
8天前
|
Java 索引
如何避免在 Java 中引发`StringIndexOutOfBoundsException`异常
在Java中,处理字符串时若访问了不存在的索引,会抛出`StringIndexOutOfBoundsException`异常。为避免此异常,应确保索引值在有效范围内,例如使用`length()`方法检查字符串长度,并确保索引值不小于0且不大于字符串长度减1。
|
10天前
|
安全 Java 数据安全/隐私保护
如何配置 Java 安全管理器来避免访问控制异常
配置Java安全管理器以防止访问控制异常,需在启动JVM时通过 `-Djava.security.manager` 参数启用,并设置安全策略文件,定义权限规则,限制代码执行操作,确保应用安全。
|
4天前
|
监控 安全 Java
在 Java 中使用线程池监控以及动态调整线程池时需要注意什么?
【10月更文挑战第22天】在进行线程池的监控和动态调整时,要综合考虑多方面的因素,谨慎操作,以确保线程池能够高效、稳定地运行,满足业务的需求。
71 38
|
1天前
|
安全 Java
java 中 i++ 到底是否线程安全?
本文通过实例探讨了 `i++` 在多线程环境下的线程安全性问题。首先,使用 100 个线程分别执行 10000 次 `i++` 操作,发现最终结果小于预期的 1000000,证明 `i++` 是线程不安全的。接着,介绍了两种解决方法:使用 `synchronized` 关键字加锁和使用 `AtomicInteger` 类。其中,`AtomicInteger` 通过 `CAS` 操作实现了高效的线程安全。最后,通过分析字节码和源码,解释了 `i++` 为何线程不安全以及 `AtomicInteger` 如何保证线程安全。
java 中 i++ 到底是否线程安全?
|
5天前
|
Java 调度
[Java]线程生命周期与线程通信
本文详细探讨了线程生命周期与线程通信。文章首先分析了线程的五个基本状态及其转换过程,结合JDK1.8版本的特点进行了深入讲解。接着,通过多个实例介绍了线程通信的几种实现方式,包括使用`volatile`关键字、`Object`类的`wait()`和`notify()`方法、`CountDownLatch`、`ReentrantLock`结合`Condition`以及`LockSupport`等工具。全文旨在帮助读者理解线程管理的核心概念和技术细节。
18 1
[Java]线程生命周期与线程通信
|
2天前
|
安全 Java
在 Java 中使用实现 Runnable 接口的方式创建线程
【10月更文挑战第22天】通过以上内容的介绍,相信你已经对在 Java 中如何使用实现 Runnable 接口的方式创建线程有了更深入的了解。在实际应用中,需要根据具体的需求和场景,合理选择线程创建方式,并注意线程安全、同步、通信等相关问题,以确保程序的正确性和稳定性。
|
1天前
|
缓存 Java 调度
Java中的多线程编程:从基础到实践
【10月更文挑战第24天】 本文旨在为读者提供一个关于Java多线程编程的全面指南。我们将从多线程的基本概念开始,逐步深入到Java中实现多线程的方法,包括继承Thread类、实现Runnable接口以及使用Executor框架。此外,我们还将探讨多线程编程中的常见问题和最佳实践,帮助读者在实际项目中更好地应用多线程技术。
8 3