Effectivekotlin 180828123804
Effectivekotlin 180828123804
https://www.slideshare.net/compscicenter/kotlin-2016-mixing-java-and-kotlin
Nothing cannot be Instantiated
// Runtime exception
val myNullPointerException: String = myPlatformString.toUpperCase()
Platform Types
// Java Declaration
public class SomeClass {
public static String getNullString() {
return null;
}
}
// Compiler error!
val myUnsafeCall: String = myPlatformString.toUpperCase()
Platform Types
// Java Declaration
public class SomeClass {
public static String getNullString() {
return null;
}
}
interface PlaylistRepository {
fun addSongToPlaylist(songId: SongId, playlistId: PlaylistId)
}
Compile time safety
data class SongId(val id: Long)
data class PlaylistId(val id: Long)
interface PlaylistRepository {
fun addSongToPlaylist(songId: SongId, playlistId: PlaylistId)
}
playlistRepository.addSongToPlaylist(song.typedId, playlist.typedId)
Custom type system: Sealed Classes
Custom type system: Sealed Classes
sealed class SongId
data class ValidSongId(val id: Long) : SongId()
object InvalidSongId : SongId()
return ViewHolder(v)
}
When statements as expressions
// Can be used to assign variables
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val layoutRes = when (ViewTypeEnum.values()[viewType]) {
VIEW_TYPE_1 -> R.layout.list_item_type1
VIEW_TYPE_2 -> R.layout.list_item_type2
}
return ViewHolder(v)
}
// RecyclerView view types
enum class ViewTypeEnum {
TYPE_1,
TYPE_2,
TYPE_3 // Added view type
}
When statements as expressions
// Can be used to assign variables
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val layoutRes = when (ViewTypeEnum.values()[viewType]) {
VIEW_TYPE_1 -> R.layout.list_item_type1
VIEW_TYPE_2 -> R.layout.list_item_type2
}
return ViewHolder(v)
}
When statements as expressions
// Can be used to assign variables
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val layoutRes = when (ViewTypeEnum.values()[viewType]) {
VIEW_TYPE_1 -> R.layout.list_item_type1
VIEW_TYPE_2 -> R.layout.list_item_type2
}
return ViewHolder(v)
}
When statements as expressions
// Not an expression
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
when (ViewTypeEnum.values()[position]) {
VIEW_TYPE_1 -> bindFirstViewType(holder, position)
VIEW_TYPE_2 -> bindSecondViewType(holder, position)
}
}
When statements as expressions
// Not an expression
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
when (ViewTypeEnum.values()[position]) {
VIEW_TYPE_1 -> bindFirstViewType(holder, position)
VIEW_TYPE_2 -> bindSecondViewType(holder, position)
}
}
// Expression
override fun onBindViewHolder(holder: ViewHolder, position: Int) =
when (ViewTypeEnum.values()[position]) {
VIEW_TYPE_1 -> bindFirstViewType(holder, position)
VIEW_TYPE_2 -> bindSecondViewType(holder, position)
}
Think Functionally
Lambda Expression Syntax
}
}
Top Level and Local Functions
class SomeClass {
fun someMemberFunction() {
}
}
Top Level and Local Functions
class SomeClass {
fun someMemberFunction() {
someLocalFunction()
}
}
Top Level and Local Functions
class SomeClass {
fun someMemberFunction() {
someLocalFunction()
}
}
fun someTopLevelFunction() {
// some implementation
}
Top Level and Local Functions
class SomeClass {
fun someMemberFunction() {
someLocalFunction()
someTopLevelFunction()
}
}
fun someTopLevelFunction() {
// some implementation
}
view.setOnClickListener { doSomething() }
Higher Order Functions are functions
that take and/or return other functions
val users: List<User> = listOf(User("Andrew"), User("Yousuf"))
val users: List<User> = listOf(User("Andrew"), User("Yousuf"))
}
Instantiating a Try Instance
inline operator fun <A> invoke(func: () -> A): Try<A> =
try {
Success(func())
Failure(e)
}
Instantiating a Try Instance
inline operator fun <A> invoke(func: () -> A): Try<A> =
try {
Success(func())
Failure(e)
}
Instantiating a Try Instance
inline operator fun <A> invoke(func: () -> A): Try<A> =
try {
Success(func())
Failure(e)
}
Kotlin Doesn’t have Checked Exceptions
@Throws(NotImplementedError::class)
TODO("not implemented")
}
Kotlin Doesn’t have Checked Exceptions
@Throws(NotImplementedError::class)
TODO("not implemented")
}
Try to the Rescue
@Throws(NotImplementedError::class)
TODO("not implemented")
}
Semantic Function Signature
@Throws(NotImplementedError::class)
TODO("not implemented")
}
Take Control of Your API
Take Control of Your API
// Default Java way
TestSubscriber<SomePojo> testSubscriber = new TestSubscriber<SomePojo>();
Take Control of Your API
// Default Java way
TestSubscriber<SomePojo> testSubscriber = new TestSubscriber<SomePojo>();
// https://github.com/ReactiveX/RxKotlin
operator fun CompositeDisposable.plusAssign(disposable: Disposable) {
add(disposable)
}
Take Control of Your API: Operator Overloading
// https://github.com/ReactiveX/RxKotlin
operator fun CompositeDisposable.plusAssign(disposable: Disposable) {
add(disposable)
}
Take Control of Your API: Operator Overloading
// https://github.com/ReactiveX/RxKotlin
operator fun CompositeDisposable.plusAssign(disposable: Disposable) {
add(disposable)
}
// Allows us to do
compositeDisposable += observable.subscribe()
Take Control of Your API: Delegated Properties
Take Control of Your API: Delegated Properties
- Kotlin Documentation
Delegated Properties
private const val KEY_TITLE = "title"
private const val KEY_MESSAGE = "message"
return fragment
}
Delegated Properties
private const val KEY_TITLE = "title"
private const val KEY_MESSAGE = "message"
return fragment
}
Delegated Properties
private const val KEY_TITLE = "title"
private const val KEY_MESSAGE = "message"
return fragment
}
Delegated Properties
return fragment
}
Delegated Properties: Bundle Delegates
var Bundle.dialogTitle: String? by StringBundleDelegate()
var Bundle.dialogMessage: String? by StringBundleDelegate()
return fragment
}
Delegated Properties: Bundle Delegates
return fragment
}
Bundle Delegates: The Byte Code
Mac: ⌘ + ⇧ + A Windows: CTRL+SHIFT+A
Bundle Delegates: The Byte Code
Bundle Delegates: The Byte Code
Built-in Delegates
● Lazy
● Observable
● Vetoable
Built-in Delegates: Lazy
val lazyValue: String by lazy {
println("Computed!")
"Hello"
}
Built-in Delegates: Lazy
val lazyValue: String by lazy {
println("Computed!")
"Hello"
}
Returns
Receiver
Returns
Last
Expression
https://hackernoon.com/kotlin-a-deeper-look-8569d4da36f
Kotlin Standard Library Extension Functions
Scoped to Receiver
https://hackernoon.com/kotlin-a-deeper-look-8569d4da36f
Kotlin Standard Library Extension Functions
Receiver as Parameter
https://hackernoon.com/kotlin-a-deeper-look-8569d4da36f
Kotlin Standard Library Extension Functions
Returns
Receiver
https://hackernoon.com/kotlin-a-deeper-look-8569d4da36f
Kotlin Standard Library Extension Functions
Returns
Last
Expression
https://hackernoon.com/kotlin-a-deeper-look-8569d4da36f
Let
// receiver as parameter
// returns last expression
val someComponent: SomeDaggerComponent =
application
.let { it as MyApplication }
.someDaggerComponent
Let
// receiver as parameter
// returns last expression
val someComponent: SomeDaggerComponent =
application
.let { it as MyApplication }
.someDaggerComponent
Let
// receiver as parameter
// returns last expression
val someComponent: SomeDaggerComponent =
application
.let { it as MyApplication }
.someDaggerComponent
Let
// receiver as parameter
// returns last expression
val someComponent: SomeDaggerComponent =
application
.let { it as MyApplication }
.someDaggerComponent
Apply
// scoped to receiver
// returns receiver
val myBundle: Bundle =
Bundle().apply {
// this is Bundle
putString(MY_STRING_KEY, "myString")
putBoolean(MY_BOOLEAN_KEY, true)
}
Apply
// scoped to receiver
// returns receiver
val myBundle: Bundle =
Bundle().apply {
// this is Bundle
putString(MY_STRING_KEY, "myString")
putBoolean(MY_BOOLEAN_KEY, true)
}
Apply
// scoped to receiver
// returns receiver
val myBundle: Bundle =
Bundle().apply {
// this is Bundle
putString(MY_STRING_KEY, "myString")
putBoolean(MY_BOOLEAN_KEY, true)
}
Also
// receiver as parameter
// returns receiver
val myUser: User = User("Yousuf")
.also { user ->
Log.d("SomeTag", user.name)
}
Also
// receiver as parameter
// returns receiver
val myUser: User = User("Yousuf")
.also { user ->
Log.d("SomeTag", user.name)
}
Also
// receiver as parameter
// returns receiver
val myUser: User = User("Yousuf")
.also { user ->
Log.d("SomeTag", user.name)
}
Also
// receiver as parameter
// returns receiver
val myUser: User = User("Yousuf")
.also { user ->
Log.d("SomeTag", user.name)
}
Run
// scoped to receiver
// returns last expression
val myNullableString: String? = null
myNullableString
?.also { nonNullString ->
doSomethingForNonNullString(nonNullString)
}
?: run { doSomethingForNullString() }
Run
// scoped to receiver
// returns last expression
val myNullableString: String? = null
myNullableString
?.also { nonNullString ->
doSomethingForNonNullString(nonNullString)
}
?: run { doSomethingForNullString() }
Run
// scoped to receiver
// returns last expression
val myNullableString: String? = null
myNullableString
?.also { nonNullString ->
doSomethingForNonNullString(nonNullString)
}
?: run { doSomethingForNullString() }
Run
// scoped to receiver
// returns last expression
val myNullableString: String? = null
myNullableString
?.also { nonNullString ->
doSomethingForNonNullString(nonNullString)
}
?: run { doSomethingForNullString() }
Run
// scoped to receiver
// returns last expression
val myNullableString: String? = null
myNullableString
?.also { nonNullString ->
doSomethingForNonNullString(nonNullString)
}
?: run { doSomethingForNullString() }
Run
// scoped to receiver
// returns last expression
val myNullableString: String? = null
myNullableString
?.also { nonNullString ->
doSomethingForNonNullString(nonNullString)
}
?: run { doSomethingForNullString() }
1. Leverage Kotlin’s Type System
2. Think Functionally
3. Take Control of Your API
4. Leverage the Standard Library
1. Leverage Kotlin’s Type System
2. Think Functionally
3. Take Control of Your API
4. Leverage the Standard Library
1. Leverage Kotlin’s Type System
2. Think Functionally
3. Take Control of Your API
4. Leverage the Standard Library
1. Leverage Kotlin’s Type System
2. Think Functionally
3. Take Control of Your API
4. Leverage the Standard Library
Thank You