У меня нет реального ответа на это, но я поделюсь тем, что я сделал в такой ситуации, когда мне нужно было получить доступ к такому коду Kotlin из Java (или что мне пришло в голову).
В основном это зависит от того, какую сторону вы действительно хотите коснуться / улучшить, просто чтобы получить то, что вам нужно.
Расширение кода Kotlin для поддержки эквивалентов 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)
}
Это имеет некоторые недостатки:Consumer
-метод также виден из Котлина и поэтому также может быть вызван оттуда.Само собой разумеется, что вам нужно дублировать все функции в интерфейсах, и, следовательно, все ваши Kotlin-интерфейсы становятся более раздутыми.Но: это работает с обеих сторон так, как вы ожидаете.Java вызывает Consumer
-вариант, Kotlin вызывает (String) -> Unit
-вариант ... надеюсь ;-) на самом деле просто демонстрирует некоторые вызовы:
// 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...
С другой стороны, еще один вариант - добавить вспомогательные методыэто на самом деле облегчает вызов функций Kotlin из Java, например, что-то вроде следующего:
fun <T> `$`(consumer: Consumer<T>): (T) -> Unit = consumer::accept
Который, вероятно, никогда не будет вызываться из Kotlin (так как написание обратных ссылок в сочетании с $ уже достаточно громоздко) или если выне хотите раздувать ваш код Kotlin, просто добавьте такой метод в Java, где, однако, он не выглядит таким уж тонким:
static <T> Function1<T, Unit> $(Consumer<T> consumer) {
return t -> {
consumer.accept(t);
return Unit.INSTANCE;
};
}
Вызовы этих методов оба выглядят одинаково:
..bar($(s -> /* do something with s */)) // where bar(x : (String) -> Unit)
Для вещей, которые мне нужно было решить, я просто возвратил Unit.INSTANCE
или null
, но если бы у меня было больше методов для вызова, я бы, вероятно, выбрал второй ($(...)
) подход.В лучшем случае мне нужно только один раз предоставить (сгенерировать? ;-)) эквиваленты и использовать их в нескольких проектах, в то время как предоставление default
вариантов в интерфейсах только для Java, вероятно, потребует гораздо больше работы и может даже запутать некоторых людей..
Наконец: нет ... Я не знаю ни одного варианта, который позволял бы вам иметь что-то вроде void
-функциональных интерфейсов (/ потребителей) из Unit
-возвратных функциональных интерфейсов Kotlin.