项目作者: faruktoptas

项目描述 :
Learn kotlin by examples
高级语言:
项目地址: git://github.com/faruktoptas/kotlin-snippets.git
创建时间: 2018-08-15T06:47:52Z
项目社区:https://github.com/faruktoptas/kotlin-snippets

开源协议:

下载


kotlin-snippets

Null Safety

  1. var b: String? = "abc"
  2. b = null // ok
  3. print(b)
  4. var b: String? = null
  5. if (b != null && b.isNotEmpty()) {
  6. print(b)
  7. }
  8. if (b?.isNotEmpty() == true){
  9. print(b)
  10. }
  11. bob?.department?.head?.name
  12. val listWithNulls: List<String?> = listOf("Kotlin", null)
  13. for (item in listWithNulls) {
  14. item?.let { println(it) } // prints A and ignores null
  15. }
  16. //elvis
  17. val l = b?.length ?: -1
  18. //early return
  19. myVar ?: return
  20. //for NPE-lovers
  21. val l = b!!.length

String templates

  1. // simple name in template:
  2. var a = 1
  3. val s1 = "a is $a"
  4. a = 2
  5. // arbitrary expression in template:
  6. val s2 = "${s1.replace("is", "was")}, but now is $a"
  7. `

Using if as an expression:

  1. fun maxOf(a: Int, b: Int) = if (a > b) a else b

Using type checks and automatic casts

  1. if (obj is String) {
  2. // `obj` is automatically cast to `String` in this branch
  3. return obj.length
  4. }

Using a for loop

  1. val items = listOf("apple", "banana", "kiwifruit")
  2. for (item in items) {
  3. println(item)
  4. }

Using when expression

  1. fun describe(obj: Any): String =
  2. when (obj) {
  3. 1 -> "One"
  4. "Hello" -> "Greeting"
  5. is Long -> "Long"
  6. !is String -> "Not a string"
  7. else -> "Unknown"
  8. }

Ranges

  1. for (x in 1..5) {
  2. print(x)
  3. }

Collections

  1. when {
  2. "orange" in items -> println("juicy")
  3. "apple" in items -> println("apple is fine too")
  4. }

Prefer using when if there are three or more options.

Lambdas

  1. val fruits = listOf("banana", "avocado", "apple", "kiwifruit")
  2. fruits
  3. .filter { it.startsWith("a") }
  4. .sortedBy { it }
  5. .map { it.toUpperCase() }
  6. .forEach { println(it) }
  7. val numbers = listOf(1, 6, 2, 7, 8, 9)
  8. numbers.find { it > 3 } // 6
  9. numbers.findLast{it > 3} // 9
  10. numbers.any{it > 8} // true

Default function values

  1. fun foo(a: Int = 0, b: String = "") { ... }

Lists

  1. val list = listOf("a", "b", "c")
  2. val mutableList = arrayListOf("a", "b", "c")

Read-only map

  1. val map = mapOf("a" to 1, "b" to 2, "c" to 3)

Lazy property

  1. val preference: String by lazy {
  2. sharedPreferences.getString(PREFERENCE_KEY)
  3. }

Constructors

  1. class Person(firstName: String) { ... }
  2. class Customer public @Inject constructor(name: String) { ... }
  3. // secondary constructor
  4. class Person {
  5. constructor(parent: Person) {
  6. parent.children.add(this)
  7. }
  8. }
  9. class Constructors {
  10. init {
  11. println("Init block") // first
  12. }
  13. constructor(i: Int) {
  14. println("Constructor") // second
  15. }
  16. }

Getter setter

  1. var email:String = ""
  2. set(value) {
  3. if (value.isValidEmail()){
  4. field = value
  5. }
  6. }

Late initialization

  1. class MyActivity : AppCompatActivity() {
  2. // non-null, but not initalized
  3. lateinit var recyclerView: RecyclerView
  4. override fun onCreate(savedInstanceState: Bundle?) {
  5. // …
  6. // initialized here
  7. recyclerView = findViewById(R.id.recycler_view)
  8. }
  9. }

Inline functions

Calls will be replaced with the function body.

  1. // define an inline function that takes a function argument
  2. inline fun onlyIf(check: Boolean, operation: () -> Unit) {
  3. if (check) {
  4. operation()
  5. }
  6. }
  7. // call it like this
  8. onlyIf(shouldPrint) { // call: pass operation as a lambda
  9. println(“Hello, Kotlin”)
  10. }
  11. // which will be inlined to this
  12. if (shouldPrint) { // execution: no need to create lambda
  13. println(“Hello, Kotlin”)
  14. }

Extensions

  1. fun View.hide() {
  2. visibility = View.GONE
  3. }
  4. textView.hide()
  5. fun MutableList<Int>.swap(index1: Int, index2: Int) {
  6. val tmp = this[index1] // 'this' corresponds to the list
  7. this[index1] = this[index2]
  8. this[index2] = tmp
  9. }
  10. val l = mutableListOf(1, 2, 3)
  11. l.swap(0, 2) // 'this' inside 'swap()' will hold the value of 'l'
  12. fun Int?.orZero() = this ?: 0
  13. val myInt:Int? = null
  14. println("${myInt.orZero()}") // will print 0

Data classes

  1. data class User(val name: String = "", val age: Int = 0)
  2. data class Person(val name: String) {
  3. var age: Int = 0 // excluded
  4. }
  5. //destructing
  6. val jane = User("Jane", 35)
  7. val (name, age) = jane
  8. println("$name, $age years of age") // prints "Jane, 35 years of age"

Sealed classes

  1. sealed class NetworkResult
  2. data class Success(val result: String): NetworkResult()
  3. data class Failure(val error: Error): NetworkResult()
  4. // one observer for success and failure
  5. viewModel.data.observe(this, Observer<NetworkResult> { data ->
  6. data ?: return@Observer // skip nulls
  7. when(data) {
  8. is Success -> showResult(data.result) // smart cast to Success
  9. is Failure -> showError(data.error) // smart cast to Failure
  10. }
  11. })
  12. // use Sealed classes as ViewHolders in a RecyclerViewAdapter
  13. override fun onBindViewHolder(
  14. holder: SealedAdapterViewHolder?, position: Int) {
  15. when (holder) { // compiler enforces handling all types
  16. is HeaderHolder -> {
  17. holder.displayHeader(items[position]) // smart cast here
  18. }
  19. is DetailsHolder -> {
  20. holder.displayDetails(items[position]) // smart cast here
  21. }
  22. }
  23. }

Generics

  1. class ApiResponse<T>(t:T){
  2. var value = t
  3. }
  4. val r = ApiResponse<String>("Data")
  5. val r = ApiResponse<User>(User("name",20))

Functions

  1. fun reformat(str: String,
  2. normalizeCase: Boolean = true,
  3. upperCaseFirstLetter: Boolean = true,
  4. divideByCamelHumps: Boolean = false,
  5. wordSeparator: Char = ' ') {
  6. ...
  7. }
  8. reformat(str)
  9. reformat(str, true, true, false, '_')
  10. reformat(str,
  11. normalizeCase = true,
  12. upperCaseFirstLetter = true,
  13. divideByCamelHumps = false,
  14. wordSeparator = '_'
  15. )
  1. fun <T> asList(vararg ts: T): List<T> {
  2. val result = ArrayList<T>()
  3. for (t in ts) // ts is an Array
  4. result.add(t)
  5. return result
  6. }
  7. val list = asList(1, 2, 3)

infix notation

  1. infix fun Int.shl(x: Int): Int { ... }
  2. // calling the function using the infix notation
  3. 1 shl 2
  4. // is the same as
  5. 1.shl(2)

Local functions

  1. fun dfs(graph: Graph) {
  2. fun dfs(current: Vertex, visited: Set<Vertex>) {
  3. if (!visited.add(current)) return
  4. for (v in current.neighbors)
  5. dfs(v, visited)
  6. }
  7. dfs(graph.vertices[0], HashSet())
  8. }

apply, also, run, let

  1. val string = "a"
  2. val result = string.apply {
  3. // this = "a"
  4. // it = not available
  5. 4 // Block return value unused
  6. // result = "a"
  7. }
  8. val string = "a"
  9. val result = string.also {
  10. // this = this@MyClass
  11. // it = "a"
  12. 4 // Block return value unused
  13. // result = "a"
  14. }
  15. val string = "a"
  16. val result = string.run {
  17. // this = "a"
  18. // it = not available
  19. 1 // Block return value
  20. // result = 1
  21. }
  22. val string = "a"
  23. val result = string.let {
  24. // this = this@MyClass
  25. // it = "a"
  26. 2 // Block return value
  27. // result = 2
  28. }

Higher order functions

  1. fun <T> ArrayList<T>.filterOnCondition(condition: (T) -> Boolean): ArrayList<T>{
  2. val result = arrayListOf<T>()
  3. for (item in this){
  4. if (condition(item)){
  5. result.add(item)
  6. }
  7. }
  8. return result
  9. }
  10. ...
  11. fun isMultipleOf (number: Int, multipleOf : Int): Boolean{
  12. return number % multipleOf == 0
  13. }
  14. ...
  15. var list = arrayListOf<Int>()
  16. for (number in 1..10){
  17. list.add(number)
  18. }
  19. var resultList = list.filterOnCondition { isMultipleOf(it, 5) }

Coroutines

  1. GlobalScope.launch {
  2. delay(2000) // Suspend function waits until completed
  3. log("one")
  4. delay(1000)
  5. log("two")
  6. }
  7. log("three")
  8. /*
  9. Output will be
  10. 0ms > three
  11. 2000ms > one
  12. 3000ms > two
  13. */
  1. runBlocking{
  2. val job = GlobalScope.launch {
  3. delay(2000)
  4. log("one")
  5. }
  6. log("two")
  7. job.join() // Job starts here waits until completed
  8. log("three")
  9. }
  10. /*
  11. Output will be
  12. 0ms > two
  13. 2000ms > one
  14. 2000ms > three
  15. */
  1. runBlocking {
  2. log("zero")
  3. launch { // launch block starts but doesn't wait to be completed. Because launch block is not suspend function
  4. delay(200)
  5. log("one")
  6. }
  7. launch {
  8. delay(300)
  9. log("two")
  10. }
  11. coroutineScope { // this block starts but waits for its all inner blocks until complete to process to the next line
  12. launch {
  13. delay(1000)
  14. log("three")
  15. }
  16. delay(500)
  17. log("four")
  18. }
  19. delay(1000)
  20. log("five")
  21. }
  22. /*
  23. Output will be
  24. 15.00.000 > zero
  25. 15.00.200 > one
  26. 15.00.300 > two
  27. 15.00.500 > four
  28. 15.01.000 > three
  29. 15.02.000 > five
  30. */

Simple Presenter-Interactor Retrofit service call

  1. class MyPresenter(private val view: BaseView) {
  2. private val job = Job()
  3. private val dispatcher = Dispatchers.Main
  4. private val uiScope = CoroutineScope(dispatcher + job)
  5. val interactor = MyInteractor()
  6. fun getResult() {
  7. view.showLoading()
  8. uiScope.launch {
  9. val response = interactor.getResult()
  10. response.response?.apply {
  11. view.onGetResult(result)
  12. }
  13. response.error?.apply { view.onError(this) }
  14. view.hideLoading()
  15. }
  16. }
  17. fun onDestroy(){
  18. job.cancel()
  19. }
  20. }
  21. class MyInteractor(private val service: DummyService) {
  22. suspend fun getResult(): ApiResponse<ResultResponse> {
  23. return service.getResult().defer()
  24. }
  25. }

Convert a Callback to suspend fun

  1. fun callWithListener(listener: OnSomethingListener) {
  2. if (condition) {
  3. listener.onSuccess("success")
  4. } else {
  5. listener.onFail(Exception("fail"))
  6. }
  7. }
  8. suspend fun convert2suspend(): String {
  9. return suspendCoroutine { continuation ->
  10. callWithListener(object : OnSomethingListener {
  11. override fun onSuccess(data: String) {
  12. continuation.resume(data)
  13. }
  14. override fun onFail(e: Exception) {
  15. continuation.resumeWithException(e)
  16. }
  17. })
  18. }
  19. }
  20. runBlocking {
  21. try {
  22. val response = convert2suspend()
  23. println("response: $response")
  24. } catch (e: Exception) {
  25. println("failed: $e")
  26. }
  27. }

What’s next?

Kotlin koans

Coroutines

Androidx

Try Kotlin Online

Resources

https://kotlinlang.org/

https://medium.com/google-developers/31daysofkotlin-week-1-recap-fbd5a622ef86

https://medium.com/google-developers/31daysofkotlin-week-2-recap-9eedcd18ef8

https://medium.com/google-developers/31daysofkotlin-week-3-recap-20b20ca9e205

https://medium.com/google-developers/31daysofkotlin-week-4-recap-d820089f8090

https://medium.com/@agrawalsuneet/higher-order-functions-in-kotlin-3d633a86f3d7