Hi everyone again, welcome to article number on 2 of the Kotlin Playground Series. There wasn’t that much code in the previous article but if you read it, you probably saw some new syntax that you’re not familiar with if coming from Java.
In this and following article I’ll cover some of Kotlin base syntax as I believe it’s important before we jump into other examples. But enough talk and let’s look at some Kotlin code.
There are some differences in declaring classes in comparison with Java. Let’s look at some examples in the code below. An important aspect in Kotlin is that you can declare multiple classes without any relation in the same file. Probably not what you want to do but nice for this example.
Kotlin classes are declared using the keyword class
and consist of the class name, the header and the body surround by curly braces. But there a lot of optional things when declaring Kotlin classes.
class ClassWithEmptyBody
class ClassWithBody(val name: String) {
val nameLength = name.length
}
If your class has a body you need to wrap it in curly braces but if there’s no class body you can actually omit it.
class ClassWithoutConstructorKeyword (val name: String) {
val nameLength = name.length
}
class ClassWithConstructorKeyword constructor (val name: String) {
val nameLength = name.length
}
class ClassWithAccessModifier public constructor (val name: String) {
val nameLength = name.length
}
class ClassWithInitialization public constructor (val name: String) {
val nameLength : Int
init {
nameLength = name.length
}
}
class ClassWithMultipleConstructors (val name: String) {
val nameLength = name.length
constructor(name: String, age: Int) : this(name) {
val yearOfBirth = LocalDateTime.now().year - age
}
}
The constructor
keyword is also optional if your class header doesn’t need any access modifiers or annotations.
As in Java, a class can have multiple constructors, but in Kotlin apart from properties declaration, we can’t have any code in the main constructor. All initialisation code needs to be inside an init
method.
val ClassWithEmptyBody = ClassWithEmptyBody()
val ClassWithBody = ClassWithBody("a name")
To instantiate classes we just assign the Class calling it as if it was a normal function as there’s no new
keyword in Kotlin.
open class ParentClass (someNumber: Int)
class ChildClass (someNumber: Int) : ParentClass(someNumber)
interface InterfaceExample {
fun test()
}
class InterfaceImplementation : InterfaceExample {
override fun test() {
//Some implementation
}
}
And to end the classes section, we can see that in Kotlin there’s no extends
or implements
keywords. To extend or implement another class we can just use :
and that’s it. Easy right?
Moving on to functions, as with constructors if you want them public, no need to use the access modifier. While in Java the default access modifier is limited, in Kotlin is public so no need to have it everywhere.
fun aFunction(x: Int, y: Int): Int {
return x + y
}
fun aFunctionWithExplicitReturnType(x: Int, y: Int): Unit {
println("sum of $x and $y is ${x + y}")
}
fun aFunctionWithoutReduntant(x: Int, y: Int) {
println("sum of $x and $y is ${x + y}")
}
fun aFunctionAsExpression(x: Int, y: Int) = x + y
As you can see, the return type of a function in Kotlin is in the end rather than the beginning like in Java. The same is also true for the params, with the return type being preceded by the param name and a colon.
Functions that don’t return anything (Void functions in Java) have return type Unit
in Kotlin. And because in Kotlin we don’t have to explicitly write obvious things this is also optional and you can omit it if your function doesn’t have a return value.
Another very cool feature regarding Kotlin functions is that they can be declared as expressions. If your function has a return type you can literally use as in the last example above and drop the function body. While this is super cool, it can be a bit dangerous as people can go wild with this, so please use it with care.
In Kotlin we can use either the keyword var
or val
to define variables. The difference between both is that var
is used to define mutable variables, while val
is used to define read-only or immutable variables depending on the train you join, but we’ll get to that after. First, let’s see some examples:
val immediateAssignment: Int = 1
val inferredTypeInt = 2
val deferredAssignment: Int
deferredAssignment = 3
var mutableInferredTypeString = "some string"
mutableInferredTypeString += "some concat"
Looking at the second variable above, it’s initialised with a default value, so Kotlin automatically infers its type as Int
. This is another cool feature from Kotlin called Inferred type. So if the type is inferred automatically that means type declaration it’s not explicitly necessary, which in Kotlin means we can drop it. This works with custom objects as well.
Going back to val
variables and the fact that they’re read-only or immutable there is some discussion around this. If we’re talking about regular variables we can definitely say that they’re immutable but it’s a different story when talking about class properties. Let’s see the example below:
class MutableValExample(val yearOfBirth: Int) {
val age: Int
get() = LocalDateTime.now().year - yearOfBirth
}
In the context of class properties, val
only means that a property won’t have a setter method which means that the property would be immutable. But as we can see above, we can have a custom getter method that returns a different value each time someone accesses the property. So, while the property is immutable we’re actually getting a different value every time the date.
This is why some people call val
variables read-only rather than immutable. The important is to be aware of this use case, so maybe a good tip is to try not to use val
properties with custom getters as it can get confusing.
And if you’re ever confused about var
and val
and which one is which, Kaushik Gopal gave a nice tip in episode 85 of Fragment Podcast where they have a casual Kotlin discussion with Dan Kim (I actually recommend this episode, it’s quite nice):
Think of
var
as ‘variable’, so by definition something that can change, andval
as ‘value’, so something that has a value and doesn’t necessarily change.
Probably one of the biggest arguments people use to make the switch from Java to Kotlin is the fact that Kotlin is a null-safe language. But what does this mean? Let’s check those 3 seagulls on the left of the image and find out what new operators are those.
Null reference was considered by its own inventor, Tony Hoare, the billion dollar mistake and the truth is, as Java developers we spend way too much time dealing Null Pointer Exceptions (NPE) right?
Well, Kotlin was designed in a way that NPE should not happen unless one of these things happen:
Some java code causing it\
Explicitly calling
throw NullPointerException()
\Using the
!!
operator\
But let’s look at the Kotlin syntax around null -safety and how it works. Before going into the operators in the image, let’s see what the ?
operator on its own is about.
fun NonNullString() {
var nonNullString: String = "some string"
nonNullString = null // compilation error
}
fun NullString() {
var nullString: String? = "some string"
nullString = null // nothing wrong
}
Looking at the example above, first, we have an example of a regular String variable in Kotlin, which by default is not nullable. If we try to assign null
to it, we get a compilation error.
But if we look at the second example there’s no compilation error, what’s the difference? By appending our variable type with ?
like we see above with var nullString :String?
we declare our variable nullable and we can assign null
to it without any compilation errors.
Cool right? This means we have full control of the nullability of our variables and we have to explicitly declare them nullable if we want them to accept null
values.
Now let’s look at the operators in the feature image, starting with the ?.
operator. This is called the Safe call operator
and by the name, or if you’re familiar with C#, for example, you can guess what it does. Let’s see an example:
var nullString: String? = "some string"
var length :Int
var lengthOrNull :Int?
nullString.length // compilation error
length = nullString?.length //compilation error
lengthOrNull = nullString?.length //nothing wrong
Ok, so we have our nullString
nullable variable from before and some operations on it. A couple with compilation errors and the last one without, let’s check them in more detail.
Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String?
The first assignment will give us this compilation error. Why? Well, the reason is obvious, if the variable is null the call would result in an NPE at runtime. But because Kotlin is null safe we get the error at compilation time. Nice, right?
Type mismatch: inferred type is Int? but Int was expected
In the second assignment we’re using the ?.
operator to read the length of the string so what’s the problem? The safe call operator will return the length of the string if this is not null or null otherwise. And because length
is of the type Int
(not nullable), we cannot assign this expression to it.
The way to go in this case is to use the last example and assign nullString?.length
to lengthOrNull
that is of type Int?
therefore nullable.
Moving on to ?:
or Elvis Operator
as it’s called. This is a simple operator that basically returns the expression to its left if its not null, or the one to the right if the left one is null. Let’s see an example:
var nullString: String? = "some string"
var length :Int
nullString.length // compilation error
length = nullString?.length ?: -1
As with the previous example, with the first assignment, we will get the same compilation error. But in the second assignment, because we’re using the ?:
operator to return length as -1 in the case nullString is effectively null
we can now assign length
to an Int
(non-nullable) variable.
One more to go. The !!
operator, or the FORBIDDEN ONE. There’s a reason why is the last one of the 3 seagulls. There’s only a reason to use this, and it’s if you like NPEs, which I hope you don’t. No developer does right? RIGHT?
val length = someString!!.length
This operator is called Not-null assertion
and basically tells the compiler that you’re 100% sure that the expression you’re using in it will never be null. Did I mention the billion dollar mistake before? I know I did but it’s very relevant to mention it again here. And please go up again and see the list of the only 3 things that can cause NPE in Kotlin, our friend !!
is right there.
Please don’t use this operator unless you really have to, which is never hopefully. If you’re using Android Studio converter to convert Java to Kotlin you’ll see loads of these but don’t assume they’re good. That’s because it’s converting Java code that is not null-safe and I would actually use it as a good excuse to look at your code and take advantage of Kotlin null-safe features to refactor it.
Ok and now finally to explain why the poor seagull on the right is feeling excluded next to those operators we just saw in the previous section about Nullability.
Well, that’s because we don’t actually need the semi-colon all over the place like we do in Java (you probably noticed it already). Kotlin provides semi-colon inference, so statements, declarations etc, are separated by the pseudo-token SEMI and in most cases, there’s no need for semi-colons in Kotlin code.
This is one of the biggest differences between Java and Kotlin syntax, but there are a couple of exceptions:
enum class SemiColonNotRequired {
WITH,
WITHOUT
}
enum class SemiColonRequired {
WITH,
WITHOUT;
fun isRequired(): Boolean = this == WITH
}
If you have an enum that also contains a property or a function you explicitly need to use a semi-colon to separate the enum constant list from the property or function definition.
If we try to remove the semi-colon from the second example we get a compilation error straight away telling us we need to use a semi-colon to close the enum constants entry.
The only other situation where you need to use a semi-colon is if you want to have 2 statements on the same line like in the example below:
var list = 1..10
list.forEach { val result = it * 2; println("$it times 2 is $result")}
If we try and replace that semi-colon with just a comma, we also get a compilation error telling us we need to use a semi-colon to separate expressions on the same line:
And that’s all for today, hopefully, you are now more comfortable with some of the basic Kotlin syntax. If you enjoyed the article don’t forget to give some 👏 and please share your ideas and comments. As usual, you can find the code used for this article in the Series Github project under the syntax
package. See you in number 3 for more Kotlin syntax examples.
Android and Kotlin — basic Hello World ⇦ PREVIOUS
NEXT ⇨ Kotlin Syntax Part II — when did this switch happen?