Java To Kotlin Part 3 — Variables And Syntactic Sugar
Part 2 demonstrated most of the different ways that classes and methods can be used in Kotlin. Part 3 will demonstrate most of the cool things that Kotlin can do with variables. This is where things start to get interesting and fun.
In Kotlin, member variables(class-level variables) are called “properties”, while local variables are called “locals”. As many parts of this blog post refer to things that can apply to both properties and locals, the word “variable” may be used as a substitute.
Visibility modifiers (public/private/default/internal)
Kotlin, like Java, has four visibility modifiers. There are the usual public
, protected
, and private
modifiers, and they work the in mostly the same way as Java:
public
objects are visible anywhere that accesses the class it’s declared in. Thepublic
is considered redundant as the default modifier for variables ispublic
.protected
objects are only visible to the class they’re declared in and any child classes.private
objects are only visible inside the class they’re declared in. The only difference
The fourth modifier is internal
. A object bearing this modifier is only visible to every class in the same module.
Constants
Constants in Kotlin work a bit differently to Java. For starters they’re accessible from anywhere in the package or module they’re declared in. This means it’s possible to create a file to contain every constant for the module. Should a less public constant be needed, one of the visibility modifiers would work. Remember: the protected
modifier will not work for constants in this context, as it’s outside of a class.
Getters and Setters
In Kotlin, all properties have invisible getters and setters. A property is only accessible through it’s getters and setters. The default getter and setters are transparent, so we just access the variable name instead. Manually adding getters and setters is not needed unless a variable needs to be modified before being set/get. Kotlin has a handy getter/setter combo for this:
In this case, department
can be null, but we don’t want to get or set it as null. Remember the part about Kotlin having built-in getters and setters? We don’t need to call getDepartment()
, as that method is completely transparent. Instead we just access the variable as per normal:
This would be a good time to show some cleaned-up decompiled bytecode for the above code:
All nicely wrapped up for use in Java.
If you’d like a custom getter and setter, the Kotlin standard recommends creating a dummy property with no backing field:
The decompiled bytecode for this would be:
The Elvis Operator
There is the following expression in GettersAndSetters
:
This can be refined by the Elvis operator (?:
):
This is a convenient shorthand expression that will set a nullable variable if it is not null, else set it to whichever value is on the other side of the elvis expression (or throw an exception, if that’s useful).
Not-Null Assertion
As demonstrated in parts 1 & 2, variables are made nullable using the ?
character. A null-check can be made to assign a nullable variable to a not-null variable. If the situation arises when a nullable variable must not be null, the !!
(non-null) operator can be appended to the variable when being used. This will throw an exception if the variable is null:
The non-null operator actually converts the nullable type to a non-null type. non-Null asserting properties and variables should be done as early as possible. This should result in possible errors being detected earlier in code execution.
Lateinit
When a non-null var
is declared, it must normally be assigned immediately. The lateinit
modifier allows a var
to be declared empty and assigned later:
A value must be set to alateinit var
, or an UninitializedPropertyAccessException
will be thrown when it’s accessed:
String Interpolation
String interpolation is one of my favourite Kotlin features. It allows the addition of variables into a String without resorting to concatenation:
On the surface it looks simple. The decompiled bytecode code simply used concatenation:
Methods calls can also be used surrounded by ${}
:
The above will be compiled into simple concatenation, so don’t be concerned about this being expensive at execution time.
String interpolation also works with expressions:
It’s not just limited to arithmetic:
Interpolation can also be nested. This can be abused to create some pretty absurd and crazy logic that is guaranteed to attract the unbridled wrath of your coworkers:
JoinToString
joinToString
is a handy method that outputs the contents of a collection to a String
. The prefix, suffix, and separator can be defined. lastly, the maximum number of elements to add to the String
can be specified:
String Equality
Kotlin has a much more mature outlook on String equality than Java. The .equals()
method is no longer needed. That’s right. Strings can be checked for equality in the same way as anything else:
Smart Casting
I saved the best for last. Kotlin has an amazing smart casting system. It remembers what a variable has been cast to. This allows for some cleaner code than continually casting a variable:
This is the end of Part 3. Compared to Parts 1 and 2, Part 3 included some more juicy stuff to sink your teeth into. Part four should be even better.
Examples for Part 3 can be found here.
Part 4 of the series can be found here.
Originally published at www.k0ma.co.za on November 4, 2018.