Section A.4 Kotlin Functions and Java Code
Calling a Kotlin function from Java code isn't more difficult than the other way around,
but because Kotlin is more feature-rich than Java, you'll often lose some functionality.
Section A.4.1 Converting Kotlin Properties
Properties in Java consist in coding conventions.
In Kotlin, properties are a language feature.
Although Kotlin programs are compiled into Java bytecode, the compiler takes care of the conversion.
Kotlin properties are converted into the standard set of Java field and accessors.
A private field with the same name as the property.
A getter with the name of the property with a capital initial and prefixed with get.
A setter with the name of the property with a capital initial and prefixed with set.
The only exception is that if the Kotlin property name starts with is.
This name is used for the getter, and the setter name is obtained by replacing is with set.
Section A.4.2 Using Kotlin Public Fields
Kotlin public fields are exposed as Java properties, meaning with getters and setters.
If you want to use them as Java fields, you have to annotate them in the Kotlin code like this.
See this code?
In this case, you can no longer access the Kotlin property from Java using accessors.
Also note that Kotlin properties declared with Latinet can be accessed both as fields or with getters.
They can't be annotated with a JVM field.
Section A.4.3 Static Fields
Kotlin has no explicitly static fields, but some Kotlin fields can be seen as static.
This is the case of fields declared in objects, including companion objects, as well as fields declared at package level.
All these fields can be accessed from Java code in the same way as properties, although with some differences.
Fields declared in companion objects can be accessed with getters and setters using the following syntax.
See this code?
But if the field is declared with const, you have to access it as a static field of the enclosing class.
See this code?
The same result can be obtained if the field is annotated with a JVM field.
For fields declared in standalone objects, use the following syntax.
See this code?
Once again, if the field is declared with const or annotated with a JVM field, it must be accessed like a static field.
See this code?
Fields declared at package level can be accessed as if they were static fields of a class with the name of the enclosing file without the .kt extension, but postfixed with kt.
Imagine the following code in myfile.kt.
See this code?
These fields can be accessed from Java as...
See this code?
But note that package level fields can't be annotated with a JVM field.
Section A.4.4 Calling Kotlin Functions as Java Methods
Functions declared with fun in classes can be accessed from Java as methods.
Functions declared in objects or at package level can be accessed as if they were static methods.
Consider the following myfile.kt program file.
See this code?
These functions can be called from Java in various ways.
See this code?
Note that myobject.instance.method5 produces the warning message, static member accessed via instance reference, as if you were calling a Java static method on a class instance.
Calling extension functions from Java?
Extension functions in Kotlin are compiled to static functions with the receiver as an additional parameter.
You can call them from Java in the form to which those are compiled.
Consider the following extension function defined in a file named myfile.kt.
See this code?
Although this function is used in Kotlin as if it were an instance function on a list of strings, you have to call it as a static method in Java.
See this code?
Calling a function with a different name?
You can change the name by which a Kotlin function can be called from Java code.
For this, you need to use the JVM name, new name, annotation on the Kotlin function.
From the Java point of view, there are a few reasons to do this, and you might be forced to do this even if you never call the function from Java code.
Consider the two following functions.
See this code?
This won't compile because Kotlin functions are compiled to Java bytecode.
Type erasure causes the type parameters to be removed on compilation.
As a result, these two functions are equivalent to the following Java methods.
See this code?
These two methods can't coexist in the same class, myfile.kt, because they compile to...
See this code?
Even if you never call these functions from Java, you need to either put them in separate files, or change the compiled name of at least one of them using an annotation.
See this code?
Names of generated Java getters and setters for Kotlin properties can be changed in the same way.
See this code?
Dealing with default values and parameters.
In Kotlin, functions' parameters can have default values.
These functions can be called from Java code, but all parameters must be specified, even those with a default value.
The Java way for dealing with a default value is through overloading.
To make the function available as overloaded Java methods, use the at jvmoverloads annotation.
See this code?
The computePriceKotlin function will be available in Java as...
See this code?
If several parameters have default values, you won't get all possibilities.
See this code?
In this case, the following Java methods are available.
See this code?
As you can see, there's no way to pass only price and shipping and use the default value for tax.
Additionally, the at jvmoverloads annotation can also be used on constructors.
See this code?
Dealing with functions throwing exceptions.
All exceptions are unchecked in Kotlin.
As a consequence, if you try to catch the exception in the Java code calling a Kotlin function throwing exceptions, you'll get a compile error.
Consider the following Kotlin function.
See this code?
You might want to call this function from Java in a try-catch block, such as...
See this code?
But this will not compile and you'll get the following error.
See this code?
To prevent this, you need to indicate explicitly what exception is thrown using the at throws annotation.
See this code?
Note that the at throws annotation is not repeatable.
If your function throws several exceptions that are checked in Java, use the following syntax.
See this code?
You don't need to indicate explicitly unchecked exception because Java lets you catch them freely.
Section A.4.5 Converting Types from Kotlin to Java
Kotlin makes a difference between nullable and non-nullable types.
Java does not.
The difference is lost in the conversion.
Numerical types are converted either to primitives or to object types following what's declared on the Java side.
Immutable collections are converted to Java collections.
For example, a list created with listoff in Kotlin is converted into a JavaArrays.ArrayList in Java.
JavaArrays.ArrayList is a private class in Arrays that extends abstract list without implementing the add method.
As a consequence, if you try to add an element, you'll get an unsupported operation exception,
which might make you think that the list is unmodifiable.
You can't add or remove an element, but you can change an element by calling the set method,
passing it the index of the element to replace the new element.
The immutable lists in Kotlin are far less immutable when converted to Java.
Kotlin also has specific types that don't exist in Java.
Unit is converted to void, although it doesn't mean exactly the same thing.
In Kotlin, unit is a singleton object.
By nature, it might look closer to void if you've ever encountered this type in Java,
but by its functions, it's more equivalent to void.
Any is converted to object.
Nothing isn't converted because nothing exists in Java corresponding to this type.
When used as a type parameter, such as set nothing, the conversion produces a raw type, set.
Functions of 1 to 22 arguments are converted to special Kotlin types,
kotlin.jvm.functions.function1 to kotlin.jvm.functions.function22.
These are SAM interfaces, which makes much more sense than the Java function interfaces.
Functions with no arguments are converted to kotlin.jvm.functions.function0,
which corresponds to the Java supplier interface.
Kotlin functions of type empty parenthesis into unit are converted into instances of kotlin.jvm.functions.function0 of unit,
which corresponds to Java runnable.
Function 1 of A, unit corresponds to Java consumer A,
and function 2 of A, B, unit corresponds to Java buy consumer A, B.
Other Kotlin functions returning unit are sort of multi-consumers with no equivalent in Java.
You can use all the converted functions as you would do in Java,
except that they all implement a method called invoke instead of the Java apply, test, accept, or get.
If you need to convert one of these functions into a Java type, it's easy if the corresponding type exists in Java.
For example, consider the following Kotlin function of type function1 of int, boolean.
You can use this function directly in Java.
The type of this function in Java is kotlin.jvm.functions.function1 of integer boolean.
To convert it into an int predicate, you need to write
See this code?