Kotlin Reference Guide

By pjain      Published Dec. 15, 2019, 6:24 p.m. in blog Programming   

kT Types Ref

Vars

val x = 0; var mut = 1
x += 1   // <-- compiler complains
mut += 1  // no problem
  • val - read only, var mutable - type can be inferred val a: Int = 1 // immediate assignment val b = 2 // Int type is inferred val c: Int // Type required when no initializer is provided c = 3 // deferred assignment

    var x = 5 // Int type is inferred x += 1

  • Scope - outer seen into function var x = 0 fun incrementX() { x += 1 }

  • string templates and expressions var a = 1 val s1 = "a is $a" // simple name in template: a = 2 // arbitrary expression in template: val s2 = "${s1.replace("is", "was")}, but now is $a"

Number Types

Long    64
Int     32
Short   16
Byte     8
Double  64
Float   32
  • No explicit widening - must convert explicitly val longval = intval.toLong() val double = floatval.toDouble() toByte(), toShort(), toInt(), toLong(), toFloat(), toDouble(), toChar().

NAMED not Ops, Bitwise, Rotates, Boolean operates std && ||

  • Not builtins but functions invoked like ops for arith, shifts are important at lower level and high perf Here is the complete list of bitwise operations (available for Int and Long only):

    shl(bits) – signed shift left (Java's <<) shr(bits) – signed shift right (Java's >>) ushr(bits) – unsigned shift right (Java's >>>) and(bits) – bitwise and or(bits) – bitwise or xor(bits) – bitwise xor inv() – bitwise inversion

    val leftShift = 1 shl 2 val rightShift = 1 shr 2 val unsignedRightShift = 1 ushr 2

    val and = 1 and 0x00001111 val or = 1 or 0x00001111 val xor = 1 xor 0x00001111 val inv = 1.inv() # unary so invoked by number.fn()

  • Booleans are standard && || ops Booleans are rather standard, and support the usual negation, conjunction, and disjunction operations. Conjunction and disjunction are lazily evaluated, so if the left-hand side satisfies the clause, then the right-hand side will not be evaluated:

    val x = 1 
    val y = 2 
    val z = 2
    
    val isTrue = x &lt; y &amp;&amp; x &lt; z 
    val alsoTrue = x == y || y == z
    

String, Char Types, String Templates

  • Char c Literals in single quotes '0' '9'

    • escape chars \n \r
    • unicode '\u1234'
  • Strings - immutable

  • Multiline strings """ create multiline string - no escaping needed"""

  • comments are the same // and / / block comments in Kotlin can be nested.

  • String Templates - allow embedding vals inside another string including kt expressions val name = "Sam" val str = "hello $name, lenght=${name.length} characters"

Strict type checks/casts

  • Kotlin does not autoatically do conversions where there is no loss of precision like Java long<-int You HAVE to do it explicitly val a: Int = 1000; val b: Long = a.toLong() // not b = a <--- Java it is ok!

  • for these Kotlin has lots of conversion functions toByte() toChar() toDouble() toFloat() toInt() toLong() toShort()

  • This is a performance boosting, as it allows Kotlin to use more primitive types than boxing ..

Variables & Null handling

  • immutables - READ-ONLY ~FINAL - type is inferred from assignment val x: Int // final int x; val y = 1 // final int y = 1;

    Complex val .. can have their members changed, but the outer itself cannot be changed ..

  • variables - type is inferred from assignment var w: Int var z = 2 //? int is default or unassigned yet? w = 3 // it is variable

  • Declaring nulls val name: String? = null // final String name = null; var lastName: String? lastName = null

    var firstName: String firstName = null // Compilation error!!

Nulls - more robust code checked @ compile

  • Variables cannot be simply assigned to null - must be declared with ? But in using .. within a scope it MUST be tested for null or compiler will give an error

  • A reference must be explicitly marked as nullable when null value is possible. // can return int or null - serves as spec for invalid str to int fun parseInt(str: String): Int? { // ... } fun printProduct(arg1: String, arg2: String) { val x = parseInt(arg1) val y = parseInt(arg2) // ALLOWS COMPILE CHECKS eg Using x * y yields error because they may hold nulls. if (x != null && y != null) { // Testing for null allows proceeding .. x and y are cast to non-nullable after null check println(x * y) } else { println("either '$arg1' or '$arg2' is not a number") }
    }

  • Example - adding conditional check allows The one line if allows checking before accessing the possibly null value! but a shortcut for testing null is using the ?. operatior - variable?. to only proceed if not null!

    var currentTime: java.util.Date? = java.util.Date() // var seconds = if (currentTime != null) currentTime.getTime() else 0 var seconds = currentTime?.getTime() println(seconds)

  • ?. operator can be chained - at each point it can simply return null or if not proceed! member1?.member2()?.member3()

  • ?: Elvis operator - ternary operator to test null in else condition var currentTime: java.util.Date? = null println( currentTime?.getTime() ?: -1 ) // returns -1 as currentTIme is null ..

  • !! operator - null pointer exception - bypass the null check and throw null pointer exception The null check safety IS still done - only throws exception instead of compile time ...

    fun test() { var currentTime: java.util.Date? = null println("Next line compiles, but throws exception when running") var seconds = currentTime!!.getTime() println(seconds) } test()

