Tengo una biblioteca que está completamente escrito en Kotlin incluyendo su API pública. Ahora, un usuario de la biblioteca utiliza Java, el problema aquí es que Kotlin Lambdas con el tipo de retorno Unit
no se compilan al tipo de retorno void
. El efecto es que el lado de Java siempre tiene que volver Unit.INSTANCE
a métodos que son effectivly void
. Se puede evitar de alguna manera?
Ejemplo:
Kotlin Lambda
interface Foo{
fun bar(x:(String)->Unit)
}
llamada Java
public void call(){
foo.bar(this::processString)
}
//the return type should rather be void instead of Unit
public Unit processString(String s){
return Unit.INSTANCE
// ^^ implementations should not be forced to return anything
}
¿Es posible declarar la Kotlin Lambda de forma diferente por lo que el compilador genera un void
tipo de retorno?
véase también la forma de declarar una función Kotlin con el tipo de retorno 'vacío' para una persona que llama java?
No tengo una respuesta real a esto, pero voy a compartir, lo que hice en una situación de este tipo en el que necesitaba para acceder a dicha Kotlin código de Java (o lo que ha venido a la mente).
Básicamente depende de qué lado realmente desea tocar / mejorar sólo para obtener lo que necesita.
La mejora del código Kotlin para apoyar a los equivalentes de Java:
interface Foo {
fun bar(x : (String) -> Unit)
/* the following is only here for Java */
@JvmDefault // this requires that you add -Xjvm-default=enable to your compiler flags!
fun bar(x:Consumer<String>) = bar(x::accept)
}
Esto tiene algunos inconvenientes: la Consumer
-method es visible desde Kotlin también y por lo tanto también se puede llamar desde allí es. Ni que decir tiene, que es necesario duplicar todas las funciones de las interfaces y por lo tanto sus enteros Kotlin interfaces acaba de obtener más hinchado. Pero: funciona de ambos lados de la manera que cabría esperar. Java llama la Consumer
-variant, Kotlin llama al (String) -> Unit
-variant ... espero ;-) en realidad sólo demos algunas llamadas:
// from Java:
..bar(s -> { System.out.println(s); })
// however, method references might not work that easily or not without a workaround...
..bar((Consumer<String>) System.out::println); // not nice... @JvmName("kotlinsBar") to the rescue? well... that will just get more and more ugly ;-)
// from Kotlin:
..bar(Consumer(::println)) // or: ..bar(Consumer { println(it) })
..bar(::println) // or: ..bar { println(it) } // whatever you prefer...
Que una vez dicho, otra variante consiste en añadir los métodos de ayuda que realmente ayuda llamando a las funciones Kotlin más fácil desde Java, por ejemplo, algo de la siguiente manera:
fun <T> `$`(consumer: Consumer<T>): (T) -> Unit = consumer::accept
Que probablemente nunca ser llamado desde Kotlin (como escribir los acentos abiertos combinados con los $ es ya bastante engorroso) o si no quiere inflar su código Kotlin acaba de añadir un método tal de Java, donde sin embargo, no se ve tan delgada :
static <T> Function1<T, Unit> $(Consumer<T> consumer) {
return t -> {
consumer.accept(t);
return Unit.INSTANCE;
};
}
Las llamadas a los métodos tanto tienen el mismo aspecto:
..bar($(s -> /* do something with s */)) // where bar(x : (String) -> Unit)
Para las cosas que necesitaba para resolver Me acabo de regresar Unit.INSTANCE
o null
, pero si tuviera más métodos para llamar probablemente habría elegido el segundo ( $(...)
enfoque). En el mejor de los casos solo me falta de suministro (generar? ;-)) equivalentes de una vez y utilizarlos en varios proyectos, mientras que el suministro de default
variantes en las interfaces sólo para Java probablemente requerirá mucho más trabajo e incluso puede confundir a algunas personas ...
Por último: no ... No sé de cualquier opción que le permite tener algo así como void
interfaces de -Funcional (/ consumidores) fuera de las Unit
interfaces funcionales -Volviendo de Kotlin.