-
Notifications
You must be signed in to change notification settings - Fork 0
Kotlin
T.Czogalik-extern edited this page Apr 12, 2022
·
10 revisions
var x = 5
- Compiler creates Int object with value 5
- Compiler assignes reference to Int object to variable x
- compiler can infer variable type
- Int, Byte, Short, Long
-
var x = 1creates Int -
var x = 1Lcreates Long -
var x: Byte = 1creates Byte
- Float, Double
-
var x = 1.0creates Double -
var x = 1.0Fcreate Float
var isBarking = true
var letter = 'c'var name = "frodo"- String Templates
var x = 42; var value = "Value of x is $x"- use properties:
var value ="my array has the size ${myArray.size}"
var myArray = arrayOf(1,2,3,4)- each item contains reference to object
myArray[0]myArray.size- compile infer type of array from its content
- explicit array type:
var myArray:Array<Byte> = arrayOf(1,2,3)
- var vs val: variable points to a different array vs the same array forever
- still modify content using val array
Java void == Kotlin Unit
- Unit is optional
fun foo(arg:String):Unit - call by reference
- can have default values
- pass arguments by naming them
fun test(foo:String, bar: String = "") {}
test(foo = "foo", bar = "bar")
while(condition) {}for (x in 1..10) {} // including 10for (x in 1 until 10) {} // excluding 10for (x in 10 downTo 1) {} // reverse orderfor (x in 1..10 step 2) {} // increase step sizefor (x in someArray) {} // loop through array elements
-
class Dog(val name: String){} // primary constructor- shortcut for
class Dog(name_param: String){ val name = name_param }
- shortcut for
- mix is also possible
class Dog(val name: String){ val age = 10 } - initializer block are called when object is created. immediately after constructor was called
class Dog(val name: String){ init { println("Dog $name was created") } } - multiple initializer block are possible. Run in order of definition
- custom getter
class Dog(val weight: String){ val weightInKg: Double get() = weight / 2.2 } val dog = Dog(2.2) println(dog.weightInKg) // 1 - custom setter
class Dog(weightParam: String){ var weight = weightParam set(value) { if (value > 0) field = value } } val dog = Dog(2.2) dog.weight = -1 println(dog.weightInKg) // 2.2 dog.weight = 10 println(dog.weightInKg) // 10 - secondary constructor
- if class has primary constructor secondary constructor needs to delegate to primary
class Dog(name: String, weight: String) {
constructor(weight_param:String) : this("Foo", weight_param) {}
}
- constructor can have default values (like functions)
- call constructor using named arguments (like functions)
- explicitly mark classes and functions
openfor inheritance. otherwise subclasses cannot override member - ':' === Java
extends - call super class primary constructor in subclass header
- override members with
overridekeyword - override val property with var (the other way is forbidden)
- val property creates getter, if overriden with var, compiler adds a setter
- override property type with subtype
- class can inherit only one other class
open class Animal(val habitat:String) {
open val food = ""
open fun makeNoise() {}
}
class Hippo(habitat: String) : Animal(habitat) {
override var food = ""
override fun makeNoise() {}
}
- cannot be instatiated
- mark members with
abstractkeyword- abstract member do not need to be
open
- abstract member do not need to be
abstract class Animal {
abstract val food: String
abstract fun eat()
}
val animal = Animal() // compile error
- class can implement multiple interfaces
- can have default implementation
- can have properties
interface Roamable {
fun roam() {
...
}
}
class Animal : Roamable {
override fun roam() {...}
}
-
==callsequals- checks object equivalence
-
===checks object identity- variables refer to same object
- does not rely on equals method
-
Anyis JavasObject- hashCode
- toString
- equals
- data classes automaticaly override equals, hashCode, toString function to check equality based on values of objects properties
- equals compares property values
- classes considering equal return same hashCode
- toString returns value for each property
- If properties are defined in class body they are not considered in functions
- object destructure
- data classes define
componentNfunctions
- data classes define
data class Recipe(val title: String = "", val isVegetarian: Boolean = false) {}
val r1 = Recipe("Chicken Bhuna")
val r2 = Recipe("Chicken Bhuna", false)
val r3 = Recipe(isVegetarian = true, title = "Thai Curry")
r1 == r2 // true
r1 === r2 // false
r1.equals(r2) // true
r1.hashCode().equals(r2.hashCode()) // true
r1.toString() // Recipe(title=Chicken Bhuna)
val title = r1.component1() // returns reference to first property in constructor
val isVegetarian = r1.component2()
val (title, isVegetatrian) = r1
- variables must explecitly declare that they are nullable
- variables, parameters and return types can be nullable
var w : Wolf = null // compile error
var w : Wolf? = null // works
fun printInt(x:Int?) {}
fun result() : Int? {}
- if you want to access member of nullable object compiler want's that you null check variable
- safe call
- member acces only if object is not null
- expression return null if object is null
-
letblock runs code if value is not null-
itvariable within let block refers to the null checked variable
-
- elvis operator
?:- if left side is not null return it. Otherwise return rigth side
-
!!throws null pointer exception
val w: Wolf? = null
w.eat() // compile error
// manualy null check
if (w != null) {
w.eat() // works
}
// safe call
w?.eat()
w?.let {
println(it.hunger)
}
w?.hunger ?: -1 // if w is null -1 is returned
w!!.hunger // if w is null throw null pointer exception
- try catch like java
- try and throw are expressions (unlike java)
// try expression
// result is either string as integer or null
val result = try {
str.toInt()
} catch(e:Exception) {
null
}
// throw expression
// if w not null assign h to w.hunger else throw Exception
val h = w?.hunger ?: throw AnimalException()
- simple collections are immutable
- if you want add / remove use MutableList/*Set/*Map
val shopping: List<String> = listOf("Tea", "Eggs")
val mutableShopping: List<String> = mutableListOf("Tea", "Eggs")
- uses hashcode to check if value already in set
- first compiler uses
===to check new value against already contained values - if false it uses
==to check new value against already contained values
- first compiler uses
val friends: Set<String> = setOf("Adam", "Adam", "Sue") // ignores duplicates
val fmutableFiends: Set<String> = mutableSetOf("Adam", "Adam", "Sue")
val r1 = Recipe("Chicken Soup")
val r2 = Recipe("Beef Soup")
val r3 = Recipe("Pork Soup")
val recipes: Map<String, Recipe> = mapOf("Recipe1", r1,"Recipe2", r2,"Recipe3", r3)
recipes.containsKey("Recipe1") // true
recipes.containsValue(r1) // true
recipes.getValue("Recipe1) // r1
val mutableRecipes: Map<String, Recipe> = mutableMapOf("Recipe1", r1,"Recipe2", r2,"Recipe3", r3)
mutableRecipes.put("Recipe4", Recipe("Curry"))
- restrict Generics to supertype
class Contest<T: Pet> { ... }
- Generics can be uses outside of classe
fun <T: Pet> listPet(t: T): List<T> {...}
- if you want to use generic subtype in place of generic supertype the generic type needs to be covariant using
out
interface Retailer<T> { ... }
val petRetailer: Retailer<Pet> = CatRetailer() // compile error
// covariant version
interface Retailer<out T> { ... }
val petRetailer: Retailer<Pet> = CatRetailer() // works
- if you want to use generic supertype in place of generic subtype the generic type needs to be contravariant using
in- class can be constructor contravariant only
class Vet<T: Pet> {...}
val catContest = Contest<Cat>(Vet<Pet>()) // compile error
// contravariant version
class Vet<in T: Pet> {...}
val catContest = Contest<Cat>(Vet<Pet>()) // works
- defined within
{} - are anonymouse
- can be assigned to variable
- call
invoketo execute lambda - if single parameter and compile can infer type you can use
itto refer to parameter -
Unitif lambda has no return value - lambdas can be passed to functions
- functions having lambda parameters or return types are
higher order functions - can be moved outside
()
- functions having lambda parameters or return types are
- can be return type
- use typealias for assigning alternative name for existing type
typealias Doubleconversion = (Double) -> Double
val add = {x: Int, y:Int -> x + y}
add.invoke(6,7)
// or
add(6,7)
val addFive : (Int)->Int = {x -> x + 5}
// compile can infer type of x
val addFive: (Int) -> Int = {it + 5}