我在学习Kotlin .

object CustomDuplicateId : RuntimeException("Invalid user with Id")
class CustomDuplicateId : RuntimeException("Invalid user with Id")

如果我只在一个位置使用这个异常,那么stacktrace总是相同的.

还是使用单例异常不好?

有人能告诉我写异常的更好的代码吗?

推荐答案

使用object是不正确的原因有很多.

  1. stacktrace在几个方面都是错误的:

    • 它是在实例化时创建的,因此您将在stacktrace中看到<clinit>作为第一行,因为它是在首次初始化对象的类时创建的
    • 即使从同一个地方抛出,当从同一个调用者调用时也不一定会抛出,因此如果在应用程序的整个生命周期中多次抛出此异常,stacktrace的底部(根)将不正确
  2. 从技术上讲,exception类有可变的部分,允许用户代码对其进行篡改是危险的/不正确的.一个非常具体的例子是,用户代码可以向您的异常实例中添加suppressed exceptions个异常实例(该异常实例只对一次抛出有效,但仍会保留在您的对象中).严格来说,这是内存泄漏.

  3. 您可能需要不同的消息,其中包含有关抛出原因的更多信息(在这种情况下,非常需要重复的ID),因此您仍然需要具有不同数据的不同实例

  4. 将来你可能会从不同的地方扔掉它(即使是现在在测试/模拟中可能也是如此?),如果是那样的话,stacktrace就更加错误了

  5. 与上述技术细节无关,class vs object也向读者发送了一条有点不清楚的信息——为什么这里是object?这一例外并非天生独特.碰巧你现在把它扔到一个特定的地方,并且依赖于stacktrace是相同的.

以下是主要问题(#1)的一个例子:

object MyExceptionObject : RuntimeException("boom")

fun main() {
    try {
        caller1() // line 7
    } catch (e: Exception) {
    }
    caller2() // line 10
}

fun caller1() = doStuff() // line 13
fun caller2() = doStuff() // line 14

fun doStuff() {
    throw MyExceptionObject // line 17
}

caller1()抛出异常,但该异常被捕获.caller2()再次抛出异常,但该异常未被捕获.我们为未捕获异常获取的stacktrace错误地显示了调用者1(第7行和第13行),但正确的应该是调用者2(第10行和第14行):

Exception in thread "main" com.example.MyExceptionObject: boom
    at com.example.MyExceptionObject.<clinit>(ExceptionObjectExample.kt)
    at com.example.ExceptionObjectExampleKt.doStuff(ExceptionObjectExample.kt:17)
    at com.example.ExceptionObjectExampleKt.caller1(ExceptionObjectExample.kt:13)
    at com.example.ExceptionObjectExampleKt.main(ExceptionObjectExample.kt:7)
    at com.example.ExceptionObjectExampleKt.main(ExceptionObjectExample.kt)

总之,只需使用一个类.

Kotlin相关问答推荐

在Kotlin中将ClosedRange字符串转换为List?<>

如何在Kotlin中为接受varargs的函数添加带有默认值的新参数?

如何在Docker中使用Selenium和chromedriver?

为什么 Kotlin 中没有 init 块的注释

kotlin中如何使用子类调用父静态方法?

为什么使用 return instance ?: synchronized(this) { instance ?: PreferenceParameterState(context) } 时无法获得单例?

按钮无法在 Android Studio 上打开新活动

返回 kotlin 中的标签和 lambda 表达式

如何在 Kotlin 中将with代码转换为完整代码?

为什么 KFunction2 在 Kotlin 中不是可表示类型?

JavaFX - 你如何在 Kotlin 中使用 MapValueFactory?

OnClickListener 未在 ConstraintLayout 上触发

Kotlin - 当表达式返回函数类型

在 Kotlin 中,当枚举类实现接口时,如何解决继承的声明冲突?

调用单元测试验证伴随对象方法

Jetpack Compose State:修改类属性

如何捕获传递给模拟函数的参数并返回它?

Lint 错误:可疑的相等判断:在 Object DiffUtilEquals 中未实现 equals()

我应该使用Kotlin数据类作为JPA实体吗?

递归方法调用在 kotlin 中导致 StackOverFlowError 但在 java 中没有