-
Kotlin可以有mutable和ready-only的field,同时它的getters和setters方法默认是自动生成的,你也可以自定义。
class User { val id: String = "" //immutable. just getter var name: String = "" //default getter and setter var surName: String = "" //custom getter, default setter get() = surName.toUpperCase() //custom getter declaration var email: String = "" //default getter, customer setter set(value) { // custom setter declaration //"value" custom setter's parameter //"field" = property's backing field; if (isEmailValid()) field = value }
Properties and Fields: Getters, Setters, const, lateinit - Kotlin Programming Languagekotlinlang.org
-
使用data class当你想要保存一些数据的时候,它默认实现了equals,hashcode,toString以及copy
data class User(val name: String, val email: String) class UserListDiffCallback { fun areContentsTheSame(oldPosition: Int, newPosition: Int): Boolean { // use the generated equals method return newList[oldPosition] == oldList[newPosition] } }
-
在Kotlin里,默认的修饰符都是public,但它还是提供了一些其他的修饰符:private,protected,internal
// public by default var isVisible = true // only in the same file private var isHidden = false internal val almostVisible = true class Foo { // public by default var isVisible = true // visible to my subclasses protected val isInheritable = true // only in the same class private val isHidden = true }
Visibility Modifiers - Kotlin Programming Languagekotlinlang.org
-
如果过度重载导致函数的数量急剧增加,我们可以指定Kotlin中参数的default值,还可以通过在call函数时候,指定参数值,增加code的可读性
// parameters with default values class BulletPointSpan(private val bulletRadius: Float = 1.2f, private val gapWidth: Int = 5, private val color: Int = 255) // using only default values val bulletPointSpan = BulletPointSpan() // passing a value to the first argument and using default values for the other two val bulletPointSpan2 = BulletPointSpan(1.6f) // using a named parameter for the last argument and default values for the other two val bulletPointSpan3 = BulletPointSpan(color = 0)
Functions: infix, vararg, tailrec - Kotlin Programming Languagekotlinlang.org
-
密封类用来限制类的继承关系,这意味着密封类的子类数量是固定的。看起来就像是枚举那样,当你想在一个密封类的子类中寻找一个指定的类的时候,你可以事先知道所有的子类。不同之处在于枚举的实例是唯一的,而密封类可以有很多实例,它们可以有不同的状态。
它和Enum class的区别:sealed class子类可以有multi instances,但是enum constant只有一个instance实例,如果需要constant behavior,选择enum,否则选择sealed;sealed类本身是抽象的,不能实例化,可以添加abstract member
sealed class Intention { // 在kotlin1.1之前,必须放到Intention之中 class Refresh: Intention() class LoadMore: Intention() } fun main(args: Array<String>) { val intention: Intention = Intention.LoadMore() // else statement is unnecessary when using sealed class val output = when (intention) { is Intention.Refresh -> "refresh" is Intention.LoadMore -> "loadMore" } println(output) } //另外一种方式定义 sealed class NetworkResult data class Success(val result: String): NetworkResult() data class Failure(val error: String): NetworkResult()
31DaysOfKotlin-series 3
-
Kotlin可以使用lazy来推迟一些开销比较大的初始化,直到真正需要的时候(第一次调用get的时候)才进行初始化,后续继续调用get,则不再执行传入的lambda
val lazyValue: String by lazy { println("computed!") "hello" } fun main(args: Array<String>) { println(lazyValue) println(lazyValue) } // example output: // computed! // hello // hello
简单总结:对于在对ready-only的property(i.e. a val), 它的delegate(by后面的类型)需要提供一个叫getValue的函数,并且两个参数,返回必须是property的类型(String)或者它的子类
- thisRef:必须是property owner或者property owner的supertype(一般是当前property所属的class)
- property:必须是KProperty<*>或者它的supertype(比如lazyValue:String)
对于mutable的propert(a var),它的delegate还需要提供一个setValue,参数除了上面两个,最后一个是new value,必须和property的类型相同或者它的子类
lazy更像一个Single Instance of Variable,是不是和单例有点类似
Delegated Properties - Kotlin Programming Languagekotlinlang.org
-
在Kotlin中non-null的变量必须要马上进行初始化,如果你的程序是稍后(在适当的时候)才给它初始化,就可以通过添加lateinit表示initialize me later!它最终还是null safe的,另外lateinit不能用在primitive type上面。比如在Android开发时,我们的View一般都是在onCreate中进行初始化,或者Dagger2在注入时
@Inject lateinit var myUtil: MyUtil
lazy和lateinit使用场景,它们的使用目的不一样,有时还是要具体场景具体分析:
- 如果是mutable的,使用lateInit
- 如果是只需要初始化一次,其他地方都可以使用
class MyActivity: AppCompatActivity() { lateinit var recyclerView: RecyclerView // non-null, but not initialized override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // .. recyclerView = findViewById(R.id.recycler_view) // initialize here } }
Properties and Fields: Getters, Setters, const, lateinit - Kotlin Programming Languagekotlinlang.org
-
你的函数参数是否有效呢?可以在用之前通过’require’进行检测,如果invalid,则会抛出IllegalArgumentException
fun setName(name: String) { // calling setName("") throws IllegalArgumentException require(name.isNotEmpty()) { "invalid name" } //.. }
-
Inline function,通过在函数前面添加inline修饰符,表明他被调用的时候,在调用它的地方,不仅仅是inline函数自己本身,包括它的lambda参数,都会被替换/inline
// define an inline function that takes a function argument inline fun onlyIf(check: Boolean, operation: () -> Unit) { if (check) { operation() } } // call it like this onlyIf(shouldPrint) { println("Hello, Kt") } //which will be inline to this if (shouldPrint) { // execution: no need to create lambda println("Hello, kt") }
在Kotlin中我们可以使用return来退出一个named function或者anonymous function,但在退出一个lambda时,我们使用label, return是禁止使用的,因为一个lambda can not make the enclosing function return。如果是inline function则可以使用return,表示退出整个函数
fun foo() { ordinaryFunction { return // ERROR: can not make `foo` return here } } // 如果是inline funciton fun foo() { inlineFunction { return // OK: the lambda is inlined } } fun hasZeros(ints: List<Int>): Boolean { ints.forEach { // forEach是inline的 if (it == 0) return true // returns from hasZeros } return false }
Inline Functions and Reified Type Parameters - Kotlin Programming Languagekotlinlang.org
-
在同一project中使用Kotlin和Java,怎样进行调用呢?在编译时默认会将kotlin文件的类名变成“YourFileKt”。可以通过@file:JvmName(“xxx”)来重新进行命名
// Default // File: ShapesGenerator.kt package com.shapes fun generateSquare() = Square() fun generateTriangle() = Triangle() // Java usage: ShapesGeneratorKt.generateSquare()
// Custom // File: ShapesGenerator.kt @file:JvmName("ShapesGenerator") package com.shapes fun generateSquare() = Square() fun generateTriangle() = Triangle() // Java usage ShapesGenerator.generateSquare()
Calling Kotlin from Java - Kotlin Programming Languagekotlinlang.org