Calling Java code from Kotlin
In this section we describe some details about calling Java code from Kotlin. In most cases, you just use it:
If a Java method returns void, it will return Unit when called from Kotlin. If, by any chance, someone uses that return value, it will be assigned at the call site by the Kotlin compiler, since the value itself is known in advance (being Unit.VALUE).
Escaping for Java identifiers that are keywords in Kotlin
Some of the Kotlin keywords are valid identifiers in Java: in, object, is, etc. It may happen that some of your favorite Java libraries use these words as names for methods. In this situation you still can call those methods from Kotlin, but you need to escape their names with backticks:
Any reference in Java may be null. So, all the Java methods called from Kotlin return nullable references (except for those annotated with @NotNull). This allows Kotlin to keep the guarantee of having no NullPointerExceptions unless they are explicitly thrown by Kotlin code or caused by something inside Java code called from Kotlin.
Consider the following examples:
In Kotlin, all exceptions are unchecked, meaning that the compiler does not force you to catch any of them. So, when you call a Java method that declares a checked exception, Kotlin does not force you to do anything:
Java generics in Kotlin
- Java's wildcards are converted into type projections
- Foo<? extends Bar> becomes Foo<out Bar>
- Foo<? super Bar> becomes Foo<in Bar>
- Java's raw types are converted into star projections
- List becomes List<*>, i.e. List<out Any?>
Like Java's, Kotlin's generics are not retained at runtime, i.e. objects do not carry information about actual type arguments passed to their constructors, i.e. ArrayList<Integer>() is indistinguishable from ArrayList<Character>(). This makes it impossible to perform is-checks that take generics into account. Kotlin only allows is-checks for star-projected generic types:
Arrays in Kotlin are invariant, unlike Java. This means that Kotlin does not let us assign an Array<String> to an Array<Any>, which prevents a possible runtime failure. Neither does it allow us to pass an array of a subclass as an array of superclass to a Java method. In most cases, this should not be a major obstacle, but if one really needs to pass an array in a covariant way, they may cast explicitly.
On the Java platform, having a generic class Array to represent arrays leads to a lot of boxing/unboxing operations. As arrays are mostly use where performance is critical, we introduced a workaround for this issue and defined classes IntArray, DoubleArray, CharArray and so on, which are not related to the Array class and are compiled down to Java's primitive arrays.
When Java types are imported into Kotlin, all the references of type java.lang.Object are turned into Any?, for any reference may be used there.
The difference between java.lang.Object and Any is that Any declares fewer functions than java.lang.Object. This is done for elegance and platform-independence. So, all that Any has is toString(), equals(Any?) and hashCode().
From the programmer's perspective almost nothing changes compared to Java: all the existing toString() implementations work, and when you need a custom toString() for your class, you simply override it:
In Kotlin, == stands for a guarded call to equals(). The expression on the left-hand side must have a method named equals that takes one parameter of type Any? and returns Boolean. Thus, all the Java objects have it out of the box. Like toString(), equals() can be overridden in Kotlin classes and there's an extension function that works on nullable references.
hashCode() has no special operator convention and no support for nullable references (there's no universal default semantics for it).
Effective Java Item 69 kindly suggests to Prefer concurrency utilities to wait and notify. Thus, these methods are not available on references of type Any, only on Java objects.
To retrieve the type information from an object, one uses the javaClass extension property.
Instead of Java's Foo.class, use javaClass<Foo>().
Any does not declare a finalize() function, so when you really need to override it, this is done "by convention":
Note that there's no override keyword before the function. For JVM this will work as an override, because method signature matches, but for Kotlin there's no override.
clone() can be overridden by with specifying Cloneable as a supertype:
Do not forget about Effective Java Item 11: Override clone judiciously.
At most one Java-class (and as many Java interfaces as you like) can be a supertype for a class in Kotlin. This class must go first in the supertype list.
Static members of Java classes form "class objects" for these classes. One cannot pass such a "class object" around as a value, but can access the members explicitly, for example
Calling Kotlin code from Java
We plan to target more platforms in the future, but currently, Kotlin is only compiled for the Java platform. This means that the compiler generates Java bytecode, and thus the code that we write in Kotlin can be called from Java. There are some concepts in Kotlin that are not available in Java, though. In this section, we briefly describe how these concepts are mapped to Java concepts.
All the functions and properties declared inside a package org.foo.bar are put into a Java class named org.foo.bar.BarPackage.
For the root package (the one that's called a "default package" in Java), a class named _DefaultPackage is created.
As we mentioned above, Kotlin does not have checked exceptions. So, normally, the Java signatures of Kotlin functions do not declare exceptions thrown. Thus, if we have a function in Kotlin like this:
And we want to call it from Java and catch the exception:
we get an error message from the Java compiler, because foo() does not declare IOException.
To work around this problem, use the [throws] annotation:
When calling Kotlin functions from Java, nobody prevents us from passing a null as a non-null parameter. That's why Kotlin generates runtime checks for all public functions that expect non-nulls. This way we get a NullPointerException in the Java code immediately.
Property getters are turned into get-methods, and setters – into set-methods.