1. Overview
Kotlin’s type system aims to eliminate certain common errors in other languages but also introduces its unique concepts and distinctions. One such distinction lies in the usage of Int and Integer. While they may appear to be interchangeable to the untrained eye, there are subtle differences between the two that can impact the performance and functionality of your code.
This tutorial aims to clarify these differences, comprehensively comparing Int and Integer in Kotlin, including their use cases, performance implications, and the phenomena of boxing and unboxing.
2. The Integer Type
Kotlin was created with Java interoperability in mind. This means that Kotlin might use Java Libraries and Java code.
In this case, Integer is an original Java class that we can use in Kotlin. However, using Integer directly in Kotlin code is not recommended as Kotlin has specific types for this. In some IDEs, we might see the following message:
This class shouldn't be used in Kotlin. Use Kotlin Int instead.
Thus, Integer behaves and has the same characteristics as a plain Java Integer wrapper class, and the main difference is that Integer isn’t native to Kotlin.
3. The Int Type
In Kotlin, Int is a primitive data type. A primitive type is the simplest data type provided natively by a programming language. Int stores integer values, i.e., whole numbers without a fractional component. It ranges from -2,147,483,648 to 2,147,483,647, making it capable of handling the most common numeric data storage needs:
val i: Int = 5
An Int in Kotlin occupies 4 bytes of memory. This is the same across all platforms, ensuring consistent code behavior and performance.
Int is the subject of usual type inference rules*,* meaning that we don’t always have to explicitly state the type of a variable when we declare it. Kotlin will infer the type of the variables whose values are in the Int range. This way, Int is similar to the int primitive type in Java:
val i = 42
In Kotlin and Java, it’s not possible to parametrize generic types with primitives. However, Kotlin provides a transparent solution and will silently transform Int to Integer if used for parametrization. It’s true for direct parametrization and creating collections, for example, with the listOf() method:
val list: List<Int> = listOf(4, 2)
Kotlin has specialized classes for collections of primitive types that avoid boxing, like IntArray, DoubleArray, etc.
4. The Int and Integer Interoperability
Kotlin ensures smooth interoperability between Int and Integer with Java. When interacting with Java methods, Kotlin allows using Int where int or Integer is required, and vice versa. Kotlin compiler does this through automatic type mappings.
However, it’s important to remember that Int and Integer are not equivalent. Int is a primitive type in Kotlin, while Integer is a nullable reference type. When a nullable type is needed, the compiler boxes Int values into Integer objects.
Boxing may impact performance due to the overhead of boxing and unboxing operations, especially in performance-critical code or large data sets. Classes like IntArray help to avoid such overhead when dealing with collections of primitive types.
5. The Int? Type
Another type widely used in Kotlin is Int?, which is a fusion between Java Integer type and Kotlin Int. This is called a nullable Int. This type corresponds to Integer Java but with Kotlin notation. Int? in Kotlin is a nullable type that can hold either a non-null Int value or null.
By using Int? we can explicitly instruct Kotlin to treat variables as an Integer instead of primitive. This might be helpful if the code should account for null values or interoperability reasons. However, boxing can have performance implications due to the overhead of boxing and unboxing operations.
While Int? and Integer seems similar, Int and Int? provide a better granularity in terms of nullable values. Thus it’s better to avoid using Integer directly if possible. Also, Int? is still a Kotlin type, not a Java type.
6. Conclusion
One of the main goals of Kotlin was to eliminate null reference errors. Int and Int? types provide better granularity and security against NPEs.
At the same time, Int can be transparently translated to boxed values and used to parametrize generic classes. This feature eliminated unnecessary boilerplate code. A general recommendation is to use the specialized classes for collections of primitive types whenever possible to avoid the overhead of boxing.
Remember that Integer in Kotlin code might produce unexpected errors and doesn’t protect against null reference errors.