首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >你有没有掉进去过这些 Exception 的“陷阱“(Part C)

你有没有掉进去过这些 Exception 的“陷阱“(Part C)

作者头像
RiemannHypothesis
发布于 2022-08-19 08:41:31
发布于 2022-08-19 08:41:31
32800
代码可运行
举报
文章被收录于专栏:ElixirElixir
运行总次数:0
代码可运行

七、除了NullPointException外的其他常见异常

ConcurrentModificationException

在test包中新增测试类ConcurrentModificationExceptionTest

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ConcurrentModificationExceptionTest {

    List<User> userList = new ArrayList<>();

    @Before
    public void before() {

        User stark = new User();
        stark.setName("stark");
        User thor = new User();
        thor.setName("thor");
        userList.add(stark);
        userList.add(thor);
    }

    @Test
    public void testModifyWhileIteratoringByFor(){

        // 直接使用for循环,触发并发修改异常
        for (User user : userList) {
            if (user.getName().equals("thor")){
                userList.remove(user);
            }
        }
    }
}

在使用for循环进行遍历集合同时将符合条件的元素移出集合会报并发修改异常,也就是触发了Java中的fail-fast机制。

fail-fast 机制是 java 集合(Collection)中的一种错误机制。 当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。例如:当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件。

要解决并发修改异常,可以使用迭代器进行遍历。增加测试方法testModifyWhileIteratoringByIterator()

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Test
public void testModifyWhileIteratoringByIterator(){

    // 直接使用迭代器
    Iterator<User> iter = userList.iterator();
    while (iter.hasNext()){
        User user = iter.next();
        if (user.getName() == "thor"){
            iter.remove();
        }
    }
}

next()方法一定在remove()方法之前调用,方法执行没有任何异常,虽然迭代器能够避免并发修改异常的问题,但是最好不要在遍历中删除

ClassCastException

