I'm taking my first steps with kotlin.
I am migrating some my existing java code to kotlin.
I have the folllowing line:
storyDate.ifPresent(article::setPublishDate);
Where storyDate is an Optional and article has a method setPublishDate(Date) method.
How would I migrate this line to kotlin?
The auto migrator at https://try.kotlinlang.org is
storyDate.ifPresent(Consumer<Date>({ article.setPublishDate() }))
But this line doesn't compile with the kotlin compiler.
I strongly prefer using extension functions and extension fields, so I've written smth like
val <T> Optional<T>.value: T?
get() = orElse(null)
And then you can use it anywhere (after import) like
myOptional.value?.let {
// handle here
}
It’s rather uncommon to use Optional in Kotlin. If you can make storyDate work as an ordinary unwrapped type, such constructs can often be expressed with a simple let call:
storyDate?.let {
article.setPublishDate(it)
//probably property access works as well:
article.publishDate = it
}
How it works: The safe call ?. will invoke let only if storyDate is not null, otherwise the whole expression evaluates to, again, null. When the variable is not null, let is called with a simple lambda where storyDate is accessible by it (or you can rename it to whatever you like).
Side note:
If storyDate really must be Optional, you can still use the depicted construct by unwrapping it like this:
storyDate.orElse(null)?.let {}
storyDate.ifPresent { Article.setPublishDate(it) }
or
storyDate.ifPresent(Article::setPublishDate)
will work.
In the first example, it denotes the value in the optional instance, which is the Date in the optional storyDate.
I assumed that Article is a class, which has the setPublishDate(Date) static method, because class names are always capitalized.
But if article is an instance, not a class, and it has non-static method, then the following will work.
// article = Article(/* some Article-typed object */)
storyDate.ifPresent { article.setPublishDate(it) }
it has the same meaning as the above one, i.e., the actual Date value in Optional.
Related
I fail to understand, why the following compiles:
directory.listFiles { it -> it.name.startsWith("abc") }
but this doesn't:
directory.listFiles { it.name.startsWith("abc") }
Am I correctly assuming that in the first case, the type of it is inferred via the name property? Why is this not happening in the second case?
It is because there are two possible FunctionalInterfaces that can be used with File.listFiles:
listFiles(FileFilter) - this interface is accept(File pathname)
listFiles(FilenameFilter) - this interface is accept(File dir, String name)
The compiler cannot work out which you want to use. So how is this better in the case you write it ->?
Well, the compiler inspects the call arguments of the two interface methods and can now see you expect one argument "SOMETHING ->," so the only matching call is the FileFilter variation.
How might you use the FilenameFilter? you'd use this syntax:
directory.listFiles { dir, name -> name.startsWith("abc") }
The magic here is not it - that's a coincidence, but that you declared just one parameter.
This question already has answers here:
Example of when should we use run, let, apply, also and with on Kotlin
(6 answers)
Closed 3 years ago.
We can write the code with or without let as follows.
var str = "Hello World"
str.let { println("$it!!") }
OR
var str = "Hello World"
println("$str!!")
What is the Actual use of let?.Is that more memory efficient or more readable?
let is one of Kotlin's Scope functions which allow you to execute a code block within the context of an object. In this case the context object is str. There are five of them: let, run, with, apply, and also. Their usages range from but are not exclusive to initialization and mapping.
They are all very similar but they differ in terms of how the context object is referenced and the value that is returned. In the case of let the context object is referenced by the it keyword as opposed to the this keyword. The return value is whatever is returned from the lambda code block. Other scope functions like apply will return the context object instead.
Because let returns whatever the lambda block evaluates to, it is most suited to performing a mapping of some kind:
var upperStr = str.let { it.toUpperCase()}
apply is a more suited function for what you are doing.
To answer your question as to which code is more preferable, it really depends on what you are using the scope function for. In the above case there is no reason to use let. If you are using IntelliJ it will give a warning saying the call to let is redundant. Readability here is a matter of preference, and may be preferred.
The let function is useful when you wish to perform a null safe operation on an Object by using the the safe call operator ?. When doing this the let code block will only be executed if the object is not null. Another reason to use let is if you need to introduce new variables for the operation but you want to confine them to the scope of the let block. This is true for all scope functions, so I reiterate that let is best used for a mapping operation.
Edit: The let function should incur no additional cost. Normally we would expect the lambda/Code-block to be compiled to a Function object but this is not the case for an inline function in Kotlin for which the compiler will emit code not dissimilar to the second code example you have given. See the documentation for more information.
One of usages you can check nullable types
var str: String? = null
str?.let { println("$it!!") }
it's equal
if (str != null) {
System.out.println(str);
}
in Java, but shorter and more useful
let takes the object it is invoked upon as the parameter and returns the result of the lambda expression.
Kotlin let is a scoping function wherein the variables declared inside the expression cannot be used outside.
One of the examples would be here :
fun main(args: Array<String>) {
var str = "Hello World"
str.let { println("$it!!") }
println(str)
}
You can find more information on Kotlin let function here
I noticed that the two onFocusChangeListener callbacks accomplish the same thing:
editTextPassword.setOnFocusChangeListener { view, hasFocus ->
if (!hasFocus) validatePassword()
}
editTextPassword.setOnFocusChangeListener(object : View.OnFocusChangeListener {
override fun onFocusChange(p0: View?, p1: Boolean) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
})
The first one is shorter and what most Kotlin developers will probably always use. It isn't clear to me from the Kotlin documentation how you go from the longer one to the shorter one. Can someone please explain this?
Even though the docs don't explicitly state it, it appears to be saying that an object expression is the equivalent of a "function type" (a.k.a lambda expression). I just don't see how the two are related.
This is a Java SAM conversion that allows you to shorthand implementation of single-method interface by using a lambda expression.
There's only one functional difference when explicitly using object expression, that is you can refer to it (using this) which is not possible inside lambda.
Transformations.map in LiveData transformations take two arguments :
#NonNull LiveData source
#NonNull final Function func
I tried to make the function like this:
val localLiveData = #some live data of type LiveData<User>
Transformations.map(localLiveData, s->{return s.name = "Hi"})
but this shows error cannot unresolved "s"
finally i got it working by this :
Transformations.map(localLiveData) {
s.name = "Hi"
return#map s
}
How this thing is working map has only one argument? (noob in kotlin)
Most of the problems here are with Kotlin's lambda syntax, which is slightly different from that of some other languages.
In Kotlin, a lambda must have braces. But the -> is optional in some cases (if the lambda takes no parameters; or if it takes one and you're referring to it with the dummy name it).
This is one reason why your first version fails; it would need the s -> moved inside the braces. (Another is that in Kotlin, an assignment is not an expression, and doesn't return a value, so you can't use it in a return.)
Your second works because in Kotlin, if the last parameter is a lambda, it can be moved outside the parenthesis. (This allows for higher-order functions that look like language syntax. In fact, if the lambda is the only parameter, you can omit the parentheses entirely!)
I don't know LiveData, but I wonder if the return#map is doing the right thing: it will return not just from the lambda, but from the map() method itself. (Such non-local returns aren't needed very often, and can be confusing.)
Also, a lambda doesn't need an explicit return; it returns the value of its last expression.
So I suspect that a more concise version would be:
Transformations.map(localLiveData) { it.name = "Hi"; it }
Java CompletableFuture<T> has a lot of async methods, static or instance, in this format
public <U> CompletableFuture<U> XXXasync(SomeFunctionalInterface<T> something, Executor executor)
If you have enough experience with FP in kotlin, you will immediately realize these function are extremely awkward to use in kotlin, because the SAM interface is not the last parameter.
aCompletableFutrue.thenComposeAsync(Function<SomeType, CompletableFuture<SomeOtherType>> {
// ^ WHAT A LONG TYPE NAME THAT NEED TO BE HAND WRITTEN
// do something that has to be written in multiple lines.
// for that sake of simplicity I use convert() to represent this process
convert(it)
}, executor)
That Function has a very very long generic signature that I don't know how to let IDE generate. It will be a plain in the butt if the type name become even longer or contains a ParameterizedType or has type variance annotations.
It also looks nasty because of the trailing , executor) on line 5.
Is there some missing functionality in kotlin or IDE that can help with the situation? At least I don't want to write that long SAM constructor all by myself.
Rejected solutions:
Using named parameter doesn't seem to work because this feature only works on a kotlin function.
Abandon async methods sounds bad from the very beginning.
Kotlin corountine is rejected because we are working with some silly Java libraries that accept CompletionStage only.
IF you calling the api from java that takes a functional interface parameter at last, you can just using lambda in kotlin.
val composed: CompletableFuture<String> = aCompletableFutrue.thenComposeAsync {
CompletableFuture.supplyAsync { it.toString() }
};
Secondly, if you don't like the java api method signature. you can write your own extension methods, for example:
fun <T, U> CompletableFuture<T>.thenComposeAsync(executor: Executor
, mapping: Function1<in T, out CompletionStage<U>>): CompletableFuture<U> {
return thenComposeAsync(Function<T,CompletionStage<U>>{mapping(it)}, executor)
}
THEN you can makes the lambda along the method.
aCompletableFutrue.thenComposeAsync(executor){
// do working
}