
fun List<Long>.average() = sum().toDouble() / size fun List<Int>.average() = sum().toDouble() / size
List with a different type argument. This is perfectly fine for Kotlin, but not when targeted for the JVM platform. Due to type erasure, both these functions on JVM are considered methods called average with a single parameter of type List. So, having them both defined in the same file leads to a platform name clash.
JvmName annotation, which changes the name that will be used for this function under the hood on the JVM platform. Usage will not change in Kotlin, but if you want to use these functions from a non-Kotlin JVM language, you need to use the names specified in the annotation.@JvmName("averageLongList") fun List<Long>.average() = sum().toDouble() / size @JvmName("averageIntList") fun List<Int>.average() = sum().toDouble() / size fun main() { val ints: List<Int> = List(10) { it } println(ints.average()) // 4.5 val longs: List<Long> = List(10) { it.toLong() } println(longs.average()) // 4.5 }
// Java public class JavaClass { public static void main(String[] args) { List<Integer> ints = List.of(1, 2, 3); double res1 = TestKt.averageIntList(ints); System.out.println(res1); // 2.0 List<Long> longs = List.of(1L, 2L, 3L); double res2 = TestKt.averageLongList(longs); System.out.println(res2); // 2.0 } }
JvmName annotation is useful for resolving name conflicts, but there is another case where it is used much more often. As I explained in the Kotlin Essentials book, for all Kotlin top-level functions and properties on JVM, a class is generated whose name is the file name with the "Kt" suffix. Top-level functions and properties are compiled to static JVM functions in this class and thus can be used from Java.package test const val e = 2.71 fun add(a: Int, b: Int) = a + b
// Compiles to the analog of the following Java code package test; public final class TestKt { public static final double e = 2.71; public static final int add(int a, int b) { return a + b; } }
// Usage from Java public class JavaClass { public static void main(String[] args) { System.out.println(TestKt.e); // 2.71 int res = TestKt.add(1, 2); System.out.println(res); // 3 } }
JvmName annotation for the file. As I explained in the Annotation targets section, file annotations must be placed at the beginning of the file, even before the package definition, and they must use the file target. The name that we will specify in the JvmName file annotation will be used for the class that stores all the top-level functions and properties.@file:JvmName("Math") package test const val e = 2.71 fun add(a: Int, b: Int) = a + b
// Compiles to the analog of the following Java code package test; public final class Math { public static final double e = 2.71; public static final int add(int a, int b) { return a + b; } }
// Usage from Java public class JavaClass { public static void main(String[] args) { System.out.println(Math.e); // 2.71 int res = Math.add(1, 2); System.out.println(res); // 3 } }
Math or Collections that are holders for static elements. In Kotlin, we use top-level functions instead, which offers us the convenience that we don’t need to collect all these functions and properties in the same file. However, when we design Kotlin code for use from Java, we might want to collect elements from multiple files that define the same package in the same generated class. For that, we need to use the JvmMultifileClass annotation next to JvmName.// FooUtils.kt @file:JvmName("Utils") @file:JvmMultifileClass package demo fun foo() { // ... }
// BarUtils.kt @file:JvmName("Utils") @file:JvmMultifileClass package demo fun bar() { // ... }
// Usage from Java import demo.Utils; public class JavaClass { public static void main(String[] args) { Utils.foo(); Utils.bar(); } }
class Pizza( val tomatoSauce: Int = 1, val cheese: Int = 0, val ham: Int = 0, val onion: Int = 0, ) class EmailSender { fun send( receiver: String, title: String = "", message: String = "", ) { /*...*/ } }


Note that when all constructor parameters are optional, two constructors are generated: one with all the parameters, and one that uses only default values.
JvmOverloads annotation before a function to make Kotlin generate different variants with different numbers of expected arguments.class Pizza @JvmOverloads constructor( val tomatoSauce: Int = 1, val cheese: Int = 0, val ham: Int = 0, val onion: Int = 0, ) class EmailSender { @JvmOverloads fun send( receiver: String, title: String = "", message: String = "", ) { /*...*/ } }



Do not confuse JvmOverloads with JVM overlords.
