Files
kotlin-fork/docs/confluence.jetbrains.com/Kotlin/40702623_Java+interoperability.confluence
T
2012-05-30 14:41:40 +04:00

232 lines
11 KiB
Plaintext

[Kotlin] is designed with *Java*\-compatibility in mind. Existing *Java* code can be called from [Kotlin] in a natural way, and [Kotlin] code can be used from *Java* rather smoothly as well.
h2. 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:
{jet}
import java.util.*
fun demo(source : List<Int>) {
val list = ArrayList<Int>()
// 'for'-loops work for Java collections:
for (item in source)
list.add(item)
// Operator conventions work as well:
for (i in 0..source.size() - 1)
list[i] = source[i] // get and set are called
}
{jet}
h3. {{void}}\-returning methods
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 {{()}}).
h3. 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:
{jet}
foo.`is`(bar)
{jet}
h3. Null-safety
Any reference in *Java* may be {{null}}. So, all the *Java* methods called from [Kotlin] return [nullable references|Null-safety] (except for those annotated with [{{@NotNull}}|http://www.jetbrains.com/idea/documentation/howto.html]). This allows [Kotlin] to keep the guarantee of [having no {{NullPointerExceptions}}|Null-safety] unless they are explicitly thrown by [Kotlin] code or caused by something inside *Java* code called from [Kotlin].
Consider the following examples:
{jet}
val list = ArrayList<Int>() // non-null (constructor result)
val size = list.size() // non-null (primitive int)
val iterator = list.iterator() // nullable (ordinary method)
{jet}
h3. Checked exceptions
In [Kotlin], [all exceptions are unchecked|Exceptions], 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:
{jet}
fun render(list : List<out Any?>, to : Appendable) {
for (item in list)
to.append(item.toString()) // Java would require us to catch IOException here
}
{jet}
{anchor:Java generics}
h3. Java generics in [Kotlin]
[Kotlin]'s generics are a little different from *Java*'s (see [Generics]). When importing *Java* types to [Kotlin] we perform some conversions:
* *Java*'s wildcards are converted into [type projections|Generics#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|Generics#Star-projections]
** {{List}} becomes {{List<*>}}, i.e. {{List<out Any?>}}
Besides, *Java*'s generics are not [retained at runtime|Generics#Reified generics], i.e. *Java* objects do not carry information about actual type arguments passed to their constructors, i.e. {{new ArrayList<Integer>()}} is indistinguishable from {{new ArrayList<Character>()}}. This makes it impossible to perform *instanceof*\-checks that take *Java* generics into account. [Kotlin] only allows *is*\-checks for [star-projected|Generics#Star-projections] *Java*'s generic types:
{jet}
if (a is <error desc="java.util.List is a Java class and its generic application to <Int> cannot be used in 'is'">java.util.List<Int></error>) // Error: cannot check if it is really a List of Ints
// but
if (a is java.util.List<*>) // OK: no guarantees about the contents of the list
{jet}
{anchor:Arrays}
h3. Invariant arrays
Arrays in [Kotlin] are [_invariant_|Generics#Declaration-site variance], unlike [*Java*|http://c2.com/cgi/wiki?JavaArraysBreakTypeSafety]. 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.
h3. Object methods
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 big difference between {{java.lang.Object}} and {{Any}} is that {{Any}} does not declare _any_ members at all. This is due to the [inheritance rules|Classes and Inheritance#Overriding rules] in [Kotlin]. Now, what do we do if we need our {{toString()}}, {{equals()}} etc?
h5. toString()
{{toString()}} is declared as an [extension function|Extension functions] that looks for an instance function named {{toString}} and calls it. If there's no {{toString}} it returns some default like {{this.javaClass.getName() + "@" + System.identityHashCode(this)}}.
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 put if there:
{jet}
class A() {
fun toString() : String = "A"
}
{jet}
You don't have to make it *virtual*, and you are allowed to put *override* there only if one of the superclasses declares it *virtual*.
h5. equals()
In [Kotlin], {{==}} stands for a [guarded call to {{equals()}}|Basic operations#Equality]. 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. On the other hand, there's an extension function to {{Any?}} that performs the same kind of lookup as {{toString()}}.
h5. hashCode()
{{hashCode()}} works for *Java* objects.
In the upcoming [Kotlin] standard library we plan to have a {{Hashable}} interface that is required for something to be put into a _non-identity_ hash-map.
h5. wait()/notify()
[Effective Java|http://java.sun.com/docs/books/effective] 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.
h5. getClass()
To retrieve the type information from an object, one uses the [{{javaClass}}|Runtime Type Information] extension function. {{getClass()}} is available for *Java* objects.
h5. finalize()
{{finalize()}} can be overridden exactly like {{toString()}}
h5. clone()
{{clone()}} can be overridden like {{toString()}} but with specifying {{Cloneable}} as a supertype. Do not forget about [Effective Java|http://java.sun.com/docs/books/effective] Item 11: *Override clone judiciously*.
h3. Inheritance from Java classes
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.
h3. Accessing static members
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
{jet}
if (Character.isLetter(a)) {
// ...
}
{jet}
h2. 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.
h3. Package-level functions
All the functions and properties declared inside a [*package*|Packages] {{org.foo.bar}} are put into a *Java* class named {{org.foo.bar.namespace}}.
{jet}
package demo {
class Foo() {
}
fun bar() {
}
}
{jet}
{code}
// Java
new Foo();
demo.namespace.bar();
{code}
h3. Checked exceptions
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:
{jet}
package demo
fun foo() {
throw IOException();
}
{jet}
And we want to call it from *Java* and catch the exception:
{jet}
// Java
try {
demo.namespace.foo();
}
catch (<error desc="Exception IOException is never thrown in the corresponding try block">IOException e</error>) { // error: foo() does not declare IOException in the throws list
// ...
}
{jet}
we get an error message from the *Java* compiler, because {{foo()}} does not declare {{IOException}}. Now, what should we do? There are a few options:
* Option one (suggested in the comments below) is to create a pseudo-throwing function in Java:
{code}
// Java
<E extends Throwable> void mayThrow(Class<E> eClass) throws E {
// Do nothing
}
{code}
And then write:
{code}
// Java
try {
mayThrow(IOException.class);
demo.namespace.foo();
}
catch (IOException e) { // No problem
// ...
}
{code}
* Option two is to catch {{Throwable}} and do an *instanceof* check. This is not very elegant, but will work.
* Option three is to write a wrapper function in *Java*:
{jet}
void foo() throws IOException { // Java does not require us to throw an exception if we declare one
demo.namespace.foo();
}
{jet}
Now, you can call {{foo()}} instead of {{demo.namespace.foo()}}, and catch the exception.
* Option four is to make [Kotlin] put a *throws* list to the {{foo()}}'s signature with the *throws* annotation:
{jet}
throws<IOException> fun foo() {
throw IOException();
}
{jet}
h3. Runtime Type Information
{note:title=Runtime Generics are not implemented yet}{note}
[Kotlin]'s generics are retained at runtime, this means that upon object creation, we pass the type information as parameter to the constructor:
{code}
// Java
new SomeClassDesclaredInKotlin<Integer>(TypeInfos.Int()) // We are passing a TypeInfo object explicitly
{code}
And the same for generic functions.
h3. Null-safety
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.
h3. Properties
Property getters are turned into {{get}}\-methods, and setters -- into {{set}}\-methods.