【问题标题】:Kotlin optional parameter with Java backwards compatibility具有 Java 向后兼容性的 Kotlin 可选参数
【发布时间】:2020-07-03 10:29:08
【问题描述】:

我目前正在编写一个 Kotlin 库,其对象具有多个需要多个可选参数的方法。由于在 JAVA 中您需要将 null 传递给这些参数,我认为这有点不舒服。重载也不是解决方案,因为我不一定知道可能的组合,或者有很多可能性的方法。

class MyObj() {
    fun method1(param1: Int, param2: String? = null, param3: Int? = null): String { ... }
    fun method2(param1: Int, param2: Float? = null, param3: String? = null): Any { ... }
    fun method5(param1: Int, ...): User { ... }
}

在 Kotlin 中我可以简单地写:

myObj = MyObj()
myObj.method1(param1 = 4711, param3 = 8850)

在 Java 中我需要编写:

MyObj myObj = new MyObj()
myObj.method1(4711, null, 8850)
...    
myObj.method5("abc", null, null, null, null, 8850, null, null, "def")

因为我有很多方法和很多可选参数,所以我考虑只为每个方法传递一个类:

/** For JAVA backwards compatibility */
class Method1(
    val param1: Int
) {
    param2: String? = null
    param3: Int? = null

    fun withParam2(value: String) = apply { param2 = value }
    fun withParam3(value: Int) = apply { param3 = value }
}

class MyObj() {
    fun method1(param1: Int, param2: String? = null, param3: Int? = null): String { ... }
    
    /** For JAVA backwards compatibility */
    fun method1(values: Method1) = method1(values.param1, values.param2, values.param3)
}

所以在 Kotlin 中我可以使用命名参数,而在 Java 中我可以简单地编写:

MyObj myObj = new MyObj()
myObj.method1(new Method1(4711).withParam3(8850))

在我看来,它看起来相当丑陋,因为我总是不得不说method1(new Method1())method2(new Method2())您认为还有更优雅的版本吗?

背景:这是为了调用带有大量可选参数的 REST API。

【问题讨论】:

  • 为了更好地理解,在构造函数中传递null 有什么不便?因为除非设置了属性,否则构建器也会保留属性null
  • 这不是很不方便,只是我不喜欢它的外观:)...

标签: java kotlin optional optional-parameters backwards-compatibility


【解决方案1】:

你可以为函数添加@JvmOverloads注解

【讨论】:

    【解决方案2】:

    对于 Java,处理大量可选参数的最佳方法通常是通过某种形式的构建器模式。我会建议以下两种变体之一:

    1:返回一个可链接的对象,并在最后有某种“运行”方法来获取提供的参数并运行实际方法。

    myObj.retrieveWhatever().from("abc").where(LESS_THAN, 3).setAsync(true).run();
    

    2:对于 Java 8+,执行相同操作,但在 lambda 中:

    myObj.retrieveWhatever(args -> 
        args.from("abc").where(LESS_THAN, 3).setAsync(true)
    );
    

    ...或者,可选地

    myObj.retrieveWhatever(args -> {
        args.from("abc");
        args.where(LESS_THAN, 3);
        args.setAsync(true);
    });
    

    通过在 lambda 中执行此操作,您可以消除最后忘记 .run() 调用的风险。

    【讨论】:

    • 谢谢,我现在就是这样做的。关于你答案的第二部分的问题。在 JAVA 中使用 lambda 方法需要做什么?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-01
    相关资源
    最近更新 更多