业务异常派生自RuntimeException才是最合理的.
BL不应该强加给调用者任何东西, 使用CheckedException或ErrorCode都是对接口的污染.
只有"感兴趣"或者"知道如何处理"的caller才有必要去捕捉相关的异常. 无法处理的就让他bubble up吧, 如果不想让线程down掉就在应用层统一捕捉.

至于性能, try/catch本身并没有多少overhead, 直道异常抛出回溯. 异常之所以叫异常, 就是因为发生频率低, 如果捕捉异常频繁到了成为bottleneck的地步, 只能说这个BL有问题了. 可能把异常用于流程控制去了.

最后, client如何调用. 我觉的一个纯粹的业务逻辑模型肯定是和client无关的. 异常信息如何到达远程client, 那是web层应该考虑的问题. 而不是bl层.

异常是指,不寻常,逻辑中不可估计的或不存在的概念,如Null异常,跟逻辑无关一样。

基于你这个bussiness,返回值问题可参考scala的Option这方面的理解。

你属于逻辑上处理成功失败,我倾向于第一种。

实际上,引起大家更多选择第二种的更多的是处理方便,特别是runtime类异常。但大家都忘记了逻辑上,成功或失败实际是状态机处理,用语句表达就是data result = Success a | Fail str,成功与失败的传递就如同 true与false的值(或状态)传递。有人说成功是返回期望类型,但失败返回的str却可能在期望类型以外,这是一种设计错误,这是由于设计返回期望类型时,就认定:这一定会成功。但事实在逻辑上,这是会失败的,这是在设计逻辑时产生的悖论。