Authors Top

If you have a few years of experience with the Kotlin language and server-side development, and you’re interested in sharing that experience with the community, have a look at our Contribution Guidelines.

1. Overview

In this article, we’ll describe the best practices for constants in Kotlin. Firstly, we’ll list allowed constant types. Afterward, we’ll define the constant at the top level and in a companion object. Finally, we’ll show how to access Kotlin’s static objects from Java.

2. Allowed Constant Types

The Kotlin language only allows defining constants of primitive types (number types, characters, and booleans) and String.

Let’s try to define a constant with a defined type. Firstly, let’s create an empty class without any logic:

class SimpleClass {
}

Now, let’s try to use it in the constant declaration:

const val constantAtTopLevel : = SimpleClass()

After that, the compiler gives us an error:

Const 'val' has type 'SimpleClass'. Only primitives and String are allowed

3. Constant at Top-Level Declaration

We should first note that Kotlin doesn’t match a file with a class. In one file, we can define multiple classes. Unlike Java, Kotlin doesn’t require a single top-level class per file. Each file can have multiple top-level classes.

Files can also have functions and variables outside of a class. These functions and variables are directly accessible.

Let’s create a constant in the ConstantsBestPractices.kt file:

const val CONSTANT_AT_TOP_LEVEL = "constant value defined at the top-level"

Now, let’s access it from another class:

class ConstantAtTopLevelTest {
    @Test
    fun whenAccessingConstantAtTopLevel_thenItWorks() {
        Assertions.assertThat(CONSTANT_AT_TOP_LEVEL).isEqualTo("constant value defined at the top-level")
    }
}

First, we defined the constant CONSTANT_AT_TOP_LEVEL outside of the class. After that, we tested that it is accessible from the ConstantAtTopLevelTest class.

It works in the class from the example. In fact, the constant is accessible from any class.

If we declare a constant as private, it will only be accessible by other classes in the same file.

The top-level constant is a perfect solution when we want to share the value between classes inside a file or in the whole application. Additionally, using a top-level constant is an excellent option when the value has no relation to a particular class.

4. Limitations of Top-Level Declaration

Despite its simplicity, we should note a couple of limitations we’re faced with when declaring top-level constants.

First of all, as mentioned above, a constant defined at the top level of a file is accessible by any class in the same file, even if it is private. We can’t limit the visibility to a particular class in that file. Because of that, such constants aren’t associated with any class.

Additionally, for the top-level constants, the compiler generates a new class. This is necessary because, ultimately, the constant must be located somewhere. For that purpose, the compiler creates a class with the name of the original file suffixed with Kt. In our case, it’s ConstantAtTopLevelTestKt, where the original file name is ConstantAtTopLevelTest.kt.

5. Define Constants in Companion Object

Now, let’s define a constant in a companion object:

class ConstantsBestPractices {
    companion object {
        const val CONSTANT_IN_COMPANION_OBJECT = "constant at in companion object"
    }
}

After that, let’s access it from our ConstantInCompanionObjectTest class:

class ConstantInCompanionObjectTest {

    @Test
    fun whenAccessingConstantInCompanionObject_thenItWorks() {
        Assertions.assertThat(CONSTANT_IN_COMPANION_OBJECT).isEqualTo("constant in companion object")
    }
}

The ConstantInCompanionObjectTest class contains an import of the constant:

import com.baeldung.constants.ConstantsBestPractices.Companion.CONSTANT_IN_COMPANION_OBJECT

This is necessary because the field belongs to a class. Defining the constant in a companion object is a perfect solution when we want to associate the value with the class. We access it via the class context.

6. Static Value Accessible From Java Code

Finally, let’s have a look at static object accessibility from Java code. Let’s create a simple example with two constants:

const val CONSTANT_AT_TOP_LEVEL = "constant at top level"

class ConstantsBestPractices {
    companion object {
        const val CONSTANT_IN_COMPANION_OBJECT = "constant at in companion object"
    }
}

There’s one constant at the top level and one in the companion object.

Let’s now create an AccessKotlinConstant Java class and use the created constants:

public class AccessKotlinConstant {
    private String staticObjectFromTopLevel = ConstantsBestPracticesKt.CONSTANT_AT_TOP_LEVEL;
    private String staticObjectFromCompanion = ConstantsBestPractices.CONSTANT_IN_COMPANION_OBJECT;
}

Firstly, the constant at the top-level declaration is accessible from Java with the generated class name suffixed with Kt. On the other hand, the companion object constant is accessible directly via the class name.

7. Conclusion

In this short article, we described constant definitions in Kotlin both at the top level and in a companion object. Additionally, we showed how to access both types of constants from a Java class.

As always, the source code of the examples is available over on GitHub.

Authors Bottom

If you have a few years of experience with the Kotlin language and server-side development, and you’re interested in sharing that experience with the community, have a look at our Contribution Guidelines.

Comments are closed on this article!