How to cope with existing java code that uses a lot of lambdas and optionals


#1

I’ve been on java 8 for a while and I’ve added extensive Optionals etc…

I’m now looking into using kotlin and I’ve started porting some of my code.

I’m having a very hard time.

Could someone help send me to resources that talk about lambdas and optionals etc in kotlin. I’d prefer not to have to rewrite the code in kotlin. Or maybe I’ll ask some of my questions here…

I’ll give you an example:

private Function<Optional<String>, Optional<String>> extractDate = from -> {
    return from.flatMap(line -> Regex.extractMatch("((\\d{2}-){2}(\\d{4}))", line));
};

Where Regex.extractMatch returns an Optional.

The kotlin java conveter (built into intellij wants to do this:

private val extractDate = 
     { from -> from.flatMap({ line -> Regex.extractMatch("((\\d{2}-){2}(\\d{4}))", line) }) }

But this kotlin code does not compile and I don’t know how to fix it…

Intellij says: Error:(175, 30) Kotlin: Cannot infer a type for this parameter. Please specify it explicitly - referring to ‘from’ and ‘line’.


#2

As the error stats, Kotlin cna not infer a type for the parameters from and line. In the Java code it is possible, because you declare the type of the value extractDate.

So you can either declare the type of extractDate explicitly or the type of from and line.

private val extractDate: (Optional<String>) -> Optional<String> = 
     { from -> from.flatMap({ line -> Regex.extractMatch("((\\d{2}-){2}(\\d{4}))", line) }) }

or

private val extractDate:  = 
     { from: Optional<String> -> from.flatMap({ line -> Regex.extractMatch("((\\d{2}-){2}(\\d{4}))", line) }) }

In the second version I did not even have to specify the type of line to be String because Kotlin could infer it after I specified from to be Optional<String>.


#3

Another option you might have is declaring extractDate as a normal function. If you then want to pass it to another function you can use the ::extractDate syntax to get a reference to the function.

See: https://kotlinlang.org/docs/reference/reflection.html#function-references
https://kotlinlang.org/docs/reference/lambdas.html#lambda-expressions-and-anonymous-functions


#4

Yes, thanks. Looks like the latter option works for me.

IntelliJ adds some extras:

	private val extractDate : *(Optional<String>) -> Optional<String!>!* = 

  { from: Optional<String> -> from.flatMap({ line -> Regex.extractMatch("((\\d{2}-){2}(\\d{4}))", line) }) }

Now that seems to work.

I’m not sure what type extractDate is though… is it still a function? Because I think that’s what I want it to be (it is a function in the source java code).

Also, what are those ! marks on the second Optional<String!>! ?

Bit between the * is the extra info provided by intellij.


#5

The ! means that since your result comes from Java the value might be nullable or not. You can probably ignore it in this case as flatMap never returns null. I hope my explanation is not too bad :slight_smile:
You can find out more here: https://kotlinlang.org/docs/reference/java-interop.html#null-safety-and-platform-types


Java Code Migration where an "andThen" and apply of a function is used