25 October 2018

1. Basics

Example 1. asdsf
package com.example;
import com.package

/**
* A block comment
**/

// single line comment

//trailing semicolon is not required

//entrypoint
fun main(args: Array<String>) {
    println("Hello, World!")
}

1.1. Declaring

Example 2. sdslf
//declaring variables
val name = "john"    // cannot be changed
var age = 5          // can be changed
age+++

//declaring function
fun sum(a:Int, b:Int) Int {
    return a+b
}

// single expression function
fun sum(a: Int, b: Int) = a + b

1.2. Null Safty and Optional

var foo:String = "foo"
foo = null // compilation error, foo is a String and can not be null
var bar:String? = "bar"
bar = null // correct, bar is an Optinal String

/**
* Safe call(?.) and explicit call (!!.)
**/
val length = bar.length // Compilation error cause bar can be null
val length = bar?.length // Correct, will be null if bar is null
val length = bar!!.length // Correct, will throw NPE if bar is null

/**
* Definition default value with elvis operator(?:)
**/
val length = if(bar != null) bar.length else -1
// equivalent to
// length will be 0 if name is null
val length = bar?.length ?: -1
// will return if name is null
val length = bar?.length ?: return
// will throw error when name is null
val length = bar?.length ?: throw Error()

2. Control Structure

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

// For loop
val list = listOf("A", "B", "C")
for (element in list) {
    println(element)
}

// When statement - replaces the old C-like switch operator
fun numberTypeName(x: Number) = when(x) {
    0 -> "Zero"
    in 1..4 -> "Four of less"
    5, 6, 7 -> "Five to seven"
    is Byte -> "Byte"
    else -> "Some number"
}

// When expression
fun signAsString(x: Int)= when {
    x < 0 -> "Negative"
    x == 0 -> "Zero"
    else -> "Positive"
}

3. Classes

//A simple Java POJO(Getter, Setter, Constructor) in one line
//All is public visibility by default
class User {
    var firstname: String
    var lastname: String
    var address: String? = null
}

class User() {// primary empty constructor
    constructor(fn: String):this() {// secondary constructor must call first one
        firstName = fn
    }
    var firstName:String = ""
    val isFilled:Boolean // read only access property
      get() = !firstName.isEmpty()
}
//Primary constructor
class Person(val name: String, var age: Int) // name is read-only, age is mutable

//inheritance
// by default class is final, so need open declare a inheritable class
open class Person(val name: String) {
    open fun hello() = "Hello, I am $name"
}

// the semicolon operator makes inheritance between classes
class PolishPerson(name: String) : Person(name) {
    override fun hello() = "Dzien dobry, jestem $name"
}

// Properties with assessors
class Person(var name: String, var surname: String) {
    var fullName: String
      get() = "$name $surname"
      set(value) = {
          val (first, rest) = value.split(" ", limit = 2)
          name = first
          surname = rest
      }
}

//no static, using object makes class singleton
object Resource {
    //properties, funtions
}

//data keywords brings toString(), equals(), hashCode(), copy() and exploded data capabilities(deconstruction)
data class Person(val name: String, var age: Int)
val mike = Person("Mike", 23)

print(mike.toString())
print(mike == Person("Mike", 21))

print(mike.hashCode() == Person("Mike", 23).hashCode())

val (name, age) = mike
print($name, $age)// Mike,23

val jake = mike.copy(name = "Jake")

4. Collections

Example 3. Collection Literals
// Kotlin makes difference between immutable collections and mutable ones
val list = listOf("a","b","c","d")
val set = setOf()
val array = arrayOf()
val seq = sequenceOf()

1 to "A" // Pair

val map = mapOf("a" to 1, "b" to 2, "c" to 3)
for ((k,v) in map) {
    print($k -> $v)
}

//Maps and Array can be accessed directly with [] syntax or range expressions.
// write with mutable map
map["a"] = "my value"
// filter collection
items.filter {it % 2 == 0}

// mutable vs immutable
var list = mutableListOf(3,4,2,1)
...
Example 4. Collection processing
students
  .filter { it.passing && it.averageGrade > 4.0 }
  //Only passing students
  .sortedByDescending { it.averageGrade }
  //Starting from ones with biggest grades
  .take(10)
  .sortedWith(compareBy({ it.surname }, { it.name }))
  //sort by surname and then name

generateSequence(0) { it + 1 }
// Infinitive sequence of next numbers starting on 0
  .filter { it % 2 == 0 } // Keep only even
  .map { it * 3 } // Triple every one
  .take(100) // Take first 100
  .average() // Count average

// Most important functions for collectio processing
val l = listOf(1, 2, 3, 4)
l.filter{ it % 2 == 0 }// returns only elements matched by predicate

l.map{ it * 2 } // returns elements after transformation

l.flatMap{ listOf(it, it + 10) }// returns elements yielded from results of trans

//accumulates elements
l.fold(0.0) { acc, i -> acc + i }
l.reduce{acc, i -> acc * i }

//perfons an action on every element
l.forEach{print(it)}
l.onEach{print(it)}

// slip into pair of lists
val (even, odd) = l.partition{it % 2 == 0}
print(even)
print(odd)

l.min()
l.minBy { -it }
l.max()
l.maxBy{ -it }

l.first()
l.first{ it % 2 == 0}

l.count{ it % 2 ==0 } // count elments matched by predicate

l.sorted()
l.sortedBy{ it % 2 }

l.groupBy{ it % 2 }

l.distinct()

5. Functions

Example 5. Function Types
()->Unit - takes no arguments and returns nothing(Unit means nothing)
(Int, Int)->Int - takes two arguments of Int and return Int
(()->Unit)->Int - takes another function and returns Int.
(Int)->()->Unit - takes argument of type Int and returns function
Example 6. Function Literal
//simple lambda expression
val add: (Int, Int) -> Int = { i, j -> i + j}

val printAndDouble: (Int) -> Int = {
    println(it) // `it` is reference of current single paramenter
    it * 2 // In lambda, last expression is returned
}

//Anonymous function alternative
val printAndDoubleFun: (Int) -> Int = fun(i: Int): Int {
  println(i) // Single argument can't be referenced by `it`
  return i * 2 // Needs return explicitly
}

//Default Values
fun read(b: Array<Byte>, off: Int = 0, len: Int = b.size()) {
 //...
}

//Named Arguments
read(myBytes, 0, myBytes.length) // old way to call
reformat(myBytes, len = 128) // using default values & named params
Example 7. Extension
fun Int.isEven() = this % 2 == 0
print(2.isEvent()) //true
fun List<Int>.average() = 1.0 * sum() / size