Real World Example

Migrating a Java Android App

Most Indian product companies (Paytm, Swiggy, PhonePe) started with Java Android code and migrated to Kotlin file by file. Both languages live in the same module. A new Kotlin utility must still be easy to use from old Java screens, so it uses the interop annotations.

// PriceFormatter.kt  (new Kotlin code)
@file:JvmName("PriceFormatter")
package com.shop.util

import java.text.NumberFormat
import java.util.Locale

private val inr: NumberFormat = NumberFormat.getCurrencyInstance(Locale("en", "IN"))

@JvmOverloads
fun format(paise: Long, showSymbol: Boolean = true): String {
    val text = inr.format(paise / 100.0)
    return if (showSymbol) text else text.removePrefix("₹")
}

object Analytics {
    @JvmStatic
    fun log(event: String, params: Map<String, Any?> = emptyMap()) { /* ... */ }
}
// CartActivity.java  (old Java screen, unchanged style)
import com.shop.util.PriceFormatter;

totalView.setText(PriceFormatter.format(totalPaise));          // ₹1,299.00
plainView.setText(PriceFormatter.format(totalPaise, false));   // 1,299.00
Analytics.log("cart_viewed", Collections.emptyMap());

Runnable Check

Example

The same formatter, running on the JVM with the Indian locale. (The JDK groups digits in thousands; the ICU-based formatter on Android shows lakh grouping such as 12,34,567.00.)

import java.text.NumberFormat
import java.util.Locale

private val inr: NumberFormat = NumberFormat.getCurrencyInstance(Locale.of("en", "IN"))

@JvmOverloads
fun format(paise: Long, showSymbol: Boolean = true): String {
    val text = inr.format(paise / 100.0)
    return if (showSymbol) text else text.removePrefix("₹")
}

fun main() {
    println(format(129_900))
    println(format(12_34_567_00, showSymbol = false))
}

Output

₹1,299.00
1,234,567.00

Tip: Migration order that works well: new features in Kotlin first, then utilities and models (data classes), then screens. Use Android Studio's Convert Java File to Kotlin, then clean up the result by hand (it often overuses !!).