Calling Kotlin from Java

Categories:
5 minute read
While Kotlin is fully interoperable with Java, calling Kotlin code from Java requires understanding certain conventions and annotations that make the interaction smooth and predictable. This comprehensive guide explores how to effectively use Kotlin code in Java applications, covering essential concepts, best practices, and common patterns.
Basic Kotlin-Java Interoperability
Properties
When calling Kotlin properties from Java, they are automatically exposed as getter and setter methods:
// Kotlin class
class KotlinUser {
var name: String = ""
val id: Int = 1
}
// Java usage
public class JavaClass {
public void useKotlinProperties() {
KotlinUser user = new KotlinUser();
user.setName("John"); // Calls the setter
String name = user.getName(); // Calls the getter
int id = user.getId(); // Calls the getter for val
}
}
Functions
Kotlin functions are converted to Java methods:
// Kotlin functions
class KotlinService {
fun processData(data: String): Boolean {
return data.isNotEmpty()
}
fun calculateTotal(vararg numbers: Int): Int {
return numbers.sum()
}
}
// Java usage
public class JavaService {
public void useKotlinFunctions() {
KotlinService service = new KotlinService();
boolean result = service.processData("test");
int total = service.calculateTotal(1, 2, 3);
}
}
Handling Kotlin-Specific Features
Data Classes
Kotlin data classes are accessible from Java with generated methods:
// Kotlin data class
data class Product(
val id: String,
val name: String,
val price: Double
)
// Java usage
public class JavaShop {
public void handleProduct() {
Product product = new Product("1", "Phone", 999.99);
String name = product.getName();
Product copy = product.copy(price = 899.99);
boolean equals = product.equals(copy);
String toString = product.toString();
}
}
Companion Objects
Accessing Kotlin companion objects from Java requires special consideration:
// Kotlin class with companion object
class KotlinFactory {
companion object {
@JvmStatic
fun create(): KotlinFactory = KotlinFactory()
const val DEFAULT_SIZE = 100
}
}
// Java usage
public class JavaFactory {
public void useCompanion() {
// With @JvmStatic
KotlinFactory instance = KotlinFactory.create();
// Accessing companion constant
int size = KotlinFactory.DEFAULT_SIZE;
// Without @JvmStatic, would need:
// KotlinFactory.Companion.create();
}
}
Extension Functions
Using Kotlin extension functions in Java:
// Kotlin extension functions
@file:JvmName("StringUtils")
fun String.addPrefix(prefix: String): String = "$prefix$this"
// Java usage
public class JavaString {
public void useExtension() {
// Extension functions are compiled to static methods
String result = StringUtils.addPrefix("World", "Hello ");
}
}
Null Safety
Handling Nullable Types
Working with Kotlin’s null safety features in Java:
// Kotlin class with nullable types
class KotlinNullable {
fun processNullable(text: String?): Int? {
return text?.length
}
@NotNull
fun getNonNull(): String = "Never null"
}
// Java usage
public class JavaNullable {
public void handleNullability() {
KotlinNullable kotlin = new KotlinNullable();
// Can pass null to nullable parameter
Integer length = kotlin.processNullable(null);
// Non-null return type is guaranteed
String nonNull = kotlin.getNonNull();
}
}
Collections and Arrays
Working with Kotlin Collections
Handling Kotlin collections in Java:
// Kotlin collections
class KotlinCollections {
fun getList(): List<String> = listOf("a", "b", "c")
fun getMutableList(): MutableList<String> = mutableListOf("x", "y", "z")
}
// Java usage
public class JavaCollections {
public void useKotlinCollections() {
KotlinCollections collections = new KotlinCollections();
// Immutable list from Kotlin
List<String> immutable = collections.getList();
// Mutable list from Kotlin
List<String> mutable = collections.getMutableList();
mutable.add("w"); // OK
}
}
Function Types and Lambdas
Using Kotlin Function Types
Working with Kotlin functions and lambdas in Java:
// Kotlin function types
class KotlinCallback {
fun setHandler(handler: (String) -> Unit) {
handler("Event")
}
fun processWithCallback(callback: (Int) -> Boolean) {
callback(42)
}
}
// Java usage
public class JavaCallback {
public void useKotlinFunctions() {
KotlinCallback callback = new KotlinCallback();
// Using Function1 interface
callback.setHandler(
(String message) -> System.out.println(message)
);
// Using Function1 with return value
callback.processWithCallback(
(Integer num) -> num > 0
);
}
}
Best Practices
1. Using @JvmOverloads
Making Kotlin default parameters accessible in Java:
// Kotlin class with default parameters
class KotlinConfig @JvmOverloads constructor(
val host: String = "localhost",
val port: Int = 8080,
val timeout: Long = 5000
)
// Java usage
public class JavaConfig {
public void createConfigs() {
// All constructors are available
KotlinConfig config1 = new KotlinConfig();
KotlinConfig config2 = new KotlinConfig("example.com");
KotlinConfig config3 = new KotlinConfig("example.com", 9090);
}
}
2. Using @JvmField
Exposing Kotlin properties as fields:
// Kotlin class with field annotation
class KotlinFields {
@JvmField
var publicField: String = "Direct access"
}
// Java usage
public class JavaFields {
public void accessFields() {
KotlinFields fields = new KotlinFields();
// Direct field access without getter/setter
fields.publicField = "New value";
}
}
3. File-Level Functions
Organizing Kotlin utility functions for Java use:
// Kotlin file: Utils.kt
@file:JvmName("Utils")
fun helper(input: String): String = input.uppercase()
// Java usage
public class JavaUtils {
public void useUtils() {
// Clean static method access
String result = Utils.helper("test");
}
}
Conclusion
Calling Kotlin from Java is straightforward when you understand the interoperability features and annotations provided by Kotlin. Key points to remember:
- Use appropriate annotations (@JvmStatic, @JvmField, @JvmOverloads) to customize Java interop
- Understand how Kotlin properties translate to Java getters and setters
- Handle nullable types appropriately
- Leverage Kotlin’s collection types in Java
- Use function types and lambdas effectively
By following these guidelines and understanding the interoperability mechanisms, you can effectively use Kotlin code in Java projects while maintaining code quality and taking advantage of Kotlin’s features.
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.