How do I pass a lambda from Java to a Kotlin method? - java

Can I call this Kotlin method from Java?
fun foo(() -> Unit)
If so, what's the syntax?

You need to create instance of Function0:
foo(new Function0<Unit>() {
#Override
public Unit invoke() {
// Here should be a code you need
return null;
}
});
or if you use Java 8 it can be simplified
foo(() -> {
// Here should be a code you need
return null;
});

You can call this but need to be careful of the return types. If your Kotlin function returns a Unit, Java will either need to return Unit or null, because void is not quite the same as Unit.
My example that worked:
foo(() -> {
System.out.println("Hi");
return null;
});
Or, if you want to be really explicit about Unit...
foo(() -> {
System.out.println("Hi");
return Unit.INSTANCE;
});

I totally agree with Andrew's Answer, There is a better way to approach
You need to see generated Kotlin Bytecode -> Decompile it
In your case it looks something like this:
public static final void foo(#NotNull Function0 acceptLambda) {
Intrinsics.checkNotNullParameter(acceptLambda, "acceptLambda");
}
now you know in order to call this function form Java you need to create instance of Function0 something like this
foo(new Function0<Unit>() {
#Override
public Unit invoke() {
// Your Code
return null;
}
});

Related

Java Lambda to Method

Given that I know little and nothing about java, exactly like my English,
I have a problem, I have this line of code and I had to delete the lambdas.
return articles (args -> {}, queryDef);
I used Android Studio, (Alt Enter) and it creates me
private com.shopify.buy3.Storefront.BlogQuery.ArticlesArgumentsDefinition GetArticlesArgumentsDefinition () {
return args -> {};
}
always with lambdas.
How can I convert args -> {} in order to eliminate them?
Thank you
EDIT:
public BlogQuery articles(ArticleConnectionQueryDefinition queryDef) {
return articles(args -> {}, queryDef);
}
/**
* List of the blog's articles.
*/
public BlogQuery articles(ArticlesArgumentsDefinition argsDef, ArticleConnectionQueryDefinition queryDef) {
startField("articles");
ArticlesArguments args = new ArticlesArguments(_queryBuilder);
argsDef.define(args);
ArticlesArguments.end(args);
_queryBuilder.append('{');
queryDef.define(new ArticleConnectionQuery(_queryBuilder));
_queryBuilder.append('}');
return this;
}
You could define a conventional implementation of ArticlesArgumentsDefinition, though I don't recommend it. Why do you have to get rid of the lambda?
return articles(new ArticlesArgumentsDefinition() {
#Override
public void define(ArticlesArguments args) { }
});
Here, I've used an anonymous class, which is the closest pre-lambda equivalent to a real lambda, but this could be any kind of class.
You are looking for "Replace lambda with anonymous class" intention available when doing Alt+Enter on -> symbol. It should replace your lambda with something like this:
return articles(new BlogQuery.ArticlesArgumentsDefinition() {
#Override
public void define(ArticlesArguments args) {
// body of lambda
}
});
I think you should be able to do Alt+Enter -> Replace lambda with anonymous class -> Fix all... to do it in one go.

Can we pass java method to to kotlin function of type () -> Unit?

I have a method of kotlin like below
fun initDrawer(drawerView: DrawerView, drawerLayout: DrawerLayout, context: Context, onRefreshClick: () -> Unit) {
}
But when I try to pass initDrawer(drawerView,drawerlayout,this,onRefreshClick())
it gives me an error of required () cannot be applied to(kotlin.Unit)
is it possible to pass methods from java to kotlin.
You have to set return value of your onRefreshClick to Unit:
private Unit onRefreshClick() {
//do something here
return Unit.INSTANCE;
}
Then you can call it like this:
initDrawer(drawerView, drawerLayout, this, this::onRefreshClick);
You cannot pass your Java method directly from Java, as the Kotlin parameter expects the method to return Unit.
You can follow the following pattern:
kotlinClass.higherOrderFunction(() -> {functionToPass(); return Unit.INSTANCE;});
where functionToPass() is defined as:
private void functionToPass() {
// do something
}
In your case:
initDrawer(drawerView, drawerlayout, this,
() -> {onRefreshClick(); return Unit.INSTANCE;})
Let's say your Java method resides in a class called Test:
public class Test {
void onRefreshClick() {
System.out.println("test");
}
}
It could be called by your Kotlin function like this (as reference):
val t = Test()
initDrawer(drawerView, drawerlayout, this, t::onRefreshClick)
onRefreshClick could also be static in Java which would enable you to use it like this:
initDrawer(drawerView, drawerlayout, this, Test::onRefreshClick)
Note:
In Kotlin () -> Unit is the type of a function which has no arguments and returns nothing (which is Unit and not Nothing as return type).
There is no Unit in Java. The Java method which corresponds to this type would have no arguments and as return type void.

