Kotlin’s extension functions are a convenient way of attaching behavior to the most natural place it belongs. Extensions are incredibly handy to extend the behavior of classes you don’t control, or to define behavior that may only be useful to a subset of users of the class.
Here’s an example extension (I’d use this mainly in tests, not in production
code) to convert an IANA timezone name (like “America/Los_Angeles”) into a Java
ZoneId
/**
* The IANA [ZoneId] for this string.
*
* For instance:
*
* "America/Los_Angeles".zone == ZoneId.of("America/Los_Angeles")
*
*/
val String.zone: ZoneId get() = ZoneId.of(this)
In Kotlin, using this extension is easy. The question is, if we’re working in a mixed Java+Kotlin codebase, how do we use a Kotlin extension in Java code?
These are the key concepts to using a Kotlin extension function/val from Java:
-
An extension is effectively equivalent to a Java static method, with the extension receiver passed as the first parameter.
-
Top-level Kotlin functions and vals can be treated as Java static methods if the file is annotated with
@file:JvmName
-
A Kotlin
val
namedx
is usable from Java asgetX
Thus if we annotate the file as:
@file:JvmName("ZoneExtensions")
package org.foobar
...
/**
* The IANA [ZoneId] for this string.
*
* For instance:
*
* "America/Los_Angeles".zone == ZoneId.of("America/Los_Angeles")
*
*/
val String.zone: ZoneId get() = ZoneId.of(this)
We can then use the extension from Java as:
package org.foobar;
import static org.foobar.ZoneExtensions.getZone;
...
getZone("Pacific/Honolulu")
Granted, with this particular example extension, we’d rather use
ZoneId.of(...)
from Java, but this is a useful option to have when your
Kotlin extension function is non-trivial.