业务异常派生自RuntimeException才是最合理的.
BL不应该强加给调用者任何东西, 使用CheckedException或ErrorCode都是对接口的污染.
只有"感兴趣"或者"知道如何处理"的caller才有必要去捕捉相关的异常. 无法处理的就让他bubble up吧, 如果不想让线程down掉就在应用层统一捕捉.
至于性能, try/catch本身并没有多少overhead, 直道异常抛出回溯. 异常之所以叫异常, 就是因为发生频率低, 如果捕捉异常频繁到了成为bottleneck的地步, 只能说这个BL有问题了. 可能把异常用于流程控制去了.
最后, client如何调用. 我觉的一个纯粹的业务逻辑模型肯定是和client无关的. 异常信息如何到达远程client, 那是web层应该考虑的问题. 而不是bl层.