Maybe switchIfEmpty lazy evaluation

I use Maybe switchIfEmpty method to provide an alternate result if the source Maybe is empty. However, I would like the alternate source to be executed only when the source is empty and not execute it when the source is not empty.
In the following example I would like to avoid execution of costlyFallback if the source returned non-empty Maybe. The current implementation always calls it because it is required to be passed to switchIfEmpty method. Maybe.fromCallable looks promising, however it will work only with callables which exludes returning a Maybe.empty. Any hints are appreciated. Would be nice if switchIfEmpty would accept some lazily evaluated Maybe provider.
public class StartRxMaybe {
public static void main(String... args) {
System.out.println(new StartRxMaybe().start().blockingGet());
}
private Maybe<Integer> start() {
return func()
.switchIfEmpty(costlyFallback());
}
private Maybe<Integer> func() {
System.out.println("Non-empty maybe returned");
return Maybe.just(1);
}
private Maybe<Integer> costlyFallback() {
System.out.println("Fallback executed anyway");
return LocalDate.now().getMonth() == Month.JULY
? Maybe.just(2)
: Maybe.empty();
}
}
I think I found the solution. Using Maybe.defer does the trick and allows to pass the supplier:
private Maybe<Integer> start() {
return func()
.switchIfEmpty(Maybe.defer(this::costlyFallback));
}
Thanks to #nosalan, here is my solution for Kotlin:
fun getOperator(id: Int): Single<Operator> {
return db.getOperator(id)
.switchIfEmpty(Single.defer { api.getOperators }
.flattenAsFlowable { it }
// etc.
)
}
Note {} instead of () in defer.

"Function0 is not a functional interface" error when passing java lambda to kotlin fun

This is my kotlin code:
class Foo : Bar {
override var onRefreshListener: (() -> Unit)? = null
...
}
And this is what I try to do in java:
class A {
private Foo foo;
private void onRefreshStarted() {}
private void problem() {
foo.setOnRefreshListener(this::onRefreshStarted);
foo.setOnRefreshListener(() -> onRefreshStarted());
}
}
In both cases in problem() I get the following error from Android Studio:
Function0 is not a functional interface
How can I set the onRefreshListener from java?
After fixing the kotlin lib's dependencies in the pom file, here are the 3 possible solutions I could figure out.
1st solution: No need for kotlin-stdlib in the java project:
In kotlin add:
#FunctionalInterface
interface OnRefreshListener {
fun onRefresh()
}
And change the interface from:
var onRefreshListener: (() -> Unit)?
to:
var onRefreshListener: OnRefreshListener?
and the invocations from:
onRefreshListener?.invoke()
to:
onRefreshListener?.onRefresh()
2nd solution: (Thanks to #hotkey) needs the kotlin-stdlib, no change in kotlin code. In java change:
foo.setOnRefreshListener(() -> onRefreshStarted());
to:
foo.setOnRefreshListener(() -> { onRefreshStarted(); return Unit.INSTANCE; });
3rd solution: needs kotlin-stdlib, no change in kotlin, change:
private void onRefreshStarted() {}
to:
private Unit onRefreshStarted() {...; return null;}
I'm not sure that it's exactly why you get that kind of error, but you can try to fix your code by passing a Unit-returning lambda instead of a lambda without a return value:
foo.setOnRefreshListener(() -> { onRefreshStarted(); return Unit.INSTANCE; });
Since the Function0<T> interface's invoke() returns T, when calling a Kotlin method accepting a () -> Unit from Java, you have to pass a lambda that returns Unit.

wrapping String in scala Future from java code

I have the following method for testing:
public scala.concurrent.Future<String> send() {
return "OK"; //error - should wrap with future
}
How can I make it return a scala future (this is java code, so didn't find any example)?
It's easy if you are working with the Scala 2.12.x library.
In Scala you would write Future(doSomeStuff()). Or simply Future.successful("OK") if you really only want to wrap a literal in a Future.
In Java that translates to one of these:
import scala.concurrent.*;
public Future<String> send1() {
return Future.apply( () -> doSomeStuff(), ExecutionContext.global());
}
public Future<String> send2(ExecutionContext ec) {
return Future.apply( () -> doSomeStuff(), ec);
}
public Future<String> send3() {
return Future.successful("OK");
}
If you have more complex code to run than simply "OK" you'll have to use send1 or send2. Which of those you want depends on whether you want to use the default ExecutionContext or let the caller decide.
If your Scala version is lower than 2.12.0, the send1 method from above will look something like this:
import scala.concurrent.*;
import scala.runtime.AbstractFunction0;
public Future<String> send1() {
return Future$.MODULE$.apply( new AbstractFunction0<String>() {
public String apply() {
return doSomeStuff();
}
}, ExecutionContext$.MODULE$.global());
}

Categories

Resources