DEV Community

Cover image for Kotlin Decoded | Part 2  - all about variables in Kotlin + visibility modifiers and data types
Daniel Rendox
Daniel Rendox

Posted on • Originally published at Medium

Kotlin Decoded | Part 2  - all about variables in Kotlin + visibility modifiers and data types

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? 🔀

 4. Visibility modifiers 👻

 5. Bullet points 📌

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;
Enter fullscreen mode Exit fullscreen mode

Kotlin:

var a = 1
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

Kotlin:

val number: Int
number = 0
Enter fullscreen mode Exit fullscreen mode

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";
Enter fullscreen mode Exit fullscreen mode

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";
    }
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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, and const val. val means the variable's value is fixed, var means the variable's value can vary, and const 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. Kotlins protected 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!

Other articles from this series

Top comments (0)