Kotlin:BetterJava
A pragmatic language for the JVM: keep 100% Java interop, strip the boilerplate, write null safety into the type system. Fourteen years later it is Android's official language, the native tongue of Cash App / Netflix / Spring, and the engine of Kotlin Multiplatform — Android + iOS + Desktop + Web from one codebase.
backwards-compat anchor
Google I/O recommendation
4 targets, one Kotlin
2024 Kotlin 2.0
What is Kotlin
Kotlin is a statically-typed JVM language from JetBrains. Its self-positioning is simple: replace Java, but with 100% interop. Mix Kotlin and Java files in one project, import each way, share builds. Kotlin sweeps away 23 years of Java boilerplate (getters, setters, equals, final, NPE) without throwing away the JVM ecosystem — that's the core of its "pragmatism."
Compiles to plain JVM bytecode. Java classes import as-is, and Java can call Kotlin back. No ecosystem swap — migrate file by file.
Unlike Scala, Kotlin doesn't pile on type theory for elegance. Its design rule: "readable beats clever" — features get cut if a Java developer can't read them at a glance.
The same Kotlin source compiles to JVM bytecode (Android / backend), native (iOS / Linux / macOS), JS, or Wasm. Share logic, keep UI native per platform.
T? and T are two distinct types. Reaching into a nullable requires ?. / ?: / !!. NPE flagged in the IDE before you save.
public class User {
private final String name;
private final int age;
public User(String n, int a) {
this.name = n; this.age = a;
}
public String getName() { return name; }
public int getAge() { return age; }
@Override public boolean equals(...) { ... }
@Override public int hashCode() { ... }
@Override public String toString() { ... }
}
// 60 lines of boilerplate, IDE-generated — still has to be maintaineddata class User(val name: String, val age: Int)
// One line — equals/hashCode/copy/toString/destructure auto-generated
val a = User("Andrey", 42)
val b = a.copy(age = 43)
val (n, y) = b
// The .class is interop-compatible with Java — 100%History : Timeline
From an internal "Better Java for ourselves" project in St. Petersburg JetBrains to Android's official language, to KMP powering shared cross-platform layers and Compose Multiplatform putting one UI on four targets — 14 years.
- 2010
JetBrains kicks off the project
The JetBrains team in St. Petersburg starts an internal project: find a language that is "better than Java" yet 100% interoperable with Java for their own million-line IntelliJ IDEA codebase. The codename is taken from Kotlin Island near St. Petersburg — echoing Java island and Scala island.
- 2011·07
Public reveal
July 22nd, JetBrains announces Kotlin at the JVM Language Summit. Two non-negotiables on day one: static typing and full Java interop. The Java world shrugs — yet another "Better Java" on the JVM, alongside Scala, Groovy and Clojure.
- 2012·02
Open-sourced
The compiler hits GitHub under Apache 2.0. This is the moment Kotlin stops being a JetBrains internal toy — outside contributors can read commits, file PRs, watch the language evolve in the open.
- 2016·02·15
1.0 ships stable
February 15th: Kotlin 1.0 arrives. Backward compatibility kicks in — code written for 1.0 will compile on every future version. Andrey Breslav (lead language designer) frames it as "a pragmatic language, not a research project."
- 2017·05
Google I/O — first-class on Android
May 17th, Google I/O. Google declares Kotlin an officially supported language for Android. Overnight, Kotlin goes from "another JVM toy" to "the official language of the largest mobile platform on Earth." Kotlin tooling is bundled into Android Studio.
- 2018·10
1.3 — coroutines stable
October 29th, Kotlin 1.3. The
suspendkeyword andkotlinx.coroutinesship as stable. Structured concurrency — coroutine lifetimes scoped, no goroutine-style leaks — is popularised by the Kotlin team. - 2019·05
Google I/O — Kotlin-first for Android
May 7th, I/O 19. Google goes from "supported" to recommended: official docs, samples and tutorials all switch to Kotlin. By year-end surveys, over 50% of professional Android developers are on Kotlin.
- 2020·08
Spring Framework first-class
Spring 5 onwards ships official Kotlin extensions; by 2020 the whole Spring ecosystem (Boot / WebFlux / Data) supports Kotlin DSLs, null safety and coroutines natively. Kotlin's reach spreads from Android clients to JVM backends.
- 2022
Compose Multiplatform alpha
JetBrains ports Google's Jetpack Compose (Android's declarative UI) to Desktop and Web as Compose Multiplatform. The same
@ComposableKotlin function targets Android, Desktop and Web. - 2023·11
1.9.20 — Kotlin Multiplatform stable
November 1st. KMP (Kotlin Multiplatform) goes stable. One Kotlin shared layer compiles to JVM bytecode (Android), native (iOS, Linux, macOS) and JS (Web). Share business logic, keep native UI per platform — the first cross-platform story that doesn't force one UI to rule them all.
- 2024·05
Compose Multiplatform for iOS stable + K2 compiler
May. Compose Multiplatform for iOS hits stable — one Kotlin Compose codebase running on Android, iOS, Desktop and Web. Kotlin 2.0 ships the same year with the K2 compiler stable; type inference roughly 2× faster than K1 and the foundation for KMP plus future syntax evolution.
- 2025
2.x · KMP / Compose go mainstream
Kotlin is squarely in 2.x. Cash App / Square move core transaction logic to KMP; Netflix / Pinterest / Trello / Airbnb run pure-Kotlin Android. Spring Boot 3.x docs put Kotlin on equal footing with Java. Compose for Web (built on K/Wasm) lands — Kotlin starts eating WebAssembly too.
Language Essentials : KotlinAlphabet
Kotlin has a wide feature matrix, but day-to-day 90% comes down to these eight: null safety, data classes, extension functions, coroutines, sealed classes, lambdas + DSL builders, inline / value classes, and property delegation.
Null safety T?
Two type families: nullable T? and non-null T. NPEs are caught at compile time — Kotlin's pitch as "killing Tony Hoare's billion-dollar mistake."
val name: String = "Andrey"
val middle: String? = null
// name.length // OK
// middle.length // ✘ compile error
middle?.length // safe call
middle ?: "-" // elvis fallbackdata class
One line for a value object: equals / hashCode / copy / toString / destructuring all generated. Seven years before Java's record.
data class User(val name: String, val age: Int)
val a = User("Andrey", 42)
val b = a.copy(age = 43)
val (n, y) = b // destructureExtension functions
Add methods to existing types — no inheritance, no wrapper class. Half of Kotlin's stdlib is built this way.
fun String.isPalindrome(): Boolean =
this == this.reversed()
"abcba".isPalindrome() // true
"hello".isPalindrome() // falseCoroutines: suspend / Flow
Async written like sync. suspend functions can pause; Flow is a cold reactive stream. Structured concurrency: when the scope ends, every coroutine ends with it.
suspend fun fetch(url: String): String =
httpClient.get(url).body()
coroutineScope {
val a = async { fetch("/u/1") }
val b = async { fetch("/u/2") }
println(a.await() + b.await())
}sealed class + when
A sealed type confines all possible subtypes to one file. when forces exhaustive matching — miss a branch and the compile fails. ADTs in OOP clothing.
sealed class Result<out T> {
data class Ok<T>(val v: T) : Result<T>()
data class Err(val e: Throwable) : Result<Nothing>()
}
when (r) {
is Result.Ok -> show(r.v)
is Result.Err -> log(r.e)
// exhaustive — miss one ⇒ compile error
}Lambdas + DSL builders
Lambdas with receivers (T.() -> Unit) make Kotlin DSLs feel like YAML. Gradle's build scripts and Compose's UI trees are built on top of this trick.
fun html(block: Tag.() -> Unit) =
Tag("html").apply(block)
html {
body {
h1 { +"Hello" }
}
}Inline / value class
Wrap a primitive in a named type with zero runtime cost — compiled away to the underlying primitive. Perfect for "semantic types" like UserId or Email.
@JvmInline
value class UserId(val raw: Long)
fun load(id: UserId): User
// at JVM level: load(J)LUser; — pure longDelegated properties
The eighth: by delegates a property's getter/setter to another object. by lazy for lazy init, by Delegates.observable for change listeners, by ViewModel() for Android injection — all one-liners.
"Pragmatism isn't doing less — it's moving the boilerplate out of your line of sight."
Why Kotlin : WhyKotlin
The JVM has no shortage of "Better Java" candidates — Scala, Groovy, Clojure all tried. Kotlin won because every design trade-off leaned toward usable, easy to migrate, readable to Java developers.
100% Java interop
Any Java library imports directly; Java can call Kotlin back. This is what put Kotlin past Scala / Clojure: you don't have to throw out 23 years of Java ecosystem to switch.
import com.google.gson.Gson
val json = Gson().toJson(obj)NPEs caught at compile time
Nullability is in the type. Bugs that show up as runtime NPE in Java get flagged in the IDE in Kotlin. The Android community's "70% drop in NPEs after a year of Kotlin" claim is not hype.
val x: String = null // ✘
val y: String? = null // OKAndroid's official language
First-class on Android since I/O 2017, recommended since I/O 2019. Android Studio bundles the full Kotlin tool chain. 80%+ of professional Android developers are on Kotlin (Google 2024 numbers).
// app/build.gradle.kts
plugins { id("org.jetbrains.kotlin.android") }Structured concurrency
Suspend functions + scope = async without leaks. One step beyond Go's goroutines: "parent scope dies, all child coroutines die with it." Kotlin is one of the birthplaces of structured concurrency as a concept.
coroutineScope {
launch { fetch() }
launch { save() }
}Multiplatform: one logic, many targets
KMP compiles Kotlin to JVM bytecode, iOS native, JS, and Wasm. Share business logic, keep UI native per platform — Cash App runs core transaction logic 100% on KMP with 80%+ code shared between iOS and Android.
// commonMain/UserRepo.kt
expect class PlatformDb
// androidMain / iosMain — actualConcise without sorcery
All the Java boilerplate (getters, setters, equals, hashCode, final) goes away. Yet unlike Scala, Kotlin doesn't pile on magic — the design principle is "readable beats clever."
data class P(val x: Int, val y: Int)
// 1 line ≈ 60 lines of JavaFP + OOP, equal partners
Lambdas, map / filter / fold, immutable data are all there — but Kotlin doesn't enforce functional purity. OOP when you need OOP, pipelines when you need pipelines. A pragmatic language.
users
.filter { it.age > 18 }
.map { it.name }Plain JVM bytecode
Kotlin compiles to ordinary JVM bytecode that runs on any JVM, indistinguishable from Java classes. No runtime to ship — just a ~1.5 MB stdlib jar that disappears into a Java project.
// .kt → .class → JVM
// no Kotlin VM, no shimBacked by JetBrains
The language is designed and maintained by the best IDE vendor in the world. IntelliJ / Android Studio's Kotlin support is always best-in-class — rename, extract, cross-language refactor all just work. Nothing else on the JVM has this.
// rename across .kt + .java
// in one shortcut, IDE-drivenWho's Using : ProductionUsers
From mobile payment apps to streaming Android clients, from IDEs to build tools — Kotlin is the de facto mainstream of the JVM and Android worlds. The 12 below sample its reach.
Android takeover + : Multiplatform Era
Kotlin had two leverage moments. First: Google adopting it into Android in 2017. Second: KMP in 2023 and Compose Multiplatform for iOS stable in 2024 — one Kotlin covering Android + iOS + Desktop + Web. This chapter is about the second leg: Kotlin has gone from "Android's language" to the shared cross-platform layer of choice.
"When we set out to make Kotlin a pragmatic language, we had one goal: a Java developer should be able to read Kotlin code and just understand it, with no explanation. Research languages can be beautiful, can be avant-garde — but 95% of day-to-day code isn't fancy. It needs to be clear, interoperable, easy to migrate. Every Kotlin design trade-off has been made on that principle.
Google 2024: over 80% of professional Android developers are primarily on Kotlin. Jetpack Compose is Kotlin-only — pulling the entire Android UI world toward fully Kotlin.
Stable since 2024-05: Android · iOS · Desktop · Web. One Kotlin @Composable, UI on all four. iOS uses Kotlin/Native compiling through LLVM to a real binary — not an RN-style JS bridge.
Kotlin 2.0 in 2024 promoted K2 to stable with a full rewrite of type inference and resolution. Common projects see ~2× faster type checks, and K2 sets the baseline for KMP's multi-target growth.
Compose Multiplatform
JetBrains ported Google's Jetpack Compose (Android's declarative UI) to Desktop, iOS, and Web. The same Kotlin @Composable function compiles natively per target: Android uses JVM bytecode; iOS uses Kotlin/Native through LLVM; Desktop runs JVM; Web runs K/Wasm.
- Kotlin/JVM — Android · Desktop · server
- Kotlin/Native — iOS · macOS · Linux · Windows — straight to LLVM binary
- Kotlin/Wasm — Browser-native, near-native performance
- expect / actual — Per-platform differences declared explicitly, resolved at compile time
Compare: Flutter goes "Skia self-painted + Dart"; React Native goes "JS bridge to native views"; Compose Multiplatform takes the native-binary + shared renderer route. Best fit for incremental adoption into existing apps.
// commonMain — one UI, all targets
@Composable
fun App() {
var count by remember { mutableStateOf(0) }
Column(Modifier.padding(16.dp)) {
Text("Clicked $count times")
Button(onClick = { count++ }) {
Text("Click me")
}
}
}
// Same code — Android / iOS / Desktop / Web
// Native compile per target, no bridgeProduction adopters
KMP vs Flutter / React Native
All three solve "share code across platforms" — but along very different paths.
Flutter (Google): UI is Skia self-painted, Dart end to end. Uniform across platforms, but the "native feel" never quite arrives; hard to drop into an existing native app.
React Native (Meta): JS for business logic, bridge to native views. UI is genuinely native, but the bridge overhead and async chains never quite go away.
KMP (JetBrains): share Kotlin for business logic, compile to native binary; UI stays platform-native (Compose Multiplatform is an optional unifier). Best fit for existing Android+iOS apps migrating gradually — the Cash App / Netflix route.
// commonMain/UserRepo.kt
expect class PlatformDb()
class UserRepo(val db: PlatformDb) {
suspend fun fetch(id: Long): User = ...
}
// androidMain/PlatformDb.kt
actual class PlatformDb(val ctx: Context)
// iosMain/PlatformDb.kt
actual class PlatformDb(val store: NSUserDefaults)
// Business logic 100% shared; platform details actual'd per targetIn one line: Kotlin's two leverage moments — 2017 (Android adoption) and 2023 KMP / 2024 Compose iOS stable — pushed it from "a Better Java for the JVM" to "the de-facto cross-platform shared layer." Fourteen years of pragmatism cashing in, in the multiplatform era.
vs Java / Swift : Kotlin vs Java vs Swift
On the JVM, Kotlin's foil is Java. On iOS, it's Swift. The three look surprisingly similar (statically typed, null-safe, modern syntax), but their lineage, ecosystem, and cross-platform stories diverge.
| Java | Kotlin | Swift | |
|---|---|---|---|
| Origin | Sun · 1995 | JetBrains · 2010 | Apple · 2014 |
| Primary platform | JVM (server / Android) | JVM / Android · KMP cross-platform | iOS / macOS / Apple |
| Null safety | NPE everywhere | T? / T | T? / T |
| Value class | Java 14+ has record | data class · 2016 起 | struct |
| Coroutines / async | Java 21+ virtual threads | suspend / Flow · structured concurrency | async / await · Task |
| Pattern matching | Java 21+ switch patterns | when · sealed 穷尽 | switch · enum + associated |
| Extension methods | None (need wrapper classes) | fun T.foo() | extension |
| Interop | Everything on JVM · the elder | 100% Java interop | 100% Objective-C; C/C++ via bridging header |
| Cross-platform | Cross-platform within JVM only | KMP · 4 targets shared | Mostly Apple (Linux experimental) |
| Boilerplate | High (getters / setters / equals) | Low (data class / val / lambdas) | Low (struct / auto init) |
| UI framework | Swing · JavaFX · Android | Jetpack Compose · Compose MP | SwiftUI |
| Build tool | Maven / Gradle (Groovy) | Gradle Kotlin DSL | Xcode · SwiftPM |
Outlook : TheRoadAhead
Compose Multiplatform iOS is stable, the K2 compiler is stable, Kotlin/Wasm joins KMP as the fourth target — four lanes moving at once. The next round is "whose cross-platform story flows better."
Compose Multiplatform for iOS — stable
JetBrains officially shipped Compose Multiplatform for iOS as stable in May 2024. One Kotlin Compose codebase running on Android, iOS, Desktop and Web — declarative UI on par with SwiftUI / Jetpack Compose.
Compared to Flutter's "Skia self-painted + Dart" or React Native's "JS bridge to native views," Compose Multiplatform takes the native-binary + Kotlin-to-LLVM route: on iOS, Kotlin compiles straight to native through LLVM, with the Compose renderer sitting on top.
K2 compiler — ~2× faster
Kotlin 2.0 in 2024 promoted the K2 compiler from alpha to stable. Type inference / resolution were rewritten end-to-end, giving common projects ~2× faster type checks and a foundation for KMP and future syntax growth.
Compose for Web on K/Wasm
Kotlin/Wasm is KMP's fourth target: native-compiled Kotlin runs inside the browser as WebAssembly, near-native performance. Compose for Web puts declarative UI on top — Kotlin eats WebAssembly too.
80%+ of Android devs on Kotlin
Google 2024: over 80% of professional Android developers primarily use Kotlin. Jetpack Compose (Android's declarative UI) is Kotlin-only — pushing the Android world to full Kotlin.
Spring Boot 3.x — Kotlin = Java
Spring Boot 3 docs treat Kotlin as a peer of Java — every sample dual-coded. Kotlin coroutines plug into Spring WebFlux, reactive servers written in sync style. Ktor and http4k carve out the lightweight-JVM-server niche.
KMP vs Flutter / RN tug-of-war
KMP says "share logic, native UI per platform"; Flutter says "one Skia-painted UI everywhere." KMP wins for incremental adoption (drop into existing apps); Flutter wins for greenfield uniformity. The 2025 split: existing Android+iOS app → KMP; brand-new product → Flutter.