Nulls & Optionals Usage

  • Basically replaces null checks everywhere with strategic use of ? or !!

  • Swift and Scala have optionals, in ObjC Sending messages to nil does not throw exceptions.

  • Optionality at point of declare and usage var notNullArtist: Artist = null //This won´t compile. Artist can´t be null var artist: Artist? = null //Artist can be null artist.print() // Won´t compile, artist could be null and we need to deal with that artist?.print() // Will print only if artist != null

  • Smart cast. We don´t need to use safe call operator if we previously checked nullity if (artist != null) { artist.print() }

  • Only use it when we are sure it´s not null. Will throw an exception otherwise. artist!!.print()

    // Use Elvis operator to give an alternative in case the object is null val name = artist?.name ?: "empty"

  • Mapping java, kotlin types For efficiency a lot of kotlin types are .. primitive java types - but they don't allow null However nullable types map only to Java boxed types descending from Object Only variables of a type that have a question mark after their name are allowed to be a null reference. Variables of types that have no question mark are never allowed to be null.

    kType JVM type Byte kotlin.Byte Primitive byte Byte? kotlin.Byte? java.lang.Byte Any kotlin.Any java.lang.Object String kotlin.String java.lang.String

  • PERFORMANCE - This is fully handled under the hood by the compiler and this improves performance a lot, as Kotlin does not have to autobox primitive values all the time.

Data Structures, Collections, Control Flow

rOS Kotlin DS, Collections, Algos

Kotlin/kotlinx.collections.immutable: Immutable collection prototypes for Kotlin Kotlin/kotlinx.cli: Pure Kotlin implementation of a generic CLI parser. https://github.com/Kotlin/kotlinx.support DOM in HTML5

SRC:https://kotlinlang.org/docs/reference/collections.html

Mutable vs Immutable Collections

  • Like Scala and Clojure and other functional, Kotlin provides immutable and mutable implementations of collection classes Google Guava also makes this distinction to squeeze out more performance.

    JavaImmutable kImmutable JavaMutable kMutable
    List listOf MutableList mutableListOf() Set setOf MutableSet mutableSetOf() Map mapOf MutableMap mutableMapOf

  • There is no kotlin primitive array type - all provide iterator, size, get/set, bracket accessors

List: A generic ordered collection of elements. Methods in this interface support only read-only access to the list; read/write access is supported through the MutableList interface.

MutableList: A generic ordered collection of elements that supports adding and removing elements.

You can modify a MutableList: change, remove, add... its elements. In a List you can only read them

listOf arrayOf

val numbers = listOf(1, 2, 3) #J8 List nos = Arrays.asList(1,2,3); #J9 final List numbers = List.of(1, 2, 3);

