异常 try – finally 注意的地方

本文详细介绍了Java中finally语句的作用及使用方式。finally块无论是否有异常发生都会被执行,常用于资源清理。文章还讨论了finally中return语句的影响及其与异常处理的关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


finally

异常机制中还有一个重要的部分,就是finally, catch后面可以跟finally语句,语法如下所示:

复制代码
 
try{
    //可能抛出异常
}catch(Exception e){
    //捕获异常
}finally{
    //不管有无异常都执行
}
 
复制代码

finally内的代码不管有无异常发生,都会执行。具体来说:

  • 如果没有异常发生,在try内的代码执行结束后执行。
  • 如果有异常发生且被catch捕获,在catch内的代码执行结束后执行
  • 如果有异常发生但没被捕获,则在异常被抛给上层之前执行。

由于finally的这个特点,它一般用于释放资源,如数据库连接、文件流等。

try/catch/finally语法中,catch不是必需的,也就是可以只有try/finally,表示不捕获异常,异常自动向上传递,但finally中的代码在异常发生后也执行。

finally语句有一个执行细节,如果在try或者catch语句内有return语句,则return语句在finally语句执行结束后才执行,但finally并不能改变返回值,我们来看下代码:

复制代码
 
public static int test(){
    int ret = 0;
    try{
        return ret;
    }finally{
        ret = 2;
    }
}
 
复制代码

这个函数的返回值是0,而不是2,实际执行过程是,在执行到try内的return ret;语句前,会先将返回值ret保存在一个临时变量中,然后才执行finally语句,最后try再返回那个临时变量,finally中对ret的修改不会被返回。

如果在finally中也有return语句呢?try和catch内的return会丢失,实际会返回finally中的返回值。finally中有return不仅会覆盖try和catch内的返回值,还会掩盖try和catch内的异常,就像异常没有发生一样,比如说:

复制代码
 
public static int test(){
    int ret = 0;
    try{
        int a = 5/0;
        return ret;
    }finally{
        return 2;
    }
}
 
复制代码

以上代码中,5/0会触发ArithmeticException,但是finally中有return语句,这个方法就会返回2,而不再向上传递异常了。

finally中不仅return语句会掩盖异常,如果finally中抛出了异常,则原异常就会被掩盖,看下面代码:

复制代码
 
public static void test(){
    try{
        int a = 5/0;
    }finally{
        throw new RuntimeException("hello");
    }
}
 
复制代码

finally中抛出了RuntimeException,则原异常ArithmeticException就丢失了。

所以,一般而言,为避免混淆,应该避免在finally中使用return语句或者抛出异常,如果调用的其他代码可能抛出异常,则应该捕获异常并进行处理。

### 黑马点评订单处理中的异常解决方案 为了有效解决黑马点评系统中订单处理过程中可能出现的异常问题,特别是针对多线程环境下的并发安全性以及库存超卖等问题,以下是详细的分析与解决方案。 #### 并发安全的核心问题 在分布式环境下,当多个用户尝试购买同一商品时,可能会因为高并发而导致重复下单或者库存超卖的情况发生。具体来说,在判断用户是否已下单和实际创建订单的过程中存在时间间隙,这使得其他线程可能在此期间介入并执行相同的操作[^1]。 #### 解决方案概述 通过引入悲观锁机制来保障数据库层面的数据一致性,从而实现对资源的有效控制。此外还可以考虑利用Redis等缓存工具作为辅助手段提升性能的同时也加强系统的健壮性。 ##### 数据库层面上的应用 - 悲观锁 对于需要严格保证事务隔离级别的场景比如本案例中的防止重复下单功能, 可以采用SELECT...FOR UPDATE语句来进行行级锁定。这样可以在事务提交前阻止其它事务对该记录做任何修改直至当前事务完成为止[^3]。 ```sql BEGIN; -- 查询是否存在该用户的此优惠券订单,并加锁 SELECT * FROM orders WHERE user_id=? AND coupon_id=? FOR UPDATE; -- 如果不存在则插入新订单 INSERT INTO orders(user_id,coupon_id,...) VALUES(?,?,...) COMMIT; ``` 上述SQL片段展示了如何在一个事务内部先查找出特定条件下的订单条目并对它们施加重读保护(即行锁),之后再决定是否继续新增一条新的订单记录。整个过程都包裹在一个显式的事务里头确保要么全部成功要么完全回滚没有任何中间状态残留下来影响后续业务程正常运转。 ##### 缓存优化策略 – Redis分布式锁 除了依靠关系型数据库自带的功能外,也可以借助像Redis这样的内存存储服务构建更高效的全局同步机制。例如使用SETNX命令配合EXPIRE设置有效期的方式来模拟信号量行为达到互斥访问的目的;或者是直接运用Redlock算法提供更强一致性的跨节点协调能力[^2]。 ```python import redis r = redis.Redis(host='localhost', port=6379) def acquire_lock(lock_name, timeout=10): identifier = str(uuid.uuid4()) end_time = time.time() + timeout while time.time() < end_time: if r.setnx(lock_name, identifier): # 尝试获取锁 r.expire(lock_name, int(timeout)) # 设置过期时间防死锁 return identifier time.sleep(.001) # 短暂休眠减少CPU占用率 raise Exception("Timeout acquiring lock") try: lock_identifier = acquire_lock('order_creation') # 执行核心业务逻辑... finally: if lock_identifier and r.get('order_creation') == lock_identifier: r.delete('order_creation') # 清理自己的锁 ``` 以上Python代码示范了怎样基于Redis实现简单的分布式锁管理器。它首先定义了一个`acquire_lock()`函数用于请求指定名称的独占权限直到获得或是超出预设时限抛出错误终止程序运行。接着无论成功与否都会进入最后阶段释放所持有的资源以便让等待队列里的下一个成员有机会取得机会去操作共享对象。 #### 总结 综上所述,为了解决黑马点评项目中存在的订单处理异常现象,可以从以下几个方面入手改进现有架构设计: - **增强数据库事务支持**:合理应用悲观锁技术规避因竞态条件引发的一致性破坏风险; - **引入外部组件协助调控量高峰压力**:如选用具备高性能特性的NoSQL产品充当临时缓冲池角色分担主干链路负载负担同时简化开发难度加快上线速度。 这些措施共同作用能够显著提高电子商务平台面对突发状况时候的表现水平进而赢得更多忠实顾客群体的认可和支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值