DEV Community

Cover image for Java friendly Kotlin - static functions
Dan Newton
Dan Newton

Posted on • Originally published at lankydan.dev on

Java friendly Kotlin - static functions

In this post, we will look at writing static functions in Kotlin that treat Java callers as first-class citizens.

Recap

There are three ways to define static functions in Kotlin:

  • Directly in a Kotlin file:
fun execute() {
  println("Executing from inside a kotlin file")
}
Enter fullscreen mode Exit fullscreen mode

Called by:

execute()
Enter fullscreen mode Exit fullscreen mode
  • Inside a Companion object:
class StaticFunctions {
  companion object {
    fun execute() {
      println("Executing from inside a companion object")
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Called by:

StaticFunctions.execute()
StaticFunctions.Companion.execute() // If you really wanted to...
Enter fullscreen mode Exit fullscreen mode
  • Inside a static object:
object StaticFunctions {
  fun execute() {
    println("Executing from inside a static object")
  }
}
Enter fullscreen mode Exit fullscreen mode
Called by:
Enter fullscreen mode Exit fullscreen mode
StaticFunctions.execute()
Enter fullscreen mode Exit fullscreen mode

Non-friendly static functions

The functions defined above are not friendly. This is how you would call each of them from Java:

  • Directly in a Kotlin file:
StaticFunctionsKt.execute();
Enter fullscreen mode Exit fullscreen mode
  • Inside a Companion object:
StaticFunctions.Companion.execute();
Enter fullscreen mode Exit fullscreen mode
  • Inside a static object:
StaticFunctions.INSTANCE.execute();
Enter fullscreen mode Exit fullscreen mode

They all look pretty bad. I would use more vulgar words if I wasn't writing...

  • StaticFunctionsKt.execute is not too bad, it is relatively close to a standard Java static function. Except, that it's clear that it came from a Kotlin file/library due to the Kt stuck onto the end.

  • StaticFunctions.Companion.execute is much worse as you have to reference the Companion object directly to access the function. Furthermore, mentioning the Companion object doesn't bring any extra clarity to the code, so even more reason to try and remove it.

  • StaticFunctions.INSTANCE.execute has the same problem as the Companion version.

Writing Java friendly static functions

The three ways of defining static functions in Kotlin can each have their Java interoperability improved through different routes.

JvmName

The @file:JvmName annotation can be added to the top of a Kotlin file to allow you to manually specify the file's name:

@file:JvmName("StaticFunctions")

package dev.lankydan

fun execute() {
  println("Executing from inside a kotlin file")
}
Enter fullscreen mode Exit fullscreen mode

This allows a function to be called from Java using the specified file name rather than the original name. Any name can be chosen for the file, but most of the time, giving it the same name as the original file will suffice (the Kt part is dropped from the end).

This can then be called as such:

StaticFunctions.execute();
Enter fullscreen mode Exit fullscreen mode

JvmStatic

The @JvmStatic annotation can be added to functions found in Companion and static objects:

  • Inside a Companion object:
class StaticFunctions {
  companion object {
    @JvmStatic
    fun execute() {
      println("Executing from inside a companion object")
    }
  }
}
Enter fullscreen mode Exit fullscreen mode
  • Inside a static object:
object StaticFunctions {
  @JvmStatic
  fun execute() {
    println("Executing from inside a static object")
  }
}
Enter fullscreen mode Exit fullscreen mode

@JvmStatic generates a new version of a function that is more suitable for Java callers.

You can then access the function just like any normal Java static function (both Companion and static objects can be called in the same way):

StaticFunctions.execute();
Enter fullscreen mode Exit fullscreen mode

Which one should you use

This is a question I am still trying to answer myself.

I currently believe that if you are writing a purely static function, you should add the function directly to the file (not inside a Companion or static object). The inclusion of the class clutters things up.

On the other hand, you should use a Companion or static object if you need to fulfil the following criteria:

  • A class/object must be directly referenced (such as passing an instance into another function)
  • Provide static functions

Summary

By using the @file:JvmName and @JvmStatic annotations, you can write static Kotlin functions that can be used from Java in a nice and friendly way. It doesn't matter how you define your static functions, as you have methods to make them all play better with Java.


If you enjoyed this post or found it helpful (or both) then please feel free to follow me on Twitter at @LankyDanDev and remember to share with anyone else who might find this useful!

Top comments (0)