1. More readable 2. (Usually) More overhead 3. We dont know which - - PowerPoint PPT Presentation

1 more readable 2 usually more overhead 3 we don t know
SMART_READER_LITE
LIVE PREVIEW

1. More readable 2. (Usually) More overhead 3. We dont know which - - PowerPoint PPT Presentation

1. More readable 2. (Usually) More overhead 3. We dont know which one we aspire to more A clever title Christina Lee Two Stones, One Bird A clever title Christina Lee Kill two birds with one stone Kill two birds with one


slide-1
SLIDE 1
slide-2
SLIDE 2
  • 1. More readable
  • 2. (Usually) More overhead
  • 3. We don’t know which one we aspire to more
slide-3
SLIDE 3

🙄

slide-4
SLIDE 4

A clever title

Christina Lee

slide-5
SLIDE 5

A clever title

Christina Lee

Two Stones, One Bird

slide-6
SLIDE 6

“Kill two birds with one stone”

slide-7
SLIDE 7

“Kill two birds with one stone” Accomplish two objectives with a single action ==

slide-8
SLIDE 8

Accomplish two objectives with a single action GOOD! ==

slide-9
SLIDE 9

Two for one GOOD! == One for two ???? ==

slide-10
SLIDE 10

Two for one GOOD! == One for two ???? ==

🤕

slide-11
SLIDE 11

ARGUE ON THE INTERNET!

slide-12
SLIDE 12

ARGUEMENTS ON THE INTERNET! W I N

slide-13
SLIDE 13
  • 1. Meme effectively
  • 2. (Optional) Know

something about the topic

slide-14
SLIDE 14
  • 1. Meme effectively
  • 2. (Optional) Know

something about the topic

¯\_()_/¯

slide-15
SLIDE 15
  • 2. (Optional) Know

something about the topic

☝ 👍

slide-16
SLIDE 16

Nullability

slide-17
SLIDE 17

