具有 Java 向后兼容性的 Kotlin 可选参数
Kotlin optional parameter with Java backwards compatibility
我目前正在编写一个 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")
因为我有很多方法和很多选项,所以我考虑过为每个方法传递一个 class:
/** 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 接受大量可选参数。
对于 Java,处理大量可选参数的最佳方法通常是通过某种形式的构建器模式。我会建议两种变体之一:
1:Return 一个可链接的对象,并在末尾有某种“运行”方法来获取提供的参数和 运行 实际方法。
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()
的风险。
您可以只为函数添加 @JvmOverloads
注释
我目前正在编写一个 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")
因为我有很多方法和很多选项,所以我考虑过为每个方法传递一个 class:
/** 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 接受大量可选参数。
对于 Java,处理大量可选参数的最佳方法通常是通过某种形式的构建器模式。我会建议两种变体之一:
1:Return 一个可链接的对象,并在末尾有某种“运行”方法来获取提供的参数和 运行 实际方法。
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()
的风险。
您可以只为函数添加 @JvmOverloads
注释