Hello everyone, welcome to another article from the Kotlin Decoded series! From this one, you’ll learn how to create variables in Kotlin, what are nullable and primitive types in Kotlin, and how Kotlin’s visibility modifiers are different from Java’s. You’ll also understand the difference between var
, val
, and const val
.
The tutorial is packed with examples and comparisons for you to really understand the topic. As a bonus, you’ll learn how to translate Kotlin to Java and vice versa in IntelliJ Idea. Let's get going!
Table of Contents
1. Variables
◦ val and var — type inference 😊
◦ What the heck is const val? 🤷
◦ Kotlin loves val ❤️
2. Data types
◦ Unsigned data types
◦ Nullable types ❓
◦ Wrappers vs primitive types 📦
◦ Unit and Nothing types
3. How to translate Kotlin to Java and vice versa? 🔀
Variables
After learning how to write the main function in Kotlin, let’s understand the most used thing in any programming language — variables.
val
and var
— type inference 😊
Java:
int a = 1;
Kotlin:
var a = 1
Kotlin is going to determine the data type from the value you assign to the variable. (In IntelliJ Idea press Ctrl+Shift+P to see the data type). If you don't assign any value, you should specify it explicitly. (See the snippets below)
var
is short for variable, but if you want it to be immutable, use val
. (See the snippets below)
Java:
final int number;
number = 0;
Kotlin:
val number: Int
number = 0
BTW, from JDK 10 we can use var
in Java either. Thanks to that, it’s possible to write things like this in Java:
var i = true ? 1 : "ABC";
However, I wouldn’t use it for creating mutable variables in Java, when it can be done in the old way because everyone is used to it and it may also break backward compatibility, as you won't be able to downgrade to the Java version below 10. In addition, there is no val
type name in Java.
What the heck is const val
? 🤷
If you are curious, you are probably going to meet const val
even though we haven’t yet studied classes. If val
makes a field immutable, what does const val
do?
The critical difference between val
and const val
in Kotlin is that the former is known at the runtime, while the latter is put into memory at the compile time. That’s why const val
is more efficient.
In fact, const val
is an equivalent of the public static final
in Java. So if you don’t understand the difference between final
and static final
in Java, you won’t understand this concept in Kotlin either. So here is the explanation.
In Java, you may want to use a non-static final
variable, when it’s unique for each object and you don’t need to change it.
public class Person {
final String name;
public Person(String name) {
this.name = name;
}
public Person() {
name = "Default name";
}
}
This way each instance of Person
will have its own name, provided in the constructor. But you can also give it a default value.
I think you should also declare it private
and create getters for it. That’s because if you eventually realize that the variable actually can be mutable, you simply remove the final
keyword and don’t break the program.
However, if you want the same shared immutable variable for all objects, make it public static final
in Java or const val
in Kotlin.
Kotlin doesn't have the static
keyword, but this will be discussed later in the series.
Kotlin loves val
❤️
In addition, it’s good practice to make a field final if you don’t change its value. IDE will notify you about it. Kotlin creators strongly encourage using val
whenever possible. And when it comes to function parameters in Kotlin, you don't even have a choice. You simply can't make them mutable. Whereas in Java a final
keyword before an argument can be rarely seen.
Data types
Kotlin has all the Java data types, but there are some nuances as well as some unique data types in Kotlin.
Unsigned data types
Unlike Java, Kotlin supports unsigned data types (java has some methods that may simulate unsigned types, but there is no actual support for them). These are data types similar to the default ones but with a u
tag, for example, uInt
. The variables of these types may have only a non-negative value. The advantage of using them is an increase in the maximum positive value that can be represented.
For example, a signed bit can represent values from -128 to 127, while an unsigned bit can represent values from 0 to 255.
But it's not recommended to use them whenever you plan the variable to be non-negative. So when to do it? See this stackoverflow answer ⬇️
I was glad to find a good conversation on this subject, as I hadn't really given it much thought before.
In summary, signed is a good general choice - even when you're dead sure all the numbers are positive - if you're going to do arithmetic on the variable (like…
Nullable types ❓
In Kotlin, the parent of all classes is the Any
class. It can’t hold nulls. To declare that a variable can be null, use ?
. For example, Any?
is an equivalent for Java Object
. And Object
shouldn’t be used in Kotlin.
Thanks to this, we can put a primitive type into an object of type Any
:
var a = 2
var b: Any = a // compiles
Wrappers vs primitive types 📦
You’ve noticed that primitives in Kotlin are capitalized. How to write wrappers for them? Simply write a ?
after the type:
val a: Int? = null // compiles
val b: Int = null // doesn't compile
Nevertheless, as the name suggests, you should use them only when you want to hold null.
You don’t need wrapper types as Kotlin internally converts the variable if needed.
Let’s clarify this with an example. To find out the type of a Java variable during runtime, we’ll use Kotlin’s .javaClass.simpleName
.
Let’s start with a simple int:
val someInt = 1
println(someInt.javaClass.simpleName) // prints int
Now, let’s try Kotlin’s nullable Int (don’t pay attention to these ?
in the 2nd line, it’s about Kotlin nullability — a topic for a separate article)
val someInteger: Int? = 1
println(someInteger?.javaClass?.simpleName) // prints Integer
Finally, let’s put a non-nullable Int in a collection. As we know, collections only accept boxed types i.e. instead of int, we’ll need to use Integer. But see what happens:
val someInt = 1
val list: MutableList<Int> = ArrayList(1)
list.add(someInt)
println(list[0].javaClass.simpleName) // prints Integer
println(someInt.javaClass.simpleName) // prints int
Mind you that the type of the object in the list is Integer but the type of the initial variable i.e. val someInt
is int. So JVM creates a new Integer and put’s it into the list, while the initial variable’s type remains primitive.
Unit and Nothing types
There are also Unit and Nothing types in Kotlin, but they mainly refer to functions, not variables. Therefore, they will be discussed later in the series.
How to translate Kotlin to Java and vice versa? 🔀
Sometimes Kotlin code can be tricky and vague. Luckily, we have a tool that adds some clarity to it. You can translate this code to Java and see what actually happens. And here is how to do it with IntelliJ Idea.
Open a Kotlin file and go to Tools → Kotlin → Show Kotlin Bytecode. This bytecode can already give you some info about what's happening under the hood. In the opened window there will be a "decompile" button that will translate the bytecode to Java.
But this code will not be the same as if you wrote it on Java because it's decompiled from the bytecode.
It's easier to translate from Java to Kotlin. Right-click on a Java file and click on "Convert Java file to Kotlin file". Or you can simply copy some Java code and paste it into a Kotlin file and the IDE will suggest converting it.
Visibility modifiers 👻
And finally the easiest part of the article — visibility modifiers.
- If a visibility modifier is not provided, the variable acquires the default visibility level, which is
public
. While in Java no-modifier means the variable is visible only within its own package. - Kotlin also has
internal
— the field is only visible inside files within the same module. There is nothing like that in Java. -
protected
Kotlin modifier is different from Java — it provides access to all the subclasses, but not to any other classes within the package. There were debates about it, but now we can only accept what we have. -
private
gives access only within the same class.
Bullet points 📌
- Kotlin has three ways to declare variables:
val
,var
, andconst val
.val
means the variable's value is fixed,var
means the variable's value can vary, andconst val
means the variable's value is constant, shared, and known at the compile time. - There are no primitives in Kotlin, but its
Int
,Long
,Donuble
, etc. are internally converted to primitives whenever possible. - By default, all objects in Kotlin can’t hold null. But if you want to, you can easily do this by writing a
?
at the end of its type. - The default visibility modifier in Kotlin is
public
. Kotlinsprotected
only gives access to the subclasses,internal
— inside files within the same module.
If you learned something new from this article, hit the like button and follow for more. Happy learning!