Перейти к основному содержимому

Kotlin и Java — совместимость на практике

Разработчику Архитектору

Kotlin и Java — совместимость на практике

Kotlin и Java компилируются в один байт-код JVM. В одном Gradle/Maven-проекте файлы .kt и .java лежат рядом, классы вызывают друг друга напрямую. Сложности появляются на границе API: null, статические методы, коллекции, default-аргументы.

Обзор: экосистема Kotlin. Java-ООП: 18.md. Spring на Kotlin: 232.md.


Словарь терминов

ТерминПростыми словами
JVMВиртуальная машина; исполняет .class независимо от исходного языка.
Platform type T!Тип из Java без null-аннотаций — Kotlin не знает, может ли быть null.
@Nullable / @NotNullПодсказки для компилятора Kotlin (JetBrains или javax).
SAMSingle Abstract Method — один метод в интерфейсе; Kotlin-лямбда подходит.
@JvmStaticМетод object виден в Java как статический.
@JvmOverloadsDefault-аргументы Kotlin → несколько перегрузок в Java.

Правило большого пальца

ПишетеДумайте о потребителе
Kotlin, вызывают из Java@JvmStatic, @JvmOverloads, @JvmName при необходимости
Java, вызывают из KotlinPlatform types, явные проверки ?. и !! только где уверены
Постепенная миграцияНовые файлы .kt, старые .java в том же пакете

Вызов Java из Kotlin

Java:

package com.example;

import org.jetbrains.annotations.Nullable;

public class JavaGreeter {
public String greet(@Nullable String name) {
return "Hello, " + (name != null ? name : "World");
}
}

Kotlin:

fun main() {
val g = JavaGreeter()
val s: String? = g.greet(null)
println(s)
}

Разбор:

  • JavaGreeter() — обычный конструктор Java-класса.
  • @Nullable на параметре → Kotlin видит String?.
  • Без аннотаций Java String становится platform type String! — компилятор разрешит присвоить и String, и String?; ответственность на вас.

Вызов Kotlin из Java

package com.example

object KotlinUtils {
@JvmStatic
fun twice(x: Int) = x * 2

@JvmOverloads
fun join(parts: List<String>, separator: String = ", ") =
parts.joinToString(separator)
}

data class User(val id: Long, val name: String)

Java:

int n = KotlinUtils.twice(21);
String line = KotlinUtils.join(List.of("a", "b"));
User u = new User(1L, "Ann");
long id = u.getId();
String name = u.getName();
KotlinЧто видит Java
object без @JvmStaticKotlinUtils.INSTANCE.twice()
@JvmStatic fun twiceKotlinUtils.twice()
@JvmOverloads + defaultНесколько методов join(...)
data class UserКонструктор, getId(), getName(), copy, equals

SAM и лямбды

Java:

public interface ClickListener {
void onClick();
}

Kotlin:

val listener = ClickListener { println("click") }

Лямбда Kotlin превращается в реализацию интерфейса с одним методом. Из Java 8+ лямбда передаётся в Kotlin-функцию ( ) -> Unit, если тип функциональный.


Коллекции и мутабельность

Java List из старого API может быть изменяемым ArrayList. Kotlin List — read-only view:

fun process(items: MutableList<String>) {
items.add("tail")
}

На границе указывайте MutableList / java.util.List явно, если код меняет коллекцию.


Постепенная миграция модуля

  1. Подключить Kotlin в Gradle/Maven (2.md).
  2. Новые классы — .kt в том же пакете, что Java.
  3. Заменить POJO на data class, сервисы — с конструкторной DI.
  4. Удалить .java, когда тесты зелёные.

Большой модуль одним коммитом без тестов ломает CI — мигрируйте по пакетам или по фичам.


Android — Java SDK + Kotlin UI

Android SDK на Java; UI на Kotlin (229) — обычная схема. Вызовы findViewById из Java Activity и Composable из Kotlin сосуществуют при постепенной миграции.


Частые ошибки

СимптомПричина
NPE в «безопасном» KotlinJava вернул null без @Nullable
KotlinUtils.INSTANCE.twiceНет @JvmStatic
Дубли методов в JavaКонфликт @JvmOverloads с ручными перегрузками
UnsupportedOperationExceptionИзменили read-only Kotlin List, обёрнутый над Java

Что попробовать

  1. Extension-функции Kotlin для «обёртки» над Java API.
  2. Spring Boot на Kotlin в проекте с Java-модулями.
  3. Один интерфейс на Kotlin, реализация в Java — и наоборот; unit-тест на границе.

Дальше

Spring Boot Kotlin · Room · о разделе


См. также

Другие статьи этого же раздела в боковом меню (как на странице «О разделе»).