data class Pin( val id: String, val creator: User? = null, // ... )

slide-18
SLIDE 18

fun updateAvatar(pin: Pin, avatarView: AvatarView) { if (pin.creator != null) { avatarView.bindUser(pin.creator) } }b if (pin.creator != null) { avatarView.bindUser(pin.creator) }q

slide-19
SLIDE 19

fun updateAvatar(pin: Pin, avatarView: AvatarView) { if (pin.creator != null) { avatarView.bindUser(pin.creator) } }b if (pin.creator != null) { avatarView.bindUser(pin.creator) }q

slide-20
SLIDE 20

fun updateAvatar(pin: Pin, avatarView: AvatarView) { if (pin.creator != null) { avatarView.bindUser(pin.creator) } }b if (pin.creator != null) { avatarView.bindUser(pin.creator!!) }q

slide-21
SLIDE 21

fun updateAvatar(pin: Pin, avatarView: AvatarView) { val creator = pin.creator if (creator != null) { avatarView.bindUser(creator) }q }b

slide-22
SLIDE 22

fun updateAvatar(pin: Pin, avatarView: AvatarView) { pin.creator?.let { avatarView.bindUser(it) } }b

slide-23
SLIDE 23

Nullability

slide-24
SLIDE 24

???

slide-25
SLIDE 25

Style guide

slide-26
SLIDE 26

Style guide

2

slide-27
SLIDE 27

Effective Kt

slide-28
SLIDE 28

Effective Kt

slide-29
SLIDE 29

Readability Readability Readability

slide-30
SLIDE 30

Readability Performance +

slide-31
SLIDE 31

Readability Performance +

slide-32
SLIDE 32

Readability Performance

You are here

slide-33
SLIDE 33

Nullability

slide-34
SLIDE 34

fun updateAvatar(pin: Pin, avatarView: AvatarView) { val creator = pin.creator if (creator != null) { avatarView.bindUser(creator) }q }b fun updateAvatar(pin: Pin, avatarView: AvatarView) { pin.creator?.let { avatarView.bindUser(it) } }b fun updateAvatar(pin: Pin, avatarView: AvatarView) { if (pin.creator != null) { avatarView.bindUser(pin.creator!!) }q }b

slide-35
SLIDE 35

!!

slide-36
SLIDE 36

fun updateAvatar(pin: Pin, avatarView: AvatarView) { val creator = pin.creator if (creator != null) { avatarView.bindUser(creator) }a }b fun updateAvatar(pin: Pin, avatarView: AvatarView) { pin.creator?.let { avatarView.bindUser(it) }c }d

slide-37
SLIDE 37

public static final void updateAvatar(@NotNull Pin pin, @NotNull AvatarView avatarView) { Intrinsics.checkParameterIsNotNull(pin, "pin"); Intrinsics.checkParameterIsNotNull(avatarView, "avatarView"); User creator = pin.getCreator(); if(creator != null) { avatarView.bindUser(creator); }a }b fun updateAvatar(pin: Pin, avatarView: AvatarView) { val creator = pin.creator if (creator != null) { avatarView.bindUser(creator) }a }b

slide-38
SLIDE 38

public static final void updateAvatar(@NotNull Pin pin, @NotNull AvatarView avatarView) { Intrinsics.checkParameterIsNotNull(pin, "pin"); Intrinsics.checkParameterIsNotNull(avatarView, "avatarView"); User creator = pin.getCreator(); if(creator != null) { avatarView.bindUser(creator); }a }b

slide-39
SLIDE 39

fun updateAvatar(pin: Pin, avatarView: AvatarView) { val creator = pin.creator if (creator != null) { avatarView.bindUser(creator) }a }b fun updateAvatar(pin: Pin, avatarView: AvatarView) { pin.creator?.let { avatarView.bindUser(it) }c }d

slide-40
SLIDE 40

fun updateAvatar(pin: Pin, avatarView: AvatarView) { pin.creator?.let { avatarView.bindUser(it) }c }d

slide-41
SLIDE 41

public static final void updateAvatar(@NotNull Pin pin, @NotNull AvatarView avatarView) { Intrinsics.checkParameterIsNotNull(pin, "pin"); Intrinsics.checkParameterIsNotNull(avatarView, "avatarView"); User var10000 = pin.getCreator(); if(var10000 != null) { User var2 = var10000; avatarView.bindUser(var2); }e }f

slide-42
SLIDE 42

public static final void updateAvatar(@NotNull Pin pin, @NotNull AvatarView avatarView) { Intrinsics.checkParameterIsNotNull(pin, "pin"); Intrinsics.checkParameterIsNotNull(avatarView, "avatarView"); User var10000 = pin.getCreator(); if(var10000 != null) { User var2 = var10000; avatarView.bindUser(var2); } }

😲

slide-43
SLIDE 43

L1 LINENUMBER 13 L1 ALOAD 0 // load pin INVOKEVIRTUAL Pin.getCreator () //invoke getter ASTORE 2 // store in field 2 L2 LINENUMBER 14 L2 ALOAD 2 // load field 2 (user) IFNULL L3 // if user is null, jump to return L4 LINENUMBER 15 L4 ALOAD 1 // load view ALOAD 2 // load user INVOKEVIRTUAL AvatarView.bindUser() //invoke L3 LINENUMBER 22 L3 RETURN if (creator == null)

slide-44
SLIDE 44

L1 LINENUMBER 13 L1 ALOAD 0 // load pin from ref 0 INVOKEVIRTUAL Pin.getCreator() // invoke pin.getCreator() DUP // duplicate returned value IFNULL L2 // if null pop ASTORE 2 // store creator value in field 2 L3 ALOAD 2 // load ref 2 onto stack ASTORE 3 // store in field 3 L4 LINENUMBER 14 L4 ALOAD 1 // load “avatarView” ALOAD 3 // load value of pin.getCreator() INVOKEVIRTUAL AvatarView.bindUser L2 POP pin.creator?.let { }

slide-45
SLIDE 45

L1 LINENUMBER 13 L1 ALOAD 0 // load pin INVOKEVIRTUAL Pin.getCreator() // invoke getter ASTORE 2 // store result in field 2 L2 LINENUMBER 14 L2 ALOAD 2 // load creator DUP // duplicate IFNULL L3 // if null?? ASTORE 3 // store in field 3 L4 ALOAD 3 // load field 3 ASTORE 4 // store in field 4 L5 LINENUMBER 15 L5 ALOAD 1 // load view ALOAD 4 // load user INVOKEVIRTUAL AvatarView.bindUser(v) //invoke view with user val creator = pin.creator; creator?.let { }

slide-46
SLIDE 46

TL;DR: Idk

slide-47
SLIDE 47

TL;DR: It doesn’t matter*

slide-48
SLIDE 48

val creator = pin.creator if (creator != null) { avatarView.bindUser(creator) } vs. pin.creator?.let { avatarView.bindUser(it) }

slide-49
SLIDE 49

val creator = pin.creator if (creator != null) { val firstName = creator.firstName if (firstName != null) { avatarView.setFirstName(firstName) } } vs. pin.creator?.firstName?.let { avatarView.setFirstName(it) }

slide-50
SLIDE 50

val creator = pin.creator if (creator != null) { val firstName = creator.firstName if (firstName != null) { avatarView.setFirstName(firstName) } } else { } vs. pin.creator?.firstName?.let { avatarView.setFirstName(it) }.orElse { }

slide-51
SLIDE 51

val creator = pin.creator if (creator != null && creator.firstName != null) { avatarView.setFirstName(firstName) } else { } vs. pin.creator?.firstName?.let { avatarView.setFirstName(it) }.orElse { }

slide-52
SLIDE 52

Lean towards let

slide-53
SLIDE 53

Lean towards let*

slide-54
SLIDE 54

Lean towards let*

* Brought to you by Twitter

slide-55
SLIDE 55

Lean towards let

slide-56
SLIDE 56

with / apply let / also

slide-57
SLIDE 57

with / apply let / also

slide-58
SLIDE 58

with / apply let / also

public inline fun <T, R> with( receiver: T, block: T.() -> R ): R = receiver.block()

slide-59
SLIDE 59

with / apply let / also

public inline fun <T, R> with( receiver: T, block: T.() -> R ): R = receiver.block()

slide-60
SLIDE 60

with / apply let / also

public inline fun <T, R> with( receiver: T, block: T.() -> R ): R = receiver.block() with(foo) {h foo.bar() foo.baz() }g

slide-61
SLIDE 61

with / apply let / also

public inline fun <T, R> with( receiver: T, block: T.() -> R ): R = receiver.block() with(foo) {h bar() baz() }g

slide-62
SLIDE 62

with / apply let / also

public inline fun <T, R> with( receiver: T, block: T.() -> R ): R = receiver.block()

slide-63
SLIDE 63

with / apply let / also

public inline fun <T, R> with( receiver: T, block: T.() -> R ): R = receiver.block()

slide-64
SLIDE 64

with / apply let / also

foo.bar() foo.baz() foo.bam()

Same receiver multiple times Logically grouped functions

slide-65
SLIDE 65

with / apply let / also

with(db) {

  • pen()

commit(obj) close() }

slide-66
SLIDE 66

with / apply let / also

slide-67
SLIDE 67

with / apply let / also

slide-68
SLIDE 68

with / apply let / also

public inline fun <T> T.apply( block: T.() -> Unit ): T { block(); return this }a

slide-69
SLIDE 69

with / apply let / also

public inline fun <T> T.apply( block: T.() -> Unit ): T { block(); return this }a

Extension function

slide-70
SLIDE 70

with / apply let / also

public inline fun <T> T.apply( block: T.() -> Unit ): T { block(); return this }a

Lambda + Receiver

slide-71
SLIDE 71

with / apply let / also

public inline fun <T> T.apply( block: T.() -> Unit ): T { block(); return this }a

slide-72
SLIDE 72

with / apply let / also

public inline fun <T> T.apply( block: T.() -> Unit ): T { block(); return this }a

“I need this object, but I need to run a bit of code on it before I use it”

slide-73
SLIDE 73

with / apply let / also

public inline fun <T> T.apply( block: T.() -> Unit ): T { block(); return this }a

INITIALIZATIONS

slide-74
SLIDE 74

with / apply let / also

val myTextView = TextView(context).apply { layoutParams = LinearLayout.LayoutParams(...) }

slide-75
SLIDE 75

with / apply let / also

return foo.apply { baz() }

slide-76
SLIDE 76

with / apply let / also

slide-77
SLIDE 77

with / apply let / also

slide-78
SLIDE 78

with / apply let / also

public inline fun <T, R> T.let( block: (T) -> R ): R = block(this)

slide-79
SLIDE 79

with / apply let / also

public inline fun <T, R> T.let( block: (T) -> R ): R = block(this) Everything but with() Spoiler Alert:

slide-80
SLIDE 80

with / apply let / also

public inline fun <T, R> T.let( block: (T) -> R ): R = block(this)

slide-81
SLIDE 81

with / apply let / also

public inline fun <T, R> T.let( block: (T) -> R ): R = block(this)

😲

slide-82
SLIDE 82

with / apply let / also

val usernameView: View? = user.name?.let { name -> ViewWithText(context, name) }

slide-83
SLIDE 83

with / apply let / also

DexMethods.kt: http://bit.ly/2xFN3Bd

slide-84
SLIDE 84

with / apply let / also

Nullablity 🎊 🎊

slide-85
SLIDE 85

with / apply let / also

slide-86
SLIDE 86

with / apply let / also

slide-87
SLIDE 87

with / apply let / also

public inline fun <T> T.also( block: (T) -> Unit ): T { block(this); return this }a

slide-88
SLIDE 88

with / apply let / also

public inline fun <T> T.also( block: (T) -> Unit ): T { block(this); return this }a

slide-89
SLIDE 89

with / apply let / also

public inline fun <T> T.also( block: (T) -> Unit ): T { block(this); return this }a

slide-90
SLIDE 90

with / apply let / also

public inline fun <T> T.also( block: (T) -> Unit ): T { block(this); return this }a

slide-91
SLIDE 91

with / apply let / also

public inline fun <T> T.also( block: (T) -> Unit ): T { block(this); return this }a Plain lambda

slide-92
SLIDE 92

with / apply let / also

public inline fun <T> T.also( block: (T) -> Unit ): T { block(this); return this }a

“Oh and also…”

slide-93
SLIDE 93

with / apply let / also

foo.bar() .also { } .baz()

“Oh and also…”

slide-94
SLIDE 94

???

slide-95
SLIDE 95

Are you calling repeated functions on an object? Do you need to return the object? Do you need to return the object? No Yes Yes No Apply With No Yes Also Let

slide-96
SLIDE 96

need caller to be returned don’t need caller returned need receiver apply with don’t need receiver also let

slide-97
SLIDE 97
  • 1. Things return values you don’t

always need to use

  • 2. You can call non-receiver functions

inside lambdas with receivers

slide-98
SLIDE 98

val idk = with(foo) { bar() baz() }

slide-99
SLIDE 99

val idk: Baz = with(foo) { bar() baz() }

slide-100
SLIDE 100

val idk: Baz = with(foo) { bar() createBaz() }

slide-101
SLIDE 101

With: Logically grouped calls on an object Apply: Initialization or configuration Let: Nulls + conversions of single objects Also: Ancillary/Side effect-y code in chains

slide-102
SLIDE 102

With: Logically grouped calls on an object Apply: Initialization or configuration Let: Nulls + conversions of single objects Also: Ancillary/Side effect-y code in chains Run: ???

slide-103
SLIDE 103

run

public inline fun <R> run( block: () -> R ): R = block() public inline fun <T, R> T.run( block: T.() -> R ): R = block()

slide-104
SLIDE 104

run

public inline fun <R> run( block: () -> R ): R = block()

slide-105
SLIDE 105

run

public inline fun <R> run( block: () -> R ): R = block() No arg block

  • f code

Return value

slide-106
SLIDE 106

run

public inline fun <R> run( block: () -> R ): R = block() fun myFun(user: User) { val foo = Foo() run { foo.baz() foo.bar() } }

slide-107
SLIDE 107

run

public inline fun <R> run( block: () -> R ): R = block() fun myFun(user: User) { val foo = Foo() { foo.baz() foo.bar() }() }

🤕

slide-108
SLIDE 108

run

public inline fun <R> run( block: () -> R ): R = block() fun myFun(user: User) { val foo = Foo() { foo.baz() foo.bar() }() }

slide-109
SLIDE 109

run

public inline fun <R> run( block: () -> R ): R = block() fun myFun(user: User) { val foo = Foo() foo.baz() foo.bar() }

slide-110
SLIDE 110

fun myFun(user: User) { val foo = Foo() val result = run { foo.baz() foo.bar() } }

run

public inline fun <R> run( block: () -> R ): R = block()

slide-111
SLIDE 111

fun myFun(user: User) { val foo = Foo() val result = { foo.baz() foo.bar() }() }

run

public inline fun <R> run( block: () -> R ): R = block()

slide-112
SLIDE 112

val repo = currentRepo ?: run { initializeRepo() }

run

public inline fun <R> run( block: () -> R ): R = block()

slide-113
SLIDE 113

run

public inline fun <R> run( block: () -> R ): R = block() public inline fun <T, R> T.run( block: T.() -> R ): R = block()

slide-114
SLIDE 114

run

public inline fun <T, R> T.run( block: T.() -> R ): R = block()

slide-115
SLIDE 115

run

public inline fun <T, R> T.run( block: T.() -> R ): R = block() public inline fun <T, R> with( receiver: T, block: T.() -> R ): R = receiver.block()

slide-116
SLIDE 116

run

with(db) {

  • pen()

commit() close() } vs. db?.run {

  • pen()

commit() close() } Can insert ?. Don’t want return value

slide-117
SLIDE 117

run

with(db) {

  • pen()

commit() close() } vs. db?.run {

  • pen()

commit() close() } Can insert ?. Don’t want return value if (db != null) { //lambda with receiver }

slide-118
SLIDE 118

run

with(db) {

  • pen()

commit() close() } vs. db.run {

  • pen()

commit() close() } Can insert ?. Don’t want return value

¯\_()_/¯

if (db != null) { //lambda with receiver }

slide-119
SLIDE 119

With: Logically grouped calls on an object Apply: Initialization or configuration Let: Nulls + conversions of single objects Also: Ancillary/Side effect-y code in chains Run: With + nullability (?: and ?.)

slide-120
SLIDE 120

With: Logically grouped calls on an object Apply: Initialization or configuration Let: Nulls (and maybe conversions of single objects) Also: Ancillary/Side effect-y code in chains Run: With + nullability (?: and ?.)

(Maybe…?)

slide-121
SLIDE 121

Array<Int>

slide-122
SLIDE 122

Array<Int> IntArray

slide-123
SLIDE 123

Array<Int> IntArray ¯\_()_/¯

slide-124
SLIDE 124

Non null types in Kotlin tend to be compiled to Java’s primitives

slide-125
SLIDE 125

List<Int> (Kotlin) List<Integer> (Java)

slide-126
SLIDE 126

Array<Int> (Kotlin) Integer[]

slide-127
SLIDE 127

Array<Int> (Kotlin) Integer[] Object[] result$iv = new Integer[size$iv];

slide-128
SLIDE 128

Array<Int> (Kotlin) Integer[] int[] ?

slide-129
SLIDE 129

Array<Int> (Kotlin) Integer[] int[] IntArray

slide-130
SLIDE 130

Array<Int> (Kotlin) Integer[] int[] IntArray int[] result$iv = new int[size$iv];

slide-131
SLIDE 131

Array<Int> Integer[] int[] IntArray

slide-132
SLIDE 132

Array<Int> Integer[] int[] IntArray

Performance

slide-133
SLIDE 133

Array<Int> Integer[] int[] IntArray

Performance

slide-134
SLIDE 134

Array<Int> Integer[] int[] IntArray

Performance

slide-135
SLIDE 135

Delegates.notNull vs lateinit

slide-136
SLIDE 136

Lateinit Delegates.notNull

must be a variable -> can be reassigned can’t be a “primitive” can be a “primitive” can be val or var

slide-137
SLIDE 137

Lateinit Delegates.notNull

must be a variable -> can be reassigned can’t be a “primitive” can be a “primitive” can be val or var

Basically no restrictions

slide-138
SLIDE 138

Lateinit Delegates.notNull

must be a variable -> can be reassigned can’t be a “primitive” can be a “primitive” can be val or var

Forcing functions: val(?) or primitive

slide-139
SLIDE 139

Delegates.notNull

slide-140
SLIDE 140

Delegates.notNull

slide-141
SLIDE 141

Delegates.notNull

private class NotNullVar<T: Any>() : ReadWriteProperty<Any?, T> { private var value: T? = null public override fun getValue(...): T { return value ?: throw IllegalStateException( "Property ${property.name} should be initialized before get.") } public override fun setValue(..., value: T) { this.value = value } }

slide-142
SLIDE 142

private class NotNullVar<T: Any>() : ReadWriteProperty<Any?, T> { private var value: T? = null public override fun getValue(...): T { return value ?: throw IllegalStateException( "Property ${property.name} should be initialized before get.") } public override fun setValue(..., value: T) { this.value = value } }

Delegates.notNull

slide-143
SLIDE 143

private class NotNullVar<T: Any>() : ReadWriteProperty<Any?, T> { private var value: T? = null public override fun getValue(...): T { return value ?: throw IllegalStateException( “Property ${property.name} should be initialized before get.") } public override fun setValue(..., value: T) { this.value = value } }

Delegates.notNull

slide-144
SLIDE 144

private class NotNullVar<T: Any>() : ReadWriteProperty<Any?, T> { private var value: T? = null public override fun getValue(...): T { return value ?: throw IllegalStateException( Property ${property.name} should be initialized before get.") } public override fun setValue(..., value: T) { this.value = value } }

Delegates.notNull

slide-145
SLIDE 145

Delegates.notNull

slide-146
SLIDE 146

Delegates.notNull?

slide-147
SLIDE 147

lateinit

slide-148
SLIDE 148

late initialized

slide-149
SLIDE 149

late initialized

class User { val firstName: String = "Christina" val lastName: String init { lastName = "Lee" } }

slide-150
SLIDE 150

late initialized

slide-151
SLIDE 151

late initialized

class TestActivity : AppCompatActivity() { lateinit var button: Button

  • verride fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState) setContentView(R.layout.activity_test) button = findViewById(R.id.button) as Button } }

slide-152
SLIDE 152

???

slide-153
SLIDE 153

late initialized:

when you can

slide-154
SLIDE 154

late initialized:

when you can*

slide-155
SLIDE 155

Inline fun vs Custom getter

slide-156
SLIDE 156

class User(val firstName: String, val lastName: String, var height: Inch) { val isTall get() = height > SixFeet }a

slide-157
SLIDE 157

class User(val firstName: String, val lastName: String, var height: Inch) { fun isTall(): Boolean = height > SixFeet }a

slide-158
SLIDE 158

val me = User(firstName = "Christina", lastName = "Lee", height = 68)

slide-159
SLIDE 159

val me = User(firstName = "Christina", lastName = "Lee", height = 68) vs me.isTall me.isTall()

slide-160
SLIDE 160

val me = User(firstName = "Christina", lastName = "Lee", height = 68) me.isTall me.isTall()

?

slide-161
SLIDE 161

me.isTall me.isTall()

?

public final isTall2()Z L0 LINENUMBER 18 L0 ALOAD 0 GETFIELD User.height : I BIPUSH 72 IF_ICMPLE L1 ICONST_1 GOTO L2 L1 ICONST_0 L2 IRETURN L3 LOCALVARIABLE this User; L0 L3 0 MAXSTACK = 2 MAXLOCALS = 1 public final isTall1()Z L0 LINENUMBER 16 L0 ALOAD 0 GETFIELD User.height : I BIPUSH 72 IF_ICMPLE L1 ICONST_1 GOTO L2 L1 ICONST_0 L2 IRETURN L3 LOCALVARIABLE this User; L0 L3 0 MAXSTACK = 2 MAXLOCALS = 1
slide-162
SLIDE 162

me.isTall me.isTall()

?

public final isTall2()Z L0 LINENUMBER 18 L0 ALOAD 0 GETFIELD User.height : I BIPUSH 72 IF_ICMPLE L1 ICONST_1 GOTO L2 L1 ICONST_0 L2 IRETURN L3 LOCALVARIABLE this User; L0 L3 0 MAXSTACK = 2 MAXLOCALS = 1 public final isTall1()Z L0 LINENUMBER 16 L0 ALOAD 0 GETFIELD User.height : I BIPUSH 72 IF_ICMPLE L1 ICONST_1 GOTO L2 L1 ICONST_0 L2 IRETURN L3 LOCALVARIABLE this User; L0 L3 0 MAXSTACK = 2 MAXLOCALS = 1
slide-163
SLIDE 163

me.isTall me.isTall()

?

public final isTall2()Z L0 LINENUMBER 18 L0 ALOAD 0 GETFIELD User.height : I BIPUSH 72 IF_ICMPLE L1 ICONST_1 GOTO L2 L1 ICONST_0 L2 IRETURN L3 LOCALVARIABLE this User; L0 L3 0 MAXSTACK = 2 MAXLOCALS = 1

There is no difference in implementation or performance; they only differ in readability.

  • Kotlin in Action, pg 26
public final isTall1()Z L0 LINENUMBER 16 L0 ALOAD 0 GETFIELD User.height : I BIPUSH 72 IF_ICMPLE L1 ICONST_1 GOTO L2 L1 ICONST_0 L2 IRETURN L3 LOCALVARIABLE this User; L0 L3 0 MAXSTACK = 2 MAXLOCALS = 1
slide-164
SLIDE 164

me.isTall me.isTall()

?

slide-165
SLIDE 165

me.isTall me.isTall()

?

me.firstName me.lastName me.age

slide-166
SLIDE 166

me.isTall me.isTall()

?

me.firstName me.lastName me.age me.getFriends() me.clear() me.clone()

slide-167
SLIDE 167

me.isTall me.isTall()

?

me.firstName me.lastName me.age me.getFriends() me.clear() me.clone()

data

slide-168
SLIDE 168

me.isTall me.isTall()

?

me.firstName me.lastName me.age me.getFriends() me.clear() me.clone()

data actions

slide-169
SLIDE 169

me.isTall me.isTall()

?

data actions attribute of the type

  • n the order of a field access

no overt side effects computationally expensive conversions or copies return value changes each time

slide-170
SLIDE 170

me.isTall me.isTall()

?

slide-171
SLIDE 171

me.isTall me.isTall()

slide-172
SLIDE 172

Map/Filter + Sequence

slide-173
SLIDE 173 * Elements in the set returned are sorted according to the given [comparator]. */ @kotlin.jvm.JvmVersion public fun <T> Array<out T>.toSortedSet(comparator: Comparator<in T>): SortedSet<T> { return toCollection(TreeSet<T>(comparator)) } /** * Returns a single list of all elements yielded from results of [transform] function being invoked on each element of original array. */ public inline fun <T, R> Array<out T>.flatMap(transform: (T) -> Iterable<R>): List<R> { return flatMapTo(ArrayList<R>(), transform) } /** * Appends all elements yielded from results of [transform] function being invoked on each element of original array, to the given [destination]. */ public inline fun <T, R, C : MutableCollection<in R>> Array<out T>.flatMapTo(destination: C, transform: (T) -> Iterable<R>): C { for (element in this) { val list = transform(element) destination.addAll(list) } return destination } /** * Groups elements of the original array by the key returned by the given [keySelector] function * applied to each element and returns a map where each group key is associated with a list of corresponding elements. * * The returned map preserves the entry iteration order of the keys produced from the original array. * * @sample samples.collections.Collections.Transformations.groupBy */ public inline fun <T, K> Array<out T>.groupBy(keySelector: (T) -> K): Map<K, List<T>> { return groupByTo(LinkedHashMap<K, MutableList<T>>(), keySelector) } /** * Groups values returned by the [valueTransform] function applied to each element of the original array * by the key returned by the given [keySelector] function applied to the element * and puts to the [destination] map each group key associated with a list of corresponding values. * * @return The [destination] map. * * @sample samples.collections.Collections.Transformations.groupByKeysAndValues */ public inline fun <T, K, V, M : MutableMap<in K, MutableList<V>>> Array<out T>.groupByTo(destination: M, keySelector: (T) -> K, valueTransform: (T) -> V): M { for (element in this) { val key = keySelector(element) val list = destination.getOrPut(key) { ArrayList<V>() } list.add(valueTransform(element)) }
slide-174
SLIDE 174

val arr = arrayOf("1", "2", "3", “4”) val numGreaterThanTwo = arr.map { Integer.valueOf(it) } .filter { it > 2 } .count()

slide-175
SLIDE 175 Object[] elements$iv = new String[]{"1", "2", "3", “4"}; Object[] $receiver$iv = (Object[])elements$iv; Object[] $receiver$iv$iv = $receiver$iv; Collection destination$iv$iv = (Collection)(new ArrayList($receiver$iv.length)); Object element$iv$iv; for(int var6 = 0; var6 < $receiver$iv$iv.length; ++var6) { element$iv$iv = $receiver$iv$iv[var6]; String it = (String)element$iv$iv; Integer var13 = Integer.valueOf(it); destination$iv$iv.add(var13); }a Iterable $receiver$iv = (Iterable)((List)destination$iv$iv); destination$iv$iv = (Collection)(new ArrayList()); Iterator var17 = $receiver$iv.iterator(); while(var17.hasNext()) { element$iv$iv = var17.next(); Integer it = (Integer)element$iv$iv; if(Intrinsics.compare(it.intValue(), 2) > 0) { destination$iv$iv.add(element$iv$iv); }b }c Collection var16 = (Collection)((List)destination$iv$iv); int numbersGreaterThanTwo = var16.size();
slide-176
SLIDE 176 Object[] elements$iv = new String[]{"1", "2", "3", “4"}; Object[] $receiver$iv = (Object[])elements$iv; Object[] $receiver$iv$iv = $receiver$iv; Collection destination$iv$iv = (Collection)(new ArrayList($receiver$iv.length)); Object element$iv$iv; for(int var6 = 0; var6 < $receiver$iv$iv.length; ++var6) { element$iv$iv = $receiver$iv$iv[var6]; String it = (String)element$iv$iv; Integer var13 = Integer.valueOf(it); destination$iv$iv.add(var13); }a Iterable $receiver$iv = (Iterable)((List)destination$iv$iv); destination$iv$iv = (Collection)(new ArrayList()); Iterator var17 = $receiver$iv.iterator(); while(var17.hasNext()) { element$iv$iv = var17.next(); Integer it = (Integer)element$iv$iv; if(Intrinsics.compare(it.intValue(), 2) > 0) { destination$iv$iv.add(element$iv$iv); }b }c Collection var16 = (Collection)((List)destination$iv$iv); int numbersGreaterThanTwo = var16.size();
slide-177
SLIDE 177 Object[] elements$iv = new String[]{“1", "2", "3", “4"}; Collection destination$iv$iv = (Collection)(new ArrayList($receiver$iv.length)); Object element$iv$iv; for(int var6 = 0; var6 < $receiver$iv$iv.length; ++var6) { Integer var13 = Integer.valueOf(it); }a destination$iv$iv = (Collection)(new ArrayList()); while(var17.hasNext()) { if(Intrinsics.compare(it.intValue(), 2) > 0) { destination$iv$iv.add(element$iv$iv); }b }c int numbersGreaterThanTwo = var16.size();
slide-178
SLIDE 178 Collection destination$iv$iv = (Collection)(new ArrayList($receiver$iv.length)); Object element$iv$iv; for(int var6 = 0; var6 < $receiver$iv$iv.length; ++var6) { Integer var13 = Integer.valueOf(it); } destination$iv$iv = (Collection)(new ArrayList()); while(var17.hasNext()) { if(Intrinsics.compare(it.intValue(), 2) > 0) { destination$iv$iv.add(element$iv$iv); } }
slide-179
SLIDE 179 Collection destination$iv$iv = (Collection)(new ArrayList($receiver$iv.length)); Object element$iv$iv; for(int var6 = 0; var6 < $receiver$iv$iv.length; ++var6) { Integer var13 = Integer.valueOf(it); } destination$iv$iv = (Collection)(new ArrayList()); while(var17.hasNext()) { if(Intrinsics.compare(it.intValue(), 2) > 0) { destination$iv$iv.add(element$iv$iv); } }

Intermediate Collections

slide-180
SLIDE 180 Collection destination$iv$iv = (Collection)(new ArrayList($receiver$iv.length)); Object element$iv$iv; for(int var6 = 0; var6 < $receiver$iv$iv.length; ++var6) { Integer var13 = Integer.valueOf(it); } destination$iv$iv = (Collection)(new ArrayList()); while(var17.hasNext()) { if(Intrinsics.compare(it.intValue(), 2) > 0) { destination$iv$iv.add(element$iv$iv); } }

Intermediate Collections

large collections

slide-181
SLIDE 181

val arr = arrayOf(“1", "2", "3", “4") val numGreaterThanTwo = arr.asSequence() .map { Integer.valueOf(it) } .filter { it > 2 } .count()

slide-182
SLIDE 182

arr.asSequence() .map { } .filter { } .count() arr.map { } .filter { } .count() Mapping 1 Filtering 1 Mapping 2 Filtering 2 Mapping 3 Filtering 3 Mapping 4 Filtering 4 Mapping 1 Mapping 2 Mapping 3 Mapping 4 Filtering 1 Filtering 2 Filtering 3 Filtering 4

slide-183
SLIDE 183

arr.asSequence() .map { } .filter { } arr.map { } .filter { } Mapping 1 Mapping 2 Mapping 3 Mapping 4 Filtering 1 Filtering 2 Filtering 3 Filtering 4

slide-184
SLIDE 184

arr.asSequence() .map { } .filter { } arr.map { } .filter { } Mapping 1 Mapping 2 Mapping 3 Mapping 4 Filtering 1 Filtering 2 Filtering 3 Filtering 4

Requires a terminal operation

slide-185
SLIDE 185

internal class TransformingSequence<T, R> constructor(private val sequence: Sequence<T>, private val transformer: (T) -> R) : Sequence<R> {

  • verride fun iterator(): Iterator<R> = object : Iterator<R> {

val iterator = sequence.iterator()

  • verride fun next(): R {

return transformer(iterator.next()) }b

  • verride fun hasNext(): Boolean {

return iterator.hasNext() } } // . . . }

slide-186
SLIDE 186
  • verride fun next(): R {

return transformer(iterator.next()) }b

slide-187
SLIDE 187

for (item in this) destination.add(transform(item)) return destination

slide-188
SLIDE 188

Performance

slide-189
SLIDE 189

Wholistic Performance

slide-190
SLIDE 190

Performance

Intermediate Collections Object allocations + Capturing references

slide-191
SLIDE 191

Use asSequence if you have a compelling large data set

  • r have profiled perf issues.

Rule of thumb:

slide-192
SLIDE 192
slide-193
SLIDE 193

The End

slide-194
SLIDE 194

Christina Lee

@RunChristinaRun

👌