var array = arrayOf(1,2,3,4,5)  --&gt; class kotlin.Array
val names2 = arrayOf("Joe","Ben","Thomas")
println(array[0]) // Outputs 1  
for (name in names2)
    println(name)

var list = listOf(1,2,3,4,5)    --&gt; class java.util.Arrays$ArrayList
val names1 = listOf("Joe","Ben","Thomas")
println(list[0]) // Outputs 1
for (name in names1)
    println(name)



class Array&lt;T&gt; private constructor() {
    val size: Int
    operator fun get(index: Int): T
    operator fun set(index: Int, value: T): Unit
    operator fun iterator(): Iterator&lt;T&gt;
}
  • create array - ArrayList? val array = arrayOf(1, 2, 3) # inferred as Array or intArrayOf(1,2,3) val rg = IntArrayOf(1,2,3) val rgZeros = IntArray(3) val numFromOne = Intrray(3) {it + 1} so 1,2,3 val perfectSquares = Array(10, { k -> k * k }) # from initial size, generator

PERFORMANCE boxing

  • Both listOf, arrayOf are available but performance differs as array is primitive Array?

    val boxedInts = arrayOfNulls(3) //J new Integer[3]

  • notes: To avoid boxing types that will ultimately be represented as primitives in the JVM, Kotlin provides alternative array classes that are specialized for each of the primitive types. This allows performance-critical code to use arrays as efficiently as they would do in plain Java. The provided classes are ByteArray, CharArray, ShortArray, IntArray, LongArray, BooleanArray, FloatArray, and DoubleArray.

ranges

map

val map = mapOf(1 to "One", 2 to "Two", 3 to "Three") # J8 final Mapmap=new HashMap();map.put(1,"One");map.put(2,"Two");.. # J9 final Map map = Map.of(1, "One", 2, "Two", 3, "Three");

k Collections Can be nullable

val strs : Array&lt;String?&gt; = 
val null3strs = arrayOfNulls&lt;String&gt;(3)
Array&lt;Int&gt;(size) doesn't compile. That's because you can't create a non-nullable array without providing the elements.

val element1 = array[0]
val element2 = array[1] 
array[2] = 5

List of primitives, for, if

  • if, for, while etc similar to java .. idiomatic ..

    // if as an expression fun maxOf(a: Int, b: Int) = if (a > b) a else b

While, For in vs :, range ..

val items = listOf("apple", "banana", "kiwi")
for (item in items) { // regular for in 
    println(item)
}
for (index in items.indices) { // nav in index
    println("item at $index is ${items[index]}")
}
  • WHILE - var index = 0 while (index < items.size) { println("item at $index is ${items[index]}") index++ }

    for (i in 1..10) { } for (i in 1..10 step 2) {} for (item in collection) {} //J for(String i : collection) {} for ((index, item) in collection.withIndex()) {} for ((key, value) in map) {} //J for (Map.Entry entry: map.entrySet()){}

switch, apply, with

  • Apply

  • With apply-vs-with

  • With == switch val x = // value val xResult = when (x) { 0, 11 -> "0 or 11" in 1..10 -> "from 1 to 10" !in 12..14 -> "not from 12 to 14" else -> if (isOdd(x)) { "is odd" } else { "otherwise" } }

    val y = // value val yResult = when { isNegative(y) -> "is Negative" isZero(y) -> "is Zero" isOdd(y) -> "is odd" else -> "otherwise" }

Functiona

  • A generic function defined using fun keyword fun method(param: String, length: Int = 2) : Int { }

  • parameters can have defaults

functions in Kotlin 101

fun fnname(arg1:Int, b:String) : Int {
    return arg1;
}
  • one liner functions body defined with = fun fnname(a:Int,b:Int) = a+b // return type is inferred

  • Unit is comparable to Java's void with the difference that a Unit return value can be evaluated and put in a variable: fun printabsum(a:Int,b:Int) : Unit { // :Unit - no return - can be omitted! println("Sum of a,b is $(a+b)") }

Destructuring

destructuring

Lambdas in core Kotlin

Anonymous (lamdbas) simpler, builtin

