Declaring Variables
Let’s look at the different ways of declaring a variable and type inference in Kotlin.
We'll cover the following
Overview
Let’s start with the very first line of the given code. It is a declaration of the variable strings
, followed by its initialization:
val strings = listOf("Hello", "World", "!")val lengths = strings.map { it.length }println(lengths)
We can see the val
keyword which does not exist in Java yet.
Note: There is a similar
var
since Java 10, which is at least part of the solution.
The declaration of the variable’s type also seems to be missing. How is this possible, given that Kotlin is a strongly typed language?
To get to the bottom of these questions, let’s have a look at a similar example in Java:
Here is a declaration of the variable i
, of the int
type in Java, which is initialized directly with the value, 42
:
int i = 42;
In Kotlin, the same variable declaration looks like this:
var i : Int = 42
This looks a bit reversed, compared to Java. Variable declarations in Kotlin do not begin with the type of the variable but always with the keyword,
var
orval
(the difference between these two will be explained shortly). This is followed by the name of the variable.
Finally, to specify the type, it is immediately noted after a :
.
It is important to note that the capital I
in Int
is not a spelling mistake. It’s because Kotlin does not know primitives, which we will talk in more detail about later. If you like, you can initialize the variable with an assignment just like in Java, as done in the example.
Should we use var or val?
The difference between declaring a variable with var
or val
is the same as the one between these two in Java:
int i = 42;
final int i = 42;
Variables that are declared with var
(variable) can be assigned a different value later. However, those with val
(value) cannot.
Like Java, the same applies here. Only the variable itself may be immutable. If the object referenced is mutable, it can be altered by appropriate methods or properties, regardless of whether it is declared with val
or var
.
Type inference
If we look closely, we will notice that we did not specify its type when declaring strings
in the original example. In most cases, this is not necessary. Rather, the Kotlin compiler can often recognize the type of a variable via the so-called type inference if an initialization follows the declaration directly.
That’s why it’s enough to write the following:
var i = 42
var map = HashMap<String, Collection<Long>>()
We don’t need to write this, as we do in Java:
HashMap<String, Collection<Long>> map = HashMap<>()
The code above only really became readable with the introduction of the diamond operator <>
in Java 7.
In the example discussed at the beginning of this lesson, the Kotlin compiler automatically determines that strings
is of the List<String>
type. This is inferred from the return type of the standard function, listOf
, which is List<T>
. Here, T
is the type of each element.
Therefore, thanks to the smart Kotlin compiler, we are usually spared from manual type specifications.
Of course, we can still add manual type specifications. For example, we can widen the type to Collection<String>
or make other specifications simply because they meet our personal taste (or the project’s style guide).
Even though we have not even mentioned the ‘built-in’ listOf
function, as a Java developer, you can probably guess its signature. In Java, it would look something like this:
public static <T> List<T> listOf(T ... elements)
As a static method embedded in a utility class, let’s call it CollectionUtils
.
We could have imported it statically (not shown) to call it without the CollectionUtils.
prefix.
In Kotlin, this is done quite similarly. However, the signature is syntactically a bit different, and Kotlin even allows us to declare functions at the top level, without any class ‘surrounding’ it.