You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何两段Scala类初始化时的异常抛出行为存在差异?

两段代码异常抛出时机差异的核心原因

1. 第一段代码初始化即抛异常的逻辑

Scala类的普通val成员会在类实例初始化阶段同步完成赋值表达式的计算:

  • 第一段代码中att的赋值表达式本身就是throw new Exception(""),执行new Test()初始化实例时会直接运行该表达式,所以会立即抛出异常。

2. 第二段代码访问属性才抛异常的逻辑

差异的核心是Scala标准库中Map.mapValues的惰性求值特性:

mapValues方法默认返回的是惰性视图类型,不会立即执行传入的转换逻辑,只有在实际访问Map中存储的value时,才会触发转换函数的计算。

对应代码的执行流程:

  • 你传入mapValues的throw new Exception("")会被自动适配为忽略输入参数的转换函数_ => throw new Exception(""),完全符合mapValues要求的函数签名。
  • 类初始化阶段只会完成Seq((1, "a")).groupBy(_._1)的计算,mapValues仅会包装生成一个惰性视图对象,不会执行你传入的抛异常的转换逻辑,所以new Test()不会触发异常。
  • 只有当你访问att属性的具体值时,惰性视图才会触发转换函数的执行,抛出异常。

简易验证

将mapValues替换为严格求值的map实现,初始化阶段就会直接抛异常:

class Test {
  val att = Seq((1, "a")).groupBy(_._1).map { case (k, v) => k -> throw new Exception("") }
}
new Test() // 初始化直接抛出异常

内容的提问来源于stack exchange,提问作者Prassi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 19:06:02