view.setOnClickListener { toast("Hello world!") }
  • Lambdas # comparator function max(heroes, { a, b -> a.strength < b.strength })

Lambdas or anonymous functions in Android

One of the most important feature in Kotlin, it’s that you can pass anonymous function (lambdas) as a parameter of a function. Normally you just use the brackets because you need to define the parameters to the left of the arrow and the actually implementation code on the right. But if the parameters are not used then Kotlin allows you to omit them:

Ex1. Interface to Lambda shorthand ..

public interface OnClickListener{
  void onClick(View v);
}
// Java equivalent
button.setOnClickListener(new OnClickListener(){
  @Override public void onClick(View v){
    doSomething();
  }
});
//k Lambda - literal translation 5 .. 5 lines - not much syntactic reduction 
button.setOnClickListener(object : OnClickListener{
  override fun onClick(view: View){
    doSomething()
  }
})
    //k lets you substitute a function that receives an interface with a lambda from View parm -&gt; Unit return
fun setOnClickListener(listener: (View) -&gt; Unit)
button.setOnClickListener({ view -&gt; doSomething() }) //maps parm view to interface View parm, and no return so body

    // you can omit parms if NOT used .. 
button.setOnClickListener({ doSomething() })
    // AND if the function is the LAST parameter you can remove parens as default
button.setOnClickListener{ doSomething() }

Ex2. with .. it

Higher-Order Functions - resource wrappers, map

A higher-order function is a function that takes functions as parameters, or returns a function. A good example of such a function is lock() that takes a lock object and a function, acquires the lock, runs the function and releases the lock //Declare lock as higher order function given a function parm named body which returns T fun lock(lock: Lock, body: () -> T): T { lock.lock() try { return body() } finally { lock.unlock() } } //Sample usage using regular function fun toBeSynchronized() = sharedResource.operation() val result = lock(lock, ::toBeSynchronized) // <-- package::method //Sample usage using inline lanbda val result = lock(lock, { sharedResource.operation() })

  • Map is a higher order fucntion - note declared as extending List so this refers to list! val doubled = ints.map { value -> value * 2 } //ints is some listOf( ints ) // DECL - ?is it in default kotlin lib? fun List.map(transform: (T) -> R): List { val result = arrayListOf() for (item in this) result.add(transform(item)) return result }

k FN Prog

KotlinConf 2017 - Kotlin for the Pragmatic Functionalist by Paco Estévez García - YouTube

Indepth functionl programming

Refactoring to Functional– Reducing and Flattening Lists – Hadi Hariri All in the name of Pragmatism – Hadi Hariri On Functional Programming and Scary Terminology – Hadi Hariri

Indepth nullables

https://kotlinlang.org/docs/reference/null-safety.html

rOS Serialization, Messaging, Rvw

https://github.com/Kotlin/kotlinx.serialization

OOP, Classes, Meta

Packages and Imports

  • Packages allow us to split code into namespaces. Any file may begin with a package declaration: Inside a package, all classes and functions can be used without fully qualified name - FQN:

    package com.packt.myproject

    class Foo #FQN: com.packt.myproject.Foo

    fun bar(): String = "bar" #FQN: com.packt.myproject.bar

  • Imports - to use OUTSIDE a package without FQN .. use an import

    import com.gomobilefirst.coreutils.* # example with Wildcard imports => use w/o prefix import com.packt.otherproject.Foo as Foo2 # renaming import reference

