364

How is it recommended to create constants in Kotlin? And what's the naming convention? I've not found that in the documentation.

companion object {
    //1
    val MY_CONST = "something"

    //2
    const val MY_CONST = "something"

    //3
    val myConst = "something"
}

Or ...?

Marco Scabbiolo
  • 7,203
  • 3
  • 38
  • 46
Jodimoro
  • 4,355
  • 3
  • 11
  • 18
  • 11
    If you want something corresponding to a `public static final` field in Java, use `const val` in your companion object. If you want a `private static final` field and a public getter, use `val` in your companion object. – Michael May 18 '17 at 12:21
  • 8
    Here's the blogpost that explains ways to define constants in Kotlin: https://blog.egorand.me/where-do-i-put-my-constants-in-kotlin/ – Micer May 28 '18 at 06:20
  • 1
    Checkout [this article](https://blog.egorand.me/where-do-i-put-my-constants-in-kotlin/). It gives a nice overview of different ways in which you can store your constants, with related performance trade-offs. – firedrillsergeant Aug 09 '18 at 22:29
  • 1
    [At a glance, Val vs Const](https://stackoverflow.com/a/61836712/4694013) – Anoop M Maddasseri May 16 '20 at 15:12
  • 1
    https://kotlinlang.org/docs/coding-conventions.html#property-names – k4dima Oct 25 '22 at 20:22

15 Answers15

331

Avoid using companion objects. Under the hood, getter and setter instance methods are created for the fields to be accessible. Calling instance methods is technically more expensive than calling static methods.

public class DbConstants {
    companion object {
        val TABLE_USER_ATTRIBUTE_EMPID = "_id"
        val TABLE_USER_ATTRIBUTE_DATA = "data"
    }

Instead define the constants in object.

Recommended practice:

object DbConstants {
    const val TABLE_USER_ATTRIBUTE_EMPID = "_id"
    const val TABLE_USER_ATTRIBUTE_DATA = "data"
}

and access them globally like this: DbConstants.TABLE_USER_ATTRIBUTE_EMPID

lwei
  • 55
  • 2
  • 6
Extremis II
  • 5,185
  • 2
  • 19
  • 29
  • Isn't a companion object a special case of an object? How can a `const val` in a companion object be any different than a `const val` in an ordinary object (i.e. the only difference between your examples seems to be that you omitted `const` in the companion object case - if you add `const`, the examples should have the same performance) – Erwin Bolwidt Feb 03 '19 at 23:57
  • 3
    @ErwinBolwidt I think @sudesh's point is that one should not use the class-wrapping-companion-object design when the sole purpose of the structure is to provide a namespace for some constant values. But if your structure needs to be instantiable and also enclose a couple of `const val`s, declaring a `companion object` is correct. – Ari Lacenski Feb 06 '19 at 19:03
  • 17
    @ErwinBolwidt: sudesh is right, generated bytecode for companion objects involves additional object creation with getters under the hood. For a good explanation with decompiled kotlin examples see https://blog.egorand.me/where-do-i-put-my-constants-in-kotlin/ – dominik Mar 13 '19 at 15:58
  • 2
    thanks @dominik, this is a very detailed article, I recommend this to everyone who wants to understand this in depth, there are many cases where kotlin produces suboptimal bytecode, jetbrains have resolved many such performance related bugs... keep an eye on https://discuss.kotlinlang.org/ , you will be informed about many such underlying aspects. – Extremis II Mar 13 '19 at 18:52
  • That's an interesting article but isn't it true to say that in the JVM, a tiny method containing only `return FOO;` would immediately be inlined by the JIT compiler? – mjaggard Dec 17 '20 at 11:26
  • 6
    Companion object is also an object. Not sure why this is so highly upvoted.. Technically yes, you can make the class into object if you want to make it singleton. But this might broadcast the idea to "not use companion object" at all, which is just false. You can use `const val` in companion objects too. – EpicPandaForce Apr 07 '21 at 12:35
  • In this case, a useless object instance will also be created. I don't think this is the recommended solution. – RareScrap Jun 09 '21 at 08:15
  • @RareScrap, Depends on your use-case, If the constant is used only by the class declaring it, a top-level declaration is enough but remember that each instance will take additional memory. However, If you want it to be accessed by other objects you need to use a static instance. So from a memory perspective, it doesn't matter if you use a companion object or object. – Extremis II Jun 09 '21 at 13:43
  • The statement "Avoid using companion objects" is very misleading. Avoid it if all the companion object is going to be used for is just defining constants. BUT definitely use it where you need a singleton with supporting functions. – Johann Aug 06 '21 at 10:39
  • 5
    For those interested in the article but couldn't access @dominik's link above. Here is the working link: https://www.egorand.dev/where-should-i-keep-my-constants-in-kotlin/ – Ivan Agrenich Feb 02 '22 at 12:49
  • The first example allows instantiation just like the keyword `new` in Java. If you do not want or need instantiation of class then the second example is the correct Singleton equivalent of Kotlin in Java. – Bitwise DEVS Feb 08 '22 at 14:13
  • @ExtremisII In Swift I store constants in Enum, and I see Kotlin has enum too and I have created a Enum to store my constants in Kotlin, so `Enum` vs `object class` which one is better option for Kotlin? – Zhou Haibo Nov 18 '22 at 06:16
186

In Kotlin, if you want to create local constants which are supposed to be used within the class, then you can create it like below:

val MY_CONSTANT = "Constants"

And if you want to create a public constant in Kotlin like public static final in Java, you can create it as follows:

companion object {    
    const val MY_CONSTANT = "Constants"    
}
Scott Stanchfield
  • 29,742
  • 9
  • 47
  • 65
AaRiF
  • 2,980
  • 2
  • 14
  • 13
  • 3
    How would I use it in a separate file like a new file named `Constants.kt` or how? – Naveed Abbas Jul 11 '18 at 10:00
  • 2
    i use a file for constants. keep all my constants in there. – filthy_wizard Jul 17 '18 at 14:36
  • 4
    you do not need the `companion object` I think @piotrpo answer should be the accepted one – Chiara Sep 11 '18 at 05:49
  • 2
    @Chiara the companion object (and its enclosing class) serves as a namespace, as opposed to top level declarations. I think both answers can make sense depending on the situation. – jingx Dec 19 '18 at 14:28
  • 4
    Actually, name `MY_CONSTANT` for within class field is not a good idea - compiler warns about it with message **"Private property name 'MY_CONSTANT' should not contain underscores in the middle or the end"**. It breaks recommended naming convection. – Daniel Sep 06 '19 at 15:00
  • @cris imho use `companion object` `const val` for constants is the best practice – Daniel Sep 23 '20 at 15:33
117

First of all, the naming convention in Kotlin for constants is the same than in java (e.g : MY_CONST_IN_UPPERCASE).

How should I create it?

1. As a top-level value (recommended)

You just have to put your const outside your class declaration.

Two possibilities: Declare your const in your class file (your const have a clear relation with your class)

private const val CONST_USED_BY_MY_CLASS = 1

class MyClass { 
    // I can use my const in my class body 
}

Create a dedicated constants.kt file where to store those global const (Here you want to use your const widely across your project):

package com.project.constants
const val URL_PATH = "https:/"

Then you just have to import it where you need it:

import com.project.constants

MyClass {
    private fun foo() {
        val url = URL_PATH
        System.out.print(url) // https://
    }
}

2. Declare it in a companion object (or an object declaration)

This is much less cleaner because under the hood, when bytecode is generated, a useless object is created:

MyClass {
    companion object {
        private const val URL_PATH = "https://"
        const val PUBLIC_URL_PATH = "https://public" // Accessible in other project files via MyClass.PUBLIC_URL_PATH
    }
}

Even worse if you declare it as a val instead of a const (compiler will generate a useless object + a useless function):

MyClass {
    companion object {
        val URL_PATH = "https://"
    }
}

Note :

In kotlin, const can just hold primitive types. If you want to assign it the result of calling a function, you need to add the @JvmField annotation. At compile time, it will be transform as a public static final variable. But it's slower than with a primitive type. Try to avoid it.

@JvmField val foo = Foo()
moffeltje
  • 4,521
  • 4
  • 33
  • 57
A.Mamode
  • 1,467
  • 1
  • 8
  • 7
  • 2
    this should be the accepted answer. anyway in a case like: public static final Pattern REGEX_NOTEMPTY = Pattern.compile(".+") ???? – Alessandro Scarozza Feb 10 '20 at 11:17
  • where is this "recommended"? Got a link to an official Kotlin resource? – treesAreEverywhere Jan 04 '21 at 21:56
  • when I did something like `private const val CONST_USED_BY_MY_CLASS = 1` above class definition as you suggested, Android studio 4.1.1 started displaying my *.kt file in which I added this line as "unresolved" inside project tree. It did not have any affect on compilation, but once I noticed it it became very annoying. Hope it will be fixed soon – artman Jan 13 '21 at 21:55
  • @treesAreEverywhere See https://kotlinlang.org/docs/coding-conventions.html#property-names : "Names of constants ... should use uppercase underscore-separated ... names" – simpleuser Aug 10 '22 at 17:29
32

You don't need a class, an object or a companion object for declaring constants in Kotlin. You can just declare a file holding all the constants (for example Constants.kt or you can also put them inside any existing Kotlin file) and directly declare the constants inside the file. The constants known at compile time must be marked with const.

So, in this case, it should be:

const val MY_CONST = "something"

and then you can import the constant using:

import package_name.MY_CONST

You can refer to this link

nik7
  • 806
  • 3
  • 12
  • 20
Abdul Wadood
  • 1,161
  • 1
  • 10
  • 18
  • 32
    Constants must be in the class they are related to. If you make a 'Constants' class you will end, eventually, will hundreds of constants inside it. P.e: MAX_WIDTH, MAX_HEIGHT must be in the Screen class so you can access to it logically: Screen.MAX_WIDTH and you don't need to put Constants.SCREEN_MAX_WIDTH which will be duplicated with Constants.SCR_MAX_W and Constants.MAX_WIDTH in 2 years because NOBODY scrolls hundreds/thousans lines down when they push Ctrl+space to autocomplete. Seriously: don't do it. leads to unmaintainability – inigoD Apr 04 '18 at 15:52
  • 1
    @inigoD That's true if you use the constant in one place or only in children, but this is hardly ever the case. If you put the constant in an obscure class then you forget about it or more likely you take over a code base, you might duplicate them. Or it's not obvious where to put them. The source or the destination? You can create several constant files, that are easy to find. One for preference keys, one for request keys, one for view constants, etc. – Herrbert74 May 04 '18 at 16:22
  • 2
    @Herrbert74 I'm sorry but I have to disagree with you. I agree on that sometimes it can be hard to find which is, but a constant place should always be the class which is more related to it. And saving them randomly in a random number files is not the best way if you wish to retrieve them later... You will argue that they would not be randomly stored but in packages the constants are related to, but that is only an excuse to not put them in the classes they are related to which is, at the end, their place... – inigoD May 31 '18 at 15:13
  • 6
    If a constant is truly global or has a large scope... such as a value for an annotation used across all packages, or a Header name that is being fetched by multiple Controllers, etc, then it is completely acceptable to create a "constants class" that is scoped appropriately. However, constants that are only used in specific contexts, should be scoped to that context, and declared in the relevant class. – Nephthys76 Jun 22 '18 at 15:31
  • @Nephthys76 Just as a note, for "_such as a value for an annotation used across all packages_" specifically, I would say the best place for the constant is in the annotation class. – Slaw Apr 07 '20 at 18:46
31

Values known at compile time can (and in my opinion should) be marked as constant.

Naming conventions should follow Java ones and should be properly visible when used from Java code (it's somehow hard to achieve with companion objects, but anyway).

The proper constant declarations are:

const val MY_CONST = "something"
const val MY_INT = 1
piotrpo
  • 12,398
  • 7
  • 42
  • 58
  • 5
    `Naming conventions should follow Java ones` - why? – Jodimoro May 18 '17 at 05:20
  • 7
    Kotlin usually follows Java conventions by default, if not specified otherwise, to make the interop smooth. – zsmb13 May 18 '17 at 05:29
  • 5
    Is specified like that in the documentation @Jodimoro http://kotlinlang.org/docs/reference/coding-conventions.html – the-ginger-geek May 18 '17 at 06:12
  • 3
    @Neil, it's not. – Jodimoro May 18 '17 at 08:55
  • 14
    In that link I posted they say `If in doubt, default to the Java Coding Conventions` – the-ginger-geek May 18 '17 at 09:00
  • @zsmb13 I understand your point, but let's presume the (possible) case where Kotlin becomes the primary language, one day subsuming Java. In this case, we have cruft because of all these lingering cases where Kotlin "looks like" Java. I understand the need for ! and !!, but we should try to minimize the cases where we're making Kotlin look like Java just because they are usually used together. – Mike Williamson Nov 13 '18 at 21:07
  • 1
    Let's assume Java disappears overnight and we don't have to keep this convention around for interop's sake. It's still a pretty good way to mark constant values, as it will be familiar for many developers. Java had a lot of baggage, sure, but this naming convention is pretty okay as far as things go, I see no reason why we wouldn't keep it. – zsmb13 Nov 14 '18 at 06:01
12

If you put your const val valName = valValue before the class name, this way it will creates a

public static final YourClass.Kt that will have the public static final values.

Kotlin:

const val MY_CONST0 = 0
const val MY_CONST1 = 1
data class MyClass(var some: String)

Java decompiled:

public final class MyClassKt {
    public static final int MY_CONST0 = 0;
    public static final int MY_CONST1 = 1;
}
// rest of MyClass.java
MostafaMashayekhi
  • 27,359
  • 3
  • 21
  • 39
10

Like val, variables defined with the const keyword are immutable. The difference here is that const is used for variables that are known at compile-time.

Declaring a variable const is much like using the static keyword in Java.

Let's see how to declare a const variable in Kotlin:

const val COMMUNITY_NAME = "wiki"

And the analogous code written in Java would be:

final static String COMMUNITY_NAME = "wiki";

Adding to the answers above -

@JvmField an be used to instruct the Kotlin compiler not to generate getters/setters for this property and expose it as a field.

 @JvmField
 val COMMUNITY_NAME = "Wiki"

Static fields

Kotlin properties declared in a named object or a companion object will have static backing fields either in that named object or in the class containing the companion object.

Usually these fields are private but they can be exposed in one of the following ways:

  • @JvmField annotation;
  • lateinit modifier;
  • const modifier.

More details here - https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#instance-fields

c-an
  • 3,543
  • 5
  • 35
  • 82
Anoop M Maddasseri
  • 10,213
  • 3
  • 52
  • 73
7

local constants:

const val NAME = "name"

Global constants:

object MyConstants{
    val NAME = "name"
    val ID = "_id"
    var EMAIL = "email"
}

access MyConstants.NAME

Amjed Baig
  • 410
  • 5
  • 9
  • one question; is it better define an object type like this and put the constant values inside it or to create a normal class and define a companion object which contains the constant variables. which way must be preferred? – Ekin Yücel Oct 07 '20 at 11:13
  • 1
    @EkinYücel `object`, for sure, if you have no non-static code at all. It cleans up the imports - if you put it in a companion object then people have to import `MyConstants.Companion.NAME`. Plus, you'd also want to mark the constructor as private. A lot of work to avoid using a convenient language feature. – Hakanai Nov 29 '22 at 23:47
7

There are a few ways you can define constants in Kotlin,

Using companion object

    companion object {
        const val ITEM1 = "item1"
        const val ITEM2 = "item2"
    }

you can use above companion object block inside any class and define all your fields inside this block itself. But there is a problem with this approach, the documentation says,

even though the members of companion objects look like static members in other languages, at runtime those are still instance members of real objects, and can, for example, implement interfaces.

When you create your constants using companion object, and see the decompiled bytecode, you'll something like below,

  ClassName.Companion Companion = ClassName.Companion.$$INSTANCE;
  @NotNull
  String ITEM1 = "item1";
  @NotNull
  String ITEM2 = "item2";
 
  public static final class Companion {
     @NotNull
     private static final String ITEM1 = "item1";
     @NotNull
     public static final String ITEM2 = "item2";
     
     // $FF: synthetic field
     static final ClassName.Companion $$INSTANCE;

     private Companion() {
     }

     static {
        ClassName.Companion var0 = new ClassName.Companion();
        $$INSTANCE = var0;
     }
  }

From here you can easily see what the documentation said, even though the members of companion objects look like static members in other languages, at runtime those are still instance members of real objects It's doing extra work than required.

Now comes another way, where we don't need to use companion object like below,

object ApiConstants {
      val ITEM1: String = "item1"
 }

Again if you see the decompiled version of the byte code of above snippet, you'll find something like this,

public final class ApiConstants {
     private static final String ITEM1 = "item1";

     public static final ApiConstants INSTANCE;

     public final String getITEM1() {
           return ITEM1;
      }

     private ApiConstants() {
      }

     static {
         ApiConstants var0 = new ApiConstants();
         INSTANCE = var0;
         CONNECT_TIMEOUT = "item1";
      }
    }

Now if you see the above decompiled code, it's creating get method for each variable. This get method is not required at all.

To get rid of these get methods, you should use const before val like below,

object ApiConstants {
     const val ITEM1: String = "item1"
 }

Now if you see the decompiled code of above snippet, you'll find it easier to read as it does the least background conversion for your code.

public final class ApiConstants {
    public static final String ITEM1 = "item1";
    public static final ApiConstants INSTANCE;

    private ApiConstants() {
     }

    static {
        ApiConstants var0 = new ApiConstants();
        INSTANCE = var0;
      }
    }

So this is the best way to create constants.

xehpuk
  • 7,814
  • 3
  • 30
  • 54
Abhishek Kumar
  • 4,532
  • 5
  • 31
  • 53
  • In the first decompiled code: why is ITEM1 private, but ITEM2 public? In the second decompiled code: where did `CONNECT_TIMEOUT` come from? – izogfif May 05 '22 at 05:42
6
class Myclass {

    companion object {
        const val MYCONSTANT = 479
    }
}

you have two choices you can use const keyword or use the @JvmField which makes it a java's static final constant.

class Myclass {

    companion object {
        @JvmField val MYCONSTANT = 479
    }
}

If you use the @JvmField annotation then after it compiles the constant gets put in for you the way you would call it in java.
Just like you would call it in java the compiler will replace that for you when you call the companion constant in code.

However, if you use the const keyword then the value of the constant gets inlined. By inline i mean the actual value is used after it compiles.

so to summarize here is what the compiler will do for you :

//so for @JvmField:

Foo var1 = Constants.FOO;

//and for const:

Foo var1 = 479
dStulle
  • 609
  • 5
  • 24
j2emanue
  • 60,549
  • 65
  • 286
  • 456
6

Something that isn't mentioned in any of the answers is the overhead of using companion objects. As you can read here, companion objects are in fact objects and creating them consumes resources. In addition, you may need to go through more than one getter function every time you use your constant. If all that you need is a few primitive constants on a few instances of your class, you'll probably just be better off using val to get a better performance and avoid the companion object. The trade off is higher memory consumption if you have many instances of your class so everyone should make their own decision.

TL;DR; of the article:

Using companion object actually turns this Kotlin code:

class MyClass {

    companion object {
        private val TAG = "TAG"
    }

    fun helloWorld() {
        println(TAG)
    }
}

Into this Java code:

public final class MyClass {
    private static final String TAG = "TAG";
    public static final Companion companion = new Companion();

    // synthetic
    public static final String access$getTAG$cp() {
        return TAG;
    }

    public static final class Companion {
        private final String getTAG() {
            return MyClass.access$getTAG$cp();
        }

        // synthetic
        public static final String access$getTAG$p(Companion c) {
            return c.getTAG();
        }
    }

    public final void helloWorld() {
        System.out.println(Companion.access$getTAG$p(companion));
    }
}
Sir Codesalot
  • 7,045
  • 2
  • 50
  • 56
6

Kotlin static and constant value & method declare

object MyConstant {

@JvmField   // for access in java code 
val PI: Double = 3.14

@JvmStatic // JvmStatic annotation for access in java code
fun sumValue(v1: Int, v2: Int): Int {
    return v1 + v2
}

}

Access value anywhere

val value = MyConstant.PI
val value = MyConstant.sumValue(10,5)
Shomu
  • 2,734
  • 24
  • 32
0

For primitives and Strings:

/** The empty String. */
const val EMPTY_STRING = ""

For other cases:

/** The empty array of Strings. */
@JvmField val EMPTY_STRING_ARRAY = arrayOfNulls<String>(0)

Example:

/*
 * Copyright 2018 Vorlonsoft LLC
 *
 * Licensed under The MIT License (MIT)
 */

package com.vorlonsoft.android.rate

import com.vorlonsoft.android.rate.Constants.Utils.Companion.UTILITY_CLASS_MESSAGE

/**
 * Constants Class - the constants class of the AndroidRate library.
 *
 * @constructor Constants is a utility class and it can't be instantiated.
 * @since       1.1.8
 * @version     1.2.1
 * @author      Alexander Savin
 */
internal class Constants private constructor() {
    /** Constants Class initializer block. */
    init {
        throw UnsupportedOperationException("Constants$UTILITY_CLASS_MESSAGE")
    }

    /**
     * Constants.Date Class - the date constants class of the AndroidRate library.
     *
     * @constructor Constants.Date is a utility class and it can't be instantiated.
     * @since       1.1.8
     * @version     1.2.1
     * @author      Alexander Savin
     */
    internal class Date private constructor() {
        /** Constants.Date Class initializer block. */
        init {
            throw UnsupportedOperationException("Constants.Date$UTILITY_CLASS_MESSAGE")
        }

        /** The singleton contains date constants. */
        companion object {
            /** The time unit representing one year in days. */
            const val YEAR_IN_DAYS = 365.toShort()
        }
    }

    /**
     * Constants.Utils Class - the utils constants class of the AndroidRate library.
     *
     * @constructor Constants.Utils is a utility class and it can't be instantiated.
     * @since       1.1.8
     * @version     1.2.1
     * @author      Alexander Savin
     */
    internal class Utils private constructor() {
        /** Constants.Utils Class initializer block. */
        init {
            throw UnsupportedOperationException("Constants.Utils$UTILITY_CLASS_MESSAGE")
        }

        /** The singleton contains utils constants. */
        companion object {
            /** The empty String. */
            const val EMPTY_STRING = ""
            /** The empty array of Strings. */
            @JvmField val EMPTY_STRING_ARRAY = arrayOfNulls<String>(0)
            /** The part 2 of a utility class unsupported operation exception message. */
            const val UTILITY_CLASS_MESSAGE = " is a utility class and it can't be instantiated!"
        }
    }
}
Alexander Savin
  • 1,952
  • 1
  • 15
  • 30
0

I figured this would the best way to put all the constants for a package in same file and as mentioned in other answers this avoid creating companion object which makes this performant and very similar to Java Constants class.

class Constants {
    object Analytics {
        const val PROJECT_OPEN = "project_open"
        const val PROJECT_CLOSE = "project_close"
    }

    object HTTP {
        const val BASE_URL = "x.y.com"
    }

    object DBConst {
        const val TABLE_NAME = "abc"
    }
}

This can be referred from the code like this making it very structured.

Constants.Analytics.PROJECT_OPEN
Constants.HTTP.BASE_URL
Constants.DBConst.TABLE_NAME
Arpit Ratan
  • 2,976
  • 1
  • 12
  • 20
-1

In Kotlin, when we declare variable(s) we have two options. 'var' or 'val'. Following naming convention for variable(s), I think we may simply generate 'constant' which means I want a fixed value assigned to a specific variable like following example code.

private val tag = "MainActivity"

I think we don't need to bother using capital letters to distinguish 'constant(s)' from variables like we have been doing in Java world.

D.Y Won
  • 245
  • 3
  • 5