One of the great wonders of Kotlin is that it’s fully integrated with Java. This means that although all your application code is written Java, you can create a class in Kotlin and use it from Java without any issues. Calling Kotlin from Java code can’t be easier.

This potentially gives you two advantages:

  • You can use Kotlin in a Java project: In any project you have already started, you can decide to start writing the new code in Kotlin. You can then call it from Java code.
  • If you have a mental block in Kotlin, you can do that part in Java: many people ask me if there is a case where Kotlin won’t be enough to do something on Android. In theory, everything can be done, but the fact is that it doesn’t matter. If you can’t do it in Kotlin, you can implement that part in Java.

Today we’re going to see how this compatibility works, and how Kotlin code looks when used from Java.

Calling Kotlin from Java: Package-level functions

In Kotlin, functions don’t need to be inside a class, but this isn’t the case in Java. How can we call a function then? Imagine that we have a file utils.kt that looks like this:

In Java we can access them through a class that will be called UtilsKt, with some static methods:

Extension functions

You’ve already seen from previous articles that I love extension functions. But how do they look in Java? Imagine that we have the following:

Want to learn Kotlin?

Check my free guide to create your first project in 15 minutes!

Note: although it may have appeared at some point, I haven’t explicitly talked about it. The arguments of a function may have default values. This means that if we don’t specify them, they’ll take the value specified in the declaration. This prevents us from using method overloading, as we tend to use in Java.

The function is applied over a ViewGroup. It receives a layout and inflates it using the parent view.

What would we get if we want to use it in Java?

As you can see, the object that applies this function (the receiver) is added as an argument to the function. In addition, the optional argument becomes mandatory, because in Java we can’t use default values.

Function overloads

If you want to generate the corresponding overloads in Java, you can use @JvmOverloads annotation for that function. That way, you wouldn’t need to specify the false in Java:

If you prefer to specify the name of the class when Kotlin from Java, you can use an annotation to modify it. In the file utils.kt, add this before the package:

And now the class in Java will be named:

Instance and static fields

In Java we use fields to store the state. They can be instance fields, which means that each object will have its own, or static (all instances of a class will share them).

If we try to find a mapping of this in Kotlin, it’d be the properties and the companion objects. If we have a class like this:

How will this work in Java? You can simply access the companion objects as static fields, and properties using getters and setters:

And you’ll see that the compiler doesn’t complain. Being val, it only generates the getter in Java. If it were var, we’d also have a setter.

Access to instance has worked automatically because it uses the lateinit annotation, which also exposes the field that Kotlin uses to store the state. But imagine we create a constant:

You’ll see that you can’t access to it directly. You will have to access through a Companion internal  class:

Which doesn’t look very good. To expose the field on Java the same way a static field would look, you’ll need a new annotation:

And now you can use it from Java code:

If you have functions in a companion object, they’re converted to static methods using the @JvmStatic annotation.

There are several ways to define constants that, when we use Kotlin from Java, generate different bytecode. I recommend you to take a look at this article from Egor Andreevici, where all this is explained in deep.

Data classes

Some things are kind of clear, but some others are a little more hard to predict how they’re going to work when calling Kotlin from Java. So let’s take a look to those features that Kotlin has but Java doesn’t. One example is data classes.

Let’s say we have a data class like this:

We are able to create instances of this class:

But are we missing something?

First, let’s check if equals works as expected:

Of course, the Toast is shown. The bytecode the class generates has everything it needs to compare the two items and, if the state is the same, then the items are also the same.

But there are other things that are more difficult to replicate. Remember the copy feature data classes have? The method is there, but you can only use it passing all arguments:

So it’s not better than just using the constructor. Also, we don’t have destructuring, as Java doesn’t allow constructs like those.

Sealed classes

Another thing that you may wonder is how sealed classes work when used from Java. Let’s try it:

We have a class Filter that represents a filter that can be applied to items. Of course, in Java we can’t do:

The switch in Java only accepts a small amount of types, and Java is seeing sealed classes as regular classes. So you can imagine how they’ll work:

As mentioned above, from Java sealed classes are just regular classes. So that’s the closest you can do to a Kotlin when. Missing auto-casting, right? 😅

Inline functions and reified types

As you may know, in Kotlin you can make generic functions use reified types. That way, you can use the generic type inside the function. But you may also remember that, in order to do this, it needs to use the reserved word inline, which will substitute the calls to the function by the body of the function when compiling. Can we use that from Java?

Let’s start with the inline functions, which are easier to test. If we have a toast function that receives a lambda for the message:

We can use it without issues like this from Java:

So inline works! But there’s an interesting thing here. When used from Kotlin, the decompiled code looks like this:

The function is being inlined as expected. But what happens when used from Java?

So, though you can use inline functions from Java, they are not really inlined. It’s calling the function and creating an object for the lambda. That’s an important thing to take into account.

Now what happens to reified types? This is a function that navigates to an activity specified in the generic type:

Then let’s try to call this function written in Kotlin from Java:

Oh! So we finally found something that can’t be used from Java. As you see, from Java this method appears to be private, so be cannot call it.

Conclusion

You see that it’s very simple to use the code we write in Kotlin from Java. Most things can still be used, though obviously we can’t take advantage of some Kotlin features from Java.

I hope that if you had any doubts, this convinced you to start using Kotlin in your projects. And if you really want to get serious, I recommend you take a look at the the rest of Kotlin articles where you can learn more about Kotlin.

Are you missing any Kotlin feature in the article? Let me know in the comments and I’ll investigate it and update the content.

Author: Antonio Leiva

I’m in love with Kotlin. I’ve been learning about it for a couple of years, applying it to Android and digesting all this knowledge so that you can learn it with no effort.

Shares
%d bloggers like this: