# Warning - this file should only be modified with vifs(8) # # Failure to do so is unsupported and may be destructive. # LABEL=WinData none ntfs rw,noauto
funanalyzeUserSession(session: Session){ val user = session.user if (user is FaceBookUser){ println(user.accountId) } (session.user as? FaceBookUser)?.let { println(it.accountId) } }
takeIf returns the receiver object if it satisfies the given predicate, otherwise returns null
1 2 3
issue.takeIf { it.status == FIXED}
person.patronymicName.takeIf(String::isNotEmpty)
1 2 3 4
val number = 42 println(number.takeIf { it > 10 }) // 42 val other = 2 println(other.takeIf { it > 10 }) // null
Using takeIf in chained calls
1 2 3
issues.filter { it.status == OPEN } .takeIf(List<Issue>::isNotEmpty) ?.let { println("There're some open issues") }
takeUnless returns the receiver object if it does not satisfy the given predicate, otherwise returns null
repeat
1 2 3 4
repeat(10) { println("Welcome!") }
All these functions are declared as inline functions (There is no performance overhead)
2. The power of inline
1) inline function
compiler substitutes a body of the function instead of calling it
1 2 3 4 5 6 7 8 9 10 11
funmyRun(f: () -> Unit) = f() inlinefunrun(f: () -> Unit) = f() funmain() { val name = "Kotlin" // brings performance overhead (class InlineKt$main$1 is created) myRun { println("Hi, $name") } // No performance overhead run { println("Hi, $name") } // in comparison to println("Hi, $name") }
inline constraints : You can’t postpone the call.
2) withLock function
3) Resource management: use function
No performance overhead when you use
run, let, takeIf, takeUnless, repeat, withLock, use
No anonymous class or extra objects are created for lambda under the hood
Note: If you call a inline function in Java, you won’t get it inlined.
Because it is credit to the Kotlin compile
4) @InlineOnly
Specifies that this function should not be called directly without inling
Not in your jar
Can’t be called in Java
Fin.
However, use inline in your code with care, because actually hotspot can do this job for you.
二. Sequences
1. Collections vs Sequences
1) Collections
example
1 2 3 4 5 6
val list = listOf(1, 2, 3) val maxOddSquare = list .map { it * it } .filter { it % 2 == 1 } .max() // create 3 collections in total
Operations on collections
lambdas are inlined (no performance overhead)
But : intermediate collections are created for chained calls
Collections vs Sequences is like Eager vs lazy evaluation
2) Sequences
example
1 2 3 4 5 6 7
val list = listOf(1, 2, 3) val maxOddSquare = list .asSequence() .map { it * it } .filter { it % 2 == 1 } .max() // create 1 collections in total
2. More about Sequences
1) Test 1
funtest1() {
listOf(1, 2, 3, 4)
.map { it * it }
.find { it > 3 } // 4// we don't do anything unless it is need
listOf(1, 2, 3, 4)
.asSequence()
.map { it * it }
.find { it > 3 } // 4
}
<!--code9-->


- intermediate operations return you another sequence
- terminal operations return you everything else
3) Test 3 Order of operations is important
funtest3() {
funm(i: Int): Int {
print("m$i ")
return i
}
funf(i: Int): Boolean {
print("f$i ")
return i % 2 == 0
}
val list = listOf(1, 2, 3, 4)
list.asSequence().map(::m).filter(::f).toList() // m1 f1 m2 f2 m3 f3 m4 f4
list.asSequence().filter(::f).map(::m).toList() // f1 f2 m2 f3 f4 m4
}
<!--code10-->