Classes 101

  • No new needed to create a new - just use class name
  • default Constructor need not be declared .. just use function syntax

    class A (i: Int) { .. } val a = A(25)

  • final is default, open to allow modification class User {} # public final class User {} open class User {} # public class User {}

  • Pojos and constructor are easy, allow defaults args # creates field of type and get = .field , set by assign .field = class User(val name: String,val lnm:String="")

    public class User { //J private final String nm; private final String lnm; public User(String nm){this.nm=nm;this.lnm=""; } public User(String nm,String lnm){this.nm=nm;this.lnm=lnm;}; public String getName()...} }

  • Create instance - No new val file = File("file.txt") # final File file = new File("file.txt");

Constructors

The primary constructor becomes a part of the class header. It follows after the name of the class. This removes the boilerplate code of writing separate constructor to just copy the passed parameters into the member variables. Also eliminates need for setters/getters

open public class Book (var ISBN: String, var price: Float, var quantity: Int,
                   var title: String , var description: String){
    open fun getShippingPrice():Float {
        return price;
    }
}
val book1 = Book("123456", 43.0f, 4, "Kotlin for you", "Book on Kotlin")

OOP, Inheritance

  • Kotlin classes cannot be extended unless they are defined as open.

  • Super/copying constructor args all autommatic.. You can override fun in base class .. without super

    class HardCoverBook(ISBN: String, price: Float, quantity: Int, title: String , description: String) : Book(ISBN, price, quantity, title, description) {

    override fun getShippingPrice():Float {
        return price + 3.0f;
    }
    

    }

data class = POJO

data class Artist(var id: Long, var name: String, var url: String, var mbid: String)
  • Schema-ish - give default constructor data class Book2(var ISBN: String, var price: Float, var quantity: Int, var title: String , var description: String)

When we define a data class it also adds the methods ‘equals’ , ‘hashCode’ , ‘toString’ . This should be a preferred way to define a POJO in Kotlin.

  • property list with defaults
    public class Book { public var ISBN: String = "" public var price: Float = 0.toFloat() public var quantity: Int = 0 public var title: String = "" public var description: String = "" }

  • like ObjC @property keyword auto-generates setters/getters.

Properties

  • These can be declared read-only or mutable, and have custom accessors.

    val isSuperHuman: Boolean get() = this.strength > 15

Static

https://stackoverflow.com/questions/40352684/what-is-the-equivalent-of-java-static-methods-in-kotlin?rq=1

Extension functions for existing classes

  • Like Objective-C categories.

We can add new functions to any class - reducing boilerplate and more readable substitute to the typical utility classes we all have in our projects.

# add toast() with defaults to exiting Fragment class, or Activity, etc.. 
fun Fragment.toast(message: CharSequence, duration: Int = Toast.LENGTH_SHORT) {
    Toast.makeText(getActivity(), message, duration).show()
}
# Simplifying usage ..
fragment.toast("Hello world!")

K BPR, Pitfalls, Tricks, Conversion Perf, AR

SRC: https://m.signalvnoise.com/some-of-my-favorite-kotlin-features-that-we-use-a-lot-in-basecamp-5ac9d6cea95

Kotlin idiomatic Syntax

  • Replacing simple if/else if/else blocks with when when { firstName == "Dan" -> person.team = programmers lastName == "Dihiansan" -> person.team = designers else -> person.team = others }

  • Replace switch - when with a single variable (if x==var1 ) when (firstName) { "Dan", "Jay" -> person.team = programmers "Jamie" -> person.team = designers else -> person.team = others }

  • No need to packages/file alignment, no need for new XYZClass

    return people ?: emptyArrayList() // emptyArrayList() <- new ArrayList()

  • null checks ? ?:

  • let/it - reduces null checks in one line message?.let {println(it) } //=java: if (message != null) {System.out.println(message) } ^-- read as if message is not null, let the function run with it replaced as message

kFunctional Idiomatic

  • One line functions
    fun fullName() = "${firstName} ${lastName}" // string template compactness, kotlin infers return String
        // k= no need for public,   - the get/set are assumed from pojo
        public String fullName() {
            return getFirstName() + " " + getLastName();
        }
    

kStd Better tweaked kStdLib shortcuts

if (name.contains(firstName, true)) { ... } // true means name and firstName.toLowerCase() will convert for better comparison

println - System.out.println

KAndr Idiomatic, functional and more readable

  • Databinding - no more findviewbyid

    view.composer.text = "Allo!" // view is parent, composer is an ET .text is synthetic .setText("xadf'")

  • Beautifying click handlers

Anko higher level

  • Beautifying click handlers

    view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { System.out.println("This is horrible"); } });

    view.onClick { println("WAT") }