在entity包中定义两个User的子类Admin和Employee

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Admin extends User {
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Employee extends User {
}

在test包下新增测试类ClassCastExceptionTest

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ClassCastExceptionTest {
    
    User employee = new Employee();

    @Test
    public void testCastWithDifferentClass(){
        // 子类之间转换
        Admin admin = (Admin) employee;
    }
}

两个子类之间是没有继承关系的,子类之间直接转换会抛出类型转换异常的错误,解决这类问题可以先进行类型关系判断,通过getClass().getName()来得到具体类型,再通过instanceof进行判断是否含有继承关系,如果有继承关系再进行类型转换,否则无法进行类型转换

IllegalArgumentException

日期转换时的非法参数异常

在日期转换时,如果传入的参数不对也会报错非法参数异常

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Test
public void testUser(){
    Date date = new Date();
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String simpleDate = simpleDateFormat.format(date);
    System.out.println(simpleDate);

    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM");
    String format = dateFormat.format("");
    System.out.println(format);
}

format()函数的参数是一个Object类型,所以传入String类型时不会报编译错误,但是运行时会出现IllegalArgumentException的异常

枚举查找时的非法参数异常

新建一个enums包,增加一个枚举类LoginErrorEnum,包含了三个枚举值

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public enum LoginErrorEnum {
    USERNAME_OR_PASSWORD_NOT_CORRECT,
    NOT_ADMIN_ROLE,
    USERNAME_NOT_REGISTER,
}

在test包下新增IllegalArgumentExceptionTest,测试查找一个不存在的枚举值

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class IllegalArgumentExceptionTest {

    @Test
    public void testGetValueFromEnum(){
        LoginErrorEnum passwordNotCorrect = LoginErrorEnum.valueOf("PASSWORD_NOT_CORRECT");
        System.out.println(passwordNotCorrect);
    }

}
枚举查找异常解决方案

第一种方式是使用try-catch这种比较通用的方式来解决枚举查找异常

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Test
public void testGetValueFromEnum(){
    try {
        LoginErrorEnum passwordNotCorrect = LoginErrorEnum.valueOf("PASSWORD_NOT_CORRECT");
        System.out.println(passwordNotCorrect);
    } catch (IllegalArgumentException e){
        System.out.println(e.getMessage());
    }
}

当要查找的枚举值不存在时,直接在控制台输出异常信息

第二种方式可以使用for循环遍历的方式,遍历所有的枚举值,查看是否有符合条件的枚举值,但是for循环效率较低

第三种方式可以使用Guava,首先在pom.xml文件中导入guava依赖

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>12.0</version>
</dependency>

新增测试方法testGetValueFromEnumWithGuava

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Test
public void testGetValueFromEnumWithGuava(){

    System.out.println(Enums.getIfPresent(LoginErrorEnum.class, "PASSWORD_NOT_CORRECT").orNull());
}

控制台输出为null,避免了非法参数异常

八、 资源关闭

资源以及资源泄露

资源有哪些?

资源在使用过之后要进行关闭或者释放,如果没有释放怎会导致资源泄露的问题

try finally 关闭资源的问题

新增一个测试类HandlerResoucesTest,使用try-catch-finally关闭单个资源的代码如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Test
public void testCloseSingleByTryCatchFinally() throws IOException {
    String context = null;
    BufferedReader bufferedReader = new BufferedReader(new FileReader("info.txt"));
    try {
        context = bufferedReader.readLine();
        System.out.println(context);
    } catch (Exception e){
        System.out.println(e.getMessage());
    } finally {
        bufferedReader.close();
    }
}

finally代码块中的代码无论是否出现异常都会执行,因此将资源关闭的代码放在finally中,确保操作结束后关闭资源

当try代码块中又包含另外一个资源的读取的时候,代码会变成这样

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Test
public void testCloseMultiByTryCatchFinally() throws IOException{
    String context = null;
    String message = null;
    BufferedReader bufferedReader = new BufferedReader(new FileReader("info.txt"));
    try {
        context = bufferedReader.readLine();
        BufferedReader messBufferedReader = new BufferedReader(new FileReader("message.txt"));
        try {
            message = messBufferedReader.readLine();
            System.out.println(message);
        } catch (Exception e){
            System.out.println(e.getMessage());
        } finally {
            messBufferedReader.close();
        }
        System.out.println(context);
    } catch (Exception e){
        System.out.println(e.getMessage());
    } finally {
        bufferedReader.close();
    }
}

使用try-catch关闭多个资源时代码冗长且不易阅读

try-with-resources 解决资源泄露隐患

try-with-resources只需要声明和使用,不需要考虑关闭的问题,在try关键字后面的括号中里new一些需要自动关闭的资源。

BufferedRead从java 7开始就实现了 AutoCloseable 接口,无论try-with关闭资源是正常关闭还是异常关闭,autoClose都能关闭他们

关闭单个资源的代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Test
public void testCloseSingleByTryWithResources() throws IOException {
    try(BufferedReader reader = new BufferedReader(new FileReader("info.txt"))){
        System.out.println(reader.readLine());
    }
}

关闭多个资源的代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Test
public void testCloseMultiByTryWithResources() throws IOException{
    try(FileInputStream inputStream = new FileInputStream("info.txt");
        FileOutputStream outputStream  = new FileOutputStream("message.txt")) {
         byte[] buffer = new byte[100];
         int n = 0;
         while ((n = inputStream.read(buffer)) != -1){
             outputStream.write(buffer, 0, n);
         }
    }
}

异常被覆盖的情况

如果try finally都抛出异常,finally中抛出的异常会抑制try中的异常,导致很难发现最初的异常。

在exceptions包中自定义一个异常

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class LiException extends Exception {

    public LiException() {
        super();
    }

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

定义一个类实现AutoCloseable接口实现AutoCloseable接口,这个接口可以被try-with-resource自动关闭掉

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class LilithAutoCloseable implements AutoCloseable {


    @Override
    public void close() throws Exception {
        System.out.println("close()方法被调用");
        throw new RuntimeException("close()方法中抛出的异常");
    }

    public void work() throws LiException{
        System.out.println("work()方法被调用");
        throw new LiException("work()方法中抛出的异常");
    }
}

增加测试方法testCloseWithAutoCloseable()

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Test
public void testCloseWithAutoCloseable() throws Exception {

    LilithAutoCloseable lilithAutoCloseable = new LilithAutoCloseable();
    try {
        lilithAutoCloseable.work();
    } finally {
        lilithAutoCloseable.close();
    }
}

work()方法中的异常被finally中的close()方法的异常覆盖掉了

使用try-with-resources则不会出现这中问题

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Test
public void testCloseWithAutoCloseableByTryWith() throws Exception {

    try(LilithAutoCloseable lilithAutoCloseable = new LilithAutoCloseable()) {
        lilithAutoCloseable.work();
    }

}

work()方法和close()方法抛出的异常都被展示出来了

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-05-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
如何在mac上录屏(并且录制到屏幕内部声音)完美解决方案
一直想找一款在mac录屏的软件,直到今天才有了完美的解决方案,总所周知,mac上有自带的录屏软件(quicktime player),这款软件简单,但是因为其不能录制屏幕内部的声音而不被新手使用。而其他录屏软件大部分需要付款,大部分开源的也不能录制屏幕内部的声音。
全栈程序员站长
2022/07/01
6.2K0
如何在mac上录屏(并且录制到屏幕内部声音)完美解决方案
MacBook 屏幕录制 soundflower 只录内屏声音 无外界声音
(博客诈尸,感觉要弃了,到时候开github主页) (搜到的一些soundflower教程都好旧, 自己写一个)
全栈程序员站长
2022/08/15
3.1K0
MacBook 屏幕录制 soundflower 只录内屏声音 无外界声音
SoundFlower+QuickTime录屏Mac含系统声音[通俗易懂]
Mac自带的录屏软件QuickTime不能录系统声音。为此,使用soundflower插件来解决。其原理是添加虚拟声卡,使系统声音输出到该声卡,再将其作为QuickTime录屏的输入。
全栈程序员站长
2022/09/05
1.8K0
Mac录屏同时录制系统声音和画外音(Soundflower无法安装解决方案)「建议收藏」
以前一直有录屏的需求,但苦于自带的QuickTime 无法录制内屏声音,一直使用的是第三方的app。近期开腾讯会议需要录屏,但主持人本身没有开启录屏权限,只好通过我本机端进行录制。然后我使用的第三方app虽然能录制系统声音,但无法录制腾讯会议的声音,录了一个半小时竟然是哑剧!一怒之下删掉了原来的那个app,重新探寻QuickTime录屏之路。
全栈程序员站长
2022/06/27
1.7K0
Mac录屏同时录制系统声音和画外音(Soundflower无法安装解决方案)「建议收藏」
mac如何同时录制系统和麦克风声音或只录制系统声音
推荐直接appstore下载record it,然后打开软件根据软件提示安装blackhole插件。 之后就可以关掉该软件了,不用升级会员,以后我们录屏可以不再打开该软件了。 到录屏的时候先调整好扬声器或耳机的音量大小,因为之后是不能调的。
全栈程序员站长
2022/08/24
3.8K0
mac如何同时录制系统和麦克风声音或只录制系统声音
Mac Quicktime 录屏带声音[通俗易懂]
最近有录屏的需求,但是 Mac 大多数录屏软件都收费,之前用 Windows 时用 EV 录屏,免费好用,可惜没有 Mac 版。
全栈程序员站长
2022/08/18
1.7K0
Mac Quicktime 录屏带声音[通俗易懂]
Mac用QuickTime录屏+soundflower录制屏内外声音
mac自带的quickTime录屏没有声音,可以安装soundflower录制屏内外声音。
全栈程序员站长
2022/09/05
1.6K0
Mac用QuickTime录屏+soundflower录制屏内外声音
Mac录屏,同时保留声音[通俗易懂]
1.先装Soundflower: Soundflower下载地址 http://pan.baidu.com/s/1jH9r6iM
全栈程序员站长
2022/08/13
2.4K0
Mac录屏,同时保留声音[通俗易懂]
【技巧帖】关于Mac如何内录电脑内部声音[通俗易懂]
参考视频: mac苹果电脑如何录制声音_哔哩哔哩_bilibili
全栈程序员站长
2022/08/12
1.9K0
如何用 QuickTime 对 Mac 屏幕录制,而且录上声音?
参考地址:https://www.zhihu.com/question/26032781
用户7798898
2020/09/27
1.6K0
如何用 QuickTime 对 Mac 屏幕录制,而且录上声音?
mac OS 10.15 catalina内录声音同时使用quicktime录屏教程
更新:安装hijack吧,这个效率更高,支持多个软件混合录制声音 https://rogueamoeba.com/audiohijack/ 首先安装BlackHole https://github.com/ExistentialAudio/BlackHole 其次根据这个教程在MIDI里面设置多输出设备 https://github.com/ExistentialAudio/BlackHole/wiki/Multi-Output-Device
全栈程序员站长
2022/08/31
5480
如何白嫖微软的文本转语音
你好,我是征哥,之前分享过微软的文本转语音服务,已经听不出是机器了,很多人惊叹于它的强大,希望能把自己的文字转成语音,做为视频或文章的配音,今天就来分享如何白嫖微软的文本转语音。
somenzz
2022/05/24
3.4K0
如何白嫖微软的文本转语音
升级Mac Catalina后OBS录屏软件麦克风和内置声音输出没有声音的问题[通俗易懂]
升级Mac Catalina后,OBS录屏软件录制的视频,电脑内置声音输出,以及麦克风输入声音都没有。使用网上搜到的soundflower工具也不行。后来找到如下命令临时解决。
全栈程序员站长
2022/08/28
1.2K0
python-声音录制和处理
用sounddevice包播放音乐直接调用play函数来播放声音,需要传入需要播放声音的波形,和采样率。
用户9925864
2022/07/27
1.2K0
python-声音录制和处理
obs录制黑屏怎么解决_obs窗口捕获黑屏
打开OBS后,新建场景、新建显示器捕获后,黑屏没有显示,即使点击开始录制,然后结束录制后,录制的视频仍然是黑屏。
全栈程序员站长
2022/08/03
6.4K0
obs录制黑屏怎么解决_obs窗口捕获黑屏
Mac录屏软件:Record It[通俗易懂]
Record It 是一款屏幕录制应用软件,支持录制屏幕和录制声音,让您能够精准,高质量地捕获屏幕上所有的活动。 Record It 支持制作专业的应用软件演示,录制在线视频,ppt 和图片幻灯片,制作指导教程等。同时录制来自系统声音或麦克风的声音。
全栈程序员站长
2022/09/30
4.6K0
Mac录屏软件:Record It[通俗易懂]
Linux音频驱动-OSS和ALSA声音系统简介及其比较
概述 昨天想在Ubuntu上用一下HTK工具包来绘制语音信号的频谱图和提取MFCC的结果,但由于前段时间把Ubuntu升级到13.04,系统的声卡驱动是ALSA(Advanced Linux Soun
DragonKingZhu
2020/03/24
5.9K0
如何解决录音嗡嗡嗡?VoiceMeeter加OBS免费且强大的录音录像解决方案
前段时间,我买了一个铁三角的收音麦克,但每次录音都嗡嗡嗡,让我一度怀疑设备是否有问题,直到我玩懂了VoiceMeeter,才意识到我的声音被采集了两次,并叠加成了输出,所以产生了嗡嗡嗡的效果。如果你的收音麦克也有嗡嗡嗡的收音效果,可以按照本文的方法,重新调试一下设备,没准儿你的声音录出来很动听呢~
zhaoolee
2021/03/02
4.1K0
如何解决录音嗡嗡嗡?VoiceMeeter加OBS免费且强大的录音录像解决方案
腾讯实时音视频 分享系统声音
什么是分享系统声音?举个例子,如果你常关注游戏直播,那这种直播方式你一定不陌生,直播中不仅可以看到主播当前屏幕所展示的画面,也能听到主播的声音和游戏的声音,简单分析一下功能点:
zqh
2021/12/09
2.8K0
ScreenToGIF录像没有声音_录屏怎么变成gif
今天意外地发现了两款非常不错的电脑录屏软件,整个软件体积小巧、操作简单,最为难得的是,录制的视频内容特别清晰,这里推荐给大家吧。
全栈程序员站长
2022/11/08
1.7K0
ScreenToGIF录像没有声音_录屏怎么变成gif
推荐阅读
相关推荐
如何在mac上录屏(并且录制到屏幕内部声音)完美解决方案
更多 >
LV.0
这个人很懒,什么都没有留下~
目录
  • 七、除了NullPointException外的其他常见异常
    • ConcurrentModificationException
    • ClassCastException
    • IllegalArgumentException
      • 日期转换时的非法参数异常
      • 枚举查找时的非法参数异常
  • 八、 资源关闭
    • 资源以及资源泄露
    • try finally 关闭资源的问题
    • try-with-resources 解决资源泄露隐患
    • 异常被覆盖的情况
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档