2) Generating a sequence
generateSequence{xx} : until xx return null
1 2 3 4 5 6
funtest1() { val seq = generateSequence { Random.nextInt(5).takeIf { it > 0 } } println(seq.toList()) }
3) Generating an infinite sequence
1 2 3 4
funtest2() { val numbers = generateSequence(0) { it + 1 } numbers.take(5).toList() // [0,1,2,3,4] }
To prevent integer overflow
1 2 3 4
funtest3() { val numbers = generateSequence(BigInteger.ZERO) { it + BigInteger.ONE } numbers.take(5).toList() // [0,1,2,3,4] }
4) Yield (lazy)
funtest5(){
val numbers = sequence {
var x =0while (true){
yield(x++)
}
}
numbers.take(5).toList() // [0,1,2,3,4]
}
<!--code14-->
val map = mutableMapOf<Int, MutableList<Person>>() for (person in people) { if (person.age !in map) { map[person.age] = mutableListOf() } val group = map.getValue(person.age) group += person } for (person in people) { val group = map.getOrPut(person.age) { mutableListOf() } group += person } val mapOneWay = people.groupBy(Person::age)
people .asSequence() .groupBy { it.age } // not lazy .mapValues { (_, group) -> group.size } people .asSequence() .groupingBy { it.age } .eachCount() }
三. Lambda with Receiver
1. Lambda with Receiver
1) with function
1 2 3 4 5 6
val sb = StringBuilder() sb.appendln("Alphabet: ") for (c in'a'..'z'){ sb.append(c) } sb.toString()
1 2 3 4 5 6 7 8
val sb = StringBuilder() with(sb){ appendln("Alphabet: ") for (c in'a'..'z'){ append(c) } toString() }
with(receiver: T, block: T.() -> R): R is a function
2) Lambda vs lambda with receiver
regular funtion
regular lambda
Extension function
lambda with receiver
1 2 3 4 5 6 7 8 9
funtest2() { // lambda val isEven: (Int) -> Boolean = { it % 2 == 0 } isEven(0)
// lambda with receiver val isOdd: Int.() -> Boolean = { this % 2 == 1 } 1.isOdd() }
improvment:
1 2 3 4 5 6 7 8
funtest3(){ val s = buildString { appendln("Alphabet: ") for (c in'a'..'z') { append(c) } } }

Expressions that have Nothing type :
throw IllegalArgumentExceptionreturnTODO("Needs to be done")
2) Nothing


Kotlin
Java
Nothing
void
.png)
the simplest expression of Nothing? type: null
3) Type of null
1 2
var user = null// user is inferred as Nothing? val users = mutableListOf(null) // users is inferred as MutableList<Nothing?>
3. Nullable types
Java
Kotlin
@Nullable Type
Type?
@NotNull Type
Type
Type
Type! (Notation, not syntax)
Type that came from Jave -> type of “unknown” nullability in Kotlin
1) Type! in Kotlin
1 2 3 4 5 6
// Java publicclassSession{ public String getDescription(){ returnnull; } }
IllegalStateException
1 2 3 4 5
funtest1(){ val session = Session() val description:String = session.description // exception println(description.length) }
NullPointerException
1 2 3 4 5
funtest2(){ val session = Session() val description = session.description // description is inferred as `String!` println(description.length) // exception }
(Correct) use ?. to safe access
1 2 3 4 5
funtest3() { val session = Session() val description = session.description // description is inferred as `String!` println(description?.length) }
(Correct) to prevent test2, if you use .length, you’ll get compile error
1 2 3 4 5
funtest4() { val session = Session() val description: String? = session.description // description is inferred as `String!` println(description?.length) }
2) How to still prevent NPEs?
Annotate your Java types
Different annotations are supported
@Nullable
@NotNull
JetBrains
@Nullable
@NotNull
Android
@Nullable
@CheckForNull
JSR-305
@Nullable
@CheckForNull
FindBugs
@NonNull
Lombok
…
…
…
1 2 3 4 5 6 7
// Java publicclassSession{ @Nullable public String getDescription(){ returnnull; } }
1 2 3
val session = Session() val description = session.description // description is inferred as `String?` println(description?.length)
Tip: make one annotation as default, only specify the other as needed
Specify types explicitly
1 2 3 4 5 6
// Java publicclassSession{ public String getDescription(){ returnnull; } }
1 2 3
val session = Session() val description: String? = session.description // description is inferred as `String!` println(description?.length)
1 2 3
val session = Session() val description:String = session.description // get IllegalStateException exception immediately, better than NPE println(description.length)
4. Collection types
1) Standard collections
1 2 3 4 5 6
valset = hashSetOf(1,7,53) val list = arrayListOf(1,7,53) val map = hashMapOf(1 to "one") println(set.javaClass) //class java.util.HashSet println(list.javaClass) // class java.util.ArrayList println(map.javaClass) // class java.util.HashMap
2) (Read-only)List & MutableList
2 interfaces declared in kotlin.collections package
MutableList extends List
Note: Read-only $\neq$ immutable
Read-only interface just lacks mutaing methods
The actual list can ve changed by another reference
See example below
1 2 3 4 5 6
funreadOnlyList(){ val mutableList = mutableListOf(1, 2, 3) val list: List<Int> = mutableList mutableList.add(4) println(list) // [1, 2, 3, 4] }
Under the hood, both List and MutableList is the same java.util.List in bytecode

classStateLogger{ var state = false set(value) { println( "state has changed: " + "$field -> $value" ) field = value } }
No backing field will be generated if you define accessors (custom getter and setter) and don’t use a field keyword
1 2 3 4 5 6 7 8 9
enumclassState{ ON, OFF } classStateLogger{ privatevar boolState = false var state: State get() = if (boolState) ON else OFF set(value: State) { boolState = value == ON } }
5) Default accessors
1 2 3 4 5 6 7
classA{ var trivialProperty: String = "abc" // get() = field // set(value) { // field = value // } }
You can always use property instead of getter or setter (Under the hood, getter and setter will be called)
And inside the class, optimization performed by the compiler are possible (using the filed directly, but only with the trial/default case)
6) Change visibility of a setter
You want a var mutable property to be accessible only as a read-only property outside of the class
1 2 3 4 5 6 7 8
classLengthCounter{ var counter: Int = 0 privateset
val value:String = run { println("1. computed") "1. Hello" }
val lazyValue:String by lazy { println("2. computed") "2. Hello" }
funmain(){ // 1. computed }
2) lateinit
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
// lateinit is still unsafe and a runtime exception may be thrown, but with a detailed message lateinitvar myData: String // lateinit's constraints // 1. it can't be val // 2. it can't have a primitive type
// check whether `lateinit var` was initialized classMyClass{ lateinitvar lateinitVar:String funinitializationLogic(){ println(this::lateinitVar.isInitialized) // false lateinitVar = "" println(this::lateinitVar.isInitialized) // true } } funmain(){ var c = MyClass() c.initializationLogic() }
二. Object-oriented Programming
1. OOP in Kotlin
1) modifier intro.
Modifier
Description
final (default)
cann’t be overridden
open
can be overridden
abstract
must be overridden
override (mandatory)
Overrides a member in a superclass or interface
Visibility Modifier
Class member
Top-level declaration
public (default)
visible everywhere
visible everywhere
internal
visible in the mudule
visible in the module
protected
visible in the class and the subclasses (in Java, it includes the same package)
private
visible in the class
visible in the file
Visibility modifiers and Java
Kotlin modifier
JVM level
public
public
internal
public & name mangling
protected
protected
private
private / package private
2) Package structure
1 2 3 4 5 6 7 8 9 10 11 12 13
// Java package:org.kyle.store City.java Customer.java Order.java // Kotlin package:store StoreModel.kt (File Structure) Class City Class Customer Class Order
one kotlin file may contain several classes and top-level functions
2. Constructors, Inheritance syntax
1) Constructor
Primer Constructor
var/val on a parameter creates a property
1 2 3
classPerson(val name: String) {
}
the same as
1 2 3 4 5 6
classPerson(name: String){ val name:String init { this.name = name } }
if foo != null return foo.bar() if foo == null return null
1 2
val length:Int? = if(s != null ) s.length elsenull val length:Int? = s?.length
Elvis operator ?:
foo ?: bar means
if foo != null return foo
if foo == null return bar
1 2
val length:Int = if(s != null) s.length else0 val lenght:Int = s?.length ?: 0
Both ?. and ?: come from Groovy
Not-null assertion operator !!
foo!! means
if foo != null return foo
if foo == null return NPE
Remember Prefer ?.?:if-checks to !!
2. Nullable types under the hood
1) Under the hood
Nullable types under the hood are using @Nullable@NotNull annotations
There is no performance ahead
2) Nullable types VS Optional
$Nullable Types \neq Optional$
NullableType uses only one object
Optional type uses 2 objects (one is for the wrapper, the other is the actual type)
3) List<Int?> VS List<Int>?
1 2 3 4 5 6 7
funfoo(list1:List<Int?>,list2:List<Int>?){ list1.size val i: Int? = list1.get(0)
list2?.size val j: Int? = list2?.get(0) }
3. Safe casts
safe cast as?
foo as? Type means
if foo is Type -> foo as Type
if foo !is Type -> null
1 2
val length:Int? = if(s != null ) s.length elsenull val length:Int? = s?.length
4. Importance of nullability
二. Functional Programming
1. Lambdas
1 2 3 4 5 6 7 8 9 10 11 12 13 14
val list = listOf(23, 34) val map = mapOf(1 to 11,2 to 22) list.any({ i: Int -> i > 0 }) // full syntax list.any() { i: Int -> i > 0 } // when lambda is the last argument list.any { i: Int -> i > 0 } // empty parentheses can be omitted list.any { i -> i > 0 } // type can be omitted if it's clear from the context list.any { it > 0 } // "it" denoted the argument if it's only one list.any { println("processing $it") it > 0// the last expression is the result } map.mapValues { entry -> "${entry.key} -> ${entry.value}" } map.mapValues { (key,value) -> "$key -> $value" } map.mapValues { (_,value) -> "$value" }
2. Common Operations on collections
filter : return a new list satisfying the predict
map : return a new list with the operation
any/all/none: return true if any/all/none satisfy the predict
find/firstOrNull return the first result, if none, return null
first : if no element throw an exception
count : counts the number of the given predict
partition : return a pair of list list
groupBy
associateBy : duplicates removed
associate: create a pair T to V (V = f(T))
zip : length = min(list1, list2)
zipWithNext
flatten : call on a List<List<>>
flatMap ?
3. Operation Quiz
1) Simplifying Code
don’t use it if it has different types in neighboring lines
prefer explicit parameter names if it might be confusing otherwise
learn the library and try to reuse the library functions as much as possible
4. Function types
1) lambda has a type (xx,xx) -> xx
1 2
val sum = { x: Int, y: Int -> x + y } val sum2: (Int, Int) -> Int = { x, y -> x + y }
2) it can be called like a function
1 2
val isEven = { i: Int -> i % 2 == 0 } val result: Boolean = isEven(42) // true
3) Passing a variable of function type as an argument
1 2 3
val list = listOf(1, 2, 3, 4) list.any(isEven) // true list.filter(isEven) // [2,4]
4) Calling lambda directly
1 2
;{ println("hey!") }() // seems strange run { println("hey") } // use run instead
5) SAM interfaces in Java
1 2 3 4
// use lambda as parameter of SAM like Runnable .. // In Java: voidpostponeComputation(int delay, Runnable computation) postponeComputation(1000){ println(42) }
6) Function types and nullability
1 2 3 4
// val f1: () -> Int? = null val f2: () -> Int? = { null } val f3: (() -> Int)? = null // val f4: (() -> Int)? = { null }