Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin optional parameter with Java backwards compatibility

I'm currently writing a Kotlin library with an object having multiple methods requirering multiple optional parameters. Since in JAVA you would require to pass null to those parameters I think this is kind of unconfortable. Also overloading is not an solution as I don't know the possible combinations necessarily or there are ways to many possibilities.

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 { ... }
}

In Kotlin I can simply write:

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

In Java I need to write:

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

Since I have quite a lot of methods with a lot of optionals I thought about just passing a class for each method:

/** 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)
}

So in Kotlin I can used named parameters and in Java I could simply write:

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

From my point of view it looks fairly ugly because I always have to say method1(new Method1()) or method2(new Method2()). Do you think there is a more elegant version of this?

Background: This is for calling a REST API taking lots of optional parameters.

like image 423
tekgator Avatar asked Apr 25 '26 10:04

tekgator


2 Answers

You can just add @JvmOverloads annotation for the functions

like image 109
Raghu Krishnan R Avatar answered Apr 27 '26 14:04

Raghu Krishnan R


For Java, the best way to handle a large amount of optional arguments is typically by some form of builder pattern. I would suggest one of two variants:

1: Return a chainable object and have some sort of "run" method at the end to take the provided arguments and run the actual method.

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

2: For Java 8+, do the same, but in a lambda:

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

...or, alternatively

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

By doing it in a lambda, you remove the risk of forgetting the .run() call at the end.

like image 31
BambooleanLogic Avatar answered Apr 27 '26 14:04

BambooleanLogic