ATX - androidx.*

kBPR-Conversion

The auto-converter is your friend, but only after it’s your enemy Android Studio (as of version 3.0) comes with built-in support for auto-converting your Java code to Kotlin. Since both languages compile to bytecode that can be executed on the Java Virtual Machine, they can easily be translated into each other. However, this doesn’t mean the translations are always accurate.

public class SimpleClass {
    private String foo;
    public SimpleClass(String foo) {this.foo = foo; }
    public String getFoo() {return foo; }
    public void setFoo(String foo) {this.foo = foo; }
    public void addToFoo() {this.foo = foo + foo; }
}

    // Data class without addToFoo and with it .. 
class SimpleClass(var foo: String?) {
    fun addToFoo() {this.foo= foo!! + foo!! } //&lt;- BROKEN AUTO will give Null Pointer exception if foo was null
}
    // manual correction of function above =&gt; test null foo before converting 
fun addToFoo() {
    foo = foo?.let { 
        it + it
    }
}

AR Under Cover

  1. The Kotlin JVM runtime is ~800k .. and code generated refers to it for eg null argument checking, etc. This needs to be in the jar (so its class library is included) $ kotlinc HelloWorld.kt -include-runtime -d HelloWorld.jar $ java -jar HelloWorld.jar

  2. Alternatively put kotlin runtime jar on class path to run bytecode $ kotlinc HelloWorld.kt # makes HelloWorldKt.class $ java -cp $KOTLIN_HOME/lib/kotlin-runtime.jar:HelloWorld.jar HelloWorldKt

  3. In a library you don't need to include kotlin in jar .. $ kotlinc -include-runtime HelloWorld.kt -d HelloWorld

  4. Kotlin compliles to Java/JVM so 1:1 type matching and Java Lib/APIs used - with syntactic sugar...

Analyzing bytecode $ kotlinc HelloWorld.kt $ javap -c HelloWorldKt.class

# Where is static main declaration here? - bytecode adds it automagically?
fun main(args: Array&lt;String&gt;) { 
  println("Hello, World!") 
}

Compiled from "HelloWorld.kt"
public final class HelloWorldKt {
  public static final void main(java.lang.String[]);
    Code:
       0: aload_0
       1: ldc           #9                  // String args
       3: invokestatic  #15                 // Method kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull:(Ljava/lang/Object;Ljava/lang/String;)V
       6: ldc           #17                 // String Hello, World!
       8: astore_1
       9: getstatic     #23                 // Field java/lang/System.out:Ljava/io/PrintStream;
      12: aload_1
      13: invokevirtual #29                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      16: return
}

Avoid Errors .. Cast

Kotlin — Beware the Silent Cast – Craig Russell – Medium

Puzzlers k Inter

  • https://kotlinlang.org/docs/reference/basic-syntax.html

k Coroutines, Async, Perf, IO

rOS High Perf IO, Rvw

https://github.com/Kotlin/kotlinx-io

Coroutines - new paradigm - no callbacks,

JVM Server Ktor - 100% async - coroutines - maximal use of multi-core CPUs - vs nodejs?

k Andr - BkgndThread

lynas/Kotlin-android-background-thread AndroidAnkoListView/CustomAdapter.kt at master · lynas/AndroidAnkoListView Home · codepath/android_guides Wiki lynas/kotlin-javascript-example

k Async

rOS Adv Concurrency, Rvw

Kotlin/kotlinx.atomicfu: The idiomatic way to use atomic operations in Kotlin Kotlin/kotlin-coroutines: Design documents and examples for coroutines in Kotlin https://github.com/Kotlin/kotlinx.coroutines

PERF, AR

Great review on language differences .. Is Kotlin better than Java 8? https://www.quora.com/Is-Kotlin-better-than-Java-8 https://kotlinlang.org/docs/reference/comparison-to-java.html

PERF tips


0 comments

There are no comments yet

Add new comment

Similar posts

Serverless Computing

Android Layouts Design 101

Drawing, Canvas in Kotlin

Custom Views