Kotlin

Kotlin: Top two null-safety tricks

  • The elvis operator (?:) allows you to assign a "default" value if the variable to the left of the elvis operator is null

  • The notation someVariable?.let{ } allows you to take an action (which is defined within "let") only if someVariable is non-null

fun main() {
    // the elvis operator
    val test = null    
    val test2 = test ?: "it was null"  
    println(test2)
    
    // taking action only if variable is non-null
    // using ?.let
    val isNull = null
    isNull?.let{
        println("Inside let with null - will not be printed")
    }
    
    val isNotNull = 1
    isNotNull?.let{
        println("Inside let with non-null value of '$it' - will be printed")
    }
    
}

Output:

it was null
Inside let with non-null value of '1' - will be printed

Kotlin
0
Create Kotlin Singletons using delegated properties

A typical java-like singleton would look like this in Kotlin:

class Singleton private constructor() {

     private object SingletonHolder {
            val INSTANCE = Singleton()
     }

    companion object {
            val instance : Singleton by lazy {
                        SingletonHolder.INSTANCE
            }
    }

}

The above code:

  • marks the constructor as private so you cannot create a new "Singleton" instance directly
  • contains a private object which can access the private constructor and so holds an instance of Singleton()
  • contains a companion object to return the instance

The important note here is the "by lazy" delegate property. by lazy is thread safe and hence avoids the double check code we normally use in Java to create a singleton. In addition, the companion object is itself a singleton, so we can shorten the above to:

class Singleton private constructor() {

    companion object {
            val instance : Singleton by lazy {
                        Singleton()
            }
    }

}

We simply got rid of the private SingletonHolder object, Furthermore, Kotlin shorthands all this to a single line:

object Singleton

Kotlin
0
Creating singletons without locking

Typically Java singletons are created using double-checked locking (i.e. check if the singleton instance is null, only if it is, go into synchronized code, check if null again and create instance). However, a more elegant way of doing this is to use static code blocks, which are also thread safe. For example:

public class ourSingleton{

    public static ourSingleton INSTANCE;
    private static String demo;

    private ourSingleton(){

        demo = "ourSingleton"; // an example of initializing a variable
        this.INSTANCE = this;
        System.out.println("init done");

    }

    static { // static code block
        new ourSingleton();
    }

    public void printDemo(){
        System.out.println(this); // show that same instance of class is used
        System.out.println(demo); // get access to the initialized variable
    }

}

// [...]

// note that now ourSingleton.INSTANCE can't be null due to the static code block, eliminating
// the need for the typical double-check locking
ourSingleton demo1 = ourSingleton.INSTANCE; 
ourSingleton demo2 = ourSingleton.INSTANCE;

demo1.printDemo();
demo2.printDemo();

/*
outputs:
"
init done               <---- init only called once
ourSingleton@5594a1b5   <---- same output for both instances of singleton
ourSingleton
ourSingleton@5594a1b5
ourSingleton
 "
 */

In kotlin this is even easier by using an object:

object ourSingleton{
    init{
        println("init done");
   }
}

Java_and_Spring
Kotlin
0
Sealed Classes

Sealed classes essentially act as enums but at a class level. This allows you to check if a class is of a certain type and call a method or variable depending on that type. Sealed classes allow you to use the when keyword to achieve this:

sealed class Demo
/*
note that the variable names in the constructors of the below data classes are different
so we cannot simply call "demo1.myNumber3" or "demo3.myNumber1". 
The variable depends on which type of data class is used 
(hence necessitating the use of the "when" expression below)

also note that both extend the sealed class "Demo"
*/
data class Demo1(val myNumber1: Int) : Demo()
data class Demo3(val myNumber3: Int) : Demo() 

fun demoTest(demo: Demo){
    when(demo){
        is Demo1 -> println(demo.myNumber1)
        is Demo3 -> println(demo.myNumber3)
    }
    	
}

fun main() {
    val sampleDemo = Demo1(123)
    demoTest(sampleDemo)
}

// results in : 123

It's a bit similar to replace the use of virtual method invocation in java ( see: #73 )

Kotlin
0
Single Expression Functions

Kotlin's single expression function syntax allows you to write clearer code. For example, instead of:

fun demo(i: Int) : Int {
   return i * i
}

we can type:

fun demo(i: Int) = i * i  // note the use of the = sign and lack of "return" keyword

Single expression functions form the backbone of using async since the async builder is defined on coroutineScope so to use it we can use a single expression function:

suspend fun parallelExampleSum(): Int = coroutineScope {
     val first = async { someFunction() }
     val second = async { someFunction() }
     first.await() + second.await() // implicit return
}

println("Result is ${parallelExampleSum()}")

Kotlin
0
Kotlin @autowired variables

When using kotlin with Spring, remember that variables injected using @Autowired need to use the lateinit keyword, since autowired injects the variable instance after initialization:

public class Demo {

    @autowired
    lateinit var someVar : someType

}

Kotlin
0
Static fields in Kotlin

Static fields are defined inside a companion object at the beginning of a class:

 companion object {
   [...]
}

Kotlin
0
Reflection in Kotlin

xyz123.javaClass.declaredMethods xyz123.javaClass.declaredFields

  • declaredMethods
  • declaredFields

Kotlin
0
Kotlin Maps and Function Types

If you come from a JavaScript background, this syntax is probably familiar to you:

const demoObject ={
   1: 100,
   2: 'yolo',
   3: (x) => x*x
}
console.log( demoObject[3](2) ) // outputs: 4

The above example highlights JS's capability of storing any value type in an object. In the above demoObject we store an Integer, String, and a function.

Kotlin has this same functionality. However, unlike JS, Kotlin is a typed language. For the more straightforward types like Integer and String, Kotlin can infer the types automatically. However it needs a helping hand to determine what "type" a function is. The above example in Kotlin would be:

val demoObject = MutableMap<Int, Any> = mutableMapOf(
   1 to 100,
   2 to 'yolo',
   3 to fun(x: Int):Int { return x*x }
)

println( (demoObject[3] as (Int)->Int)(2) )  //Outputs 4

In the last line above, note the use of the function type (Int) -> Int. Breaking down the line:

  • demoObject[3] will return a function, however Kotlin sees it as type "any" and cannot infer that it is a function
  • demoObject[3] as (Int)->Int casts the "Any" type to a function type, with the correct parameter and return type
  • (demoObject[3] as (Int)->Int)(2) wraps the function in brackets and passes a parameter of '2'

Kotlin playground example

Kotlin
0
SAM conversions

In java, many libraries (such as the Android SDK), use interfaces which define a Single Abstract Method (a.k.a SAM), for example, in the below interface named Adder, we have a single method called add:

interface Adder {
    Integer add(int a, int b);
}

In java, we'd implement it like so:

public class myAdder implements Adder {
        public Integer add(int a, int b){
            return a+b;
        }        
}

However in Kotlin, the SAM conversion feature allows us to more do the above more concisely by passing in a lambda whenever an interface has just one method, like so:

val myAdder = Adder{ a,b -> a+b }
//or more concretely...
val runnable = Runnable { println("This runs in a runnable") }

However... SAM conversions can only be used with JAVA interfaces, not kotlin interfaces

Kotlin
0
Lazy loading variables

Achieved easily in kotlin:

val z: String by lazy {"Hello"}

Kotlin
0