1.函數的基本用法
//java
@Override
public void onCreate(Bundle savedInstanceState) {
...
}
//Kotlin
override fun onCreate(savedInstanceState: Bundle?) {
...
}
<1>使用小寫“override”在同一行表達重載操作;
<2>默認函數是公開的,忽略關鍵字“public”;
<3>不存在關鍵字void,若無返回參數,則不用特別說明;
<4>用關鍵字“fun”表示這裏是函數定義;
<5>使用“變量名稱:變量類型”聲明輸入參數的格式;
<6>如果某個變量爲空,需要在變量類型後面加個問號“?”。
1.1輸入參數的格式
函數既可以沒有輸入參數,也可以沒有輸出參數;或者只有輸入參數;輸入參數可空
//沒有輸入參數,沒有輸出參數
fun getDinnerEmpty() {
tv_result.text = ""
}
//只有輸入參數
fun getDinnerInput(egg:Int, leek:Double, water:String, shell:Float) {
tv_result.text = ""
}
//輸入參數存在空值
fun getDinnerCanNull(egg:Int, leek:Double, water:String?, shell:Float)
{
tv_result.text = ""
}
1.2 輸出參數的格式
fun main():Int//輸入參數後加“:數據類型”
開發者不聲明任何返回參數時,Kotlin默認返回一個Unit類型的對象。
fun getDinnerUnit():Unit {
tv_result.text = ""
}
//只有輸出參數
fun getDinnerOutput():String {
var dinner:String = "巧婦難爲無米之炊"
return dinner
}
//同時具備輸入參數和輸出參數
fun getDinnerFull(egg:Int, leek:Double, water:String?, shell:Float):String {
var dinner = "橫看成嶺側成峯..."
return dinner
}
1.3輸入參數的變化
默認參數
fun getFourBigDefault(general:String, first:String="造紙", second:String="印刷術",
third:String="火藥", fourth:String="指南針"):String {
var answer:String = "$general:$first:$second:$third:$fourth"
return answer
}
//如果調用參數沒有給出某參數的具體值,系統就自動對該參數賦予默認值
btn_input_default.setOnClickListener {
tv_four_answer.text= getFourBigDefault("中國古代四大發明")
}
命名參數
btn_input_part.setOnClickListener {
tv_four_answer.text=getFourBigDefault("中國古代四大發明","蔡倫發明的造紙") }
//如果不需要某參數默認值,只需調用“變量名="***"”
btn_input_name.setOnClickListener {
tv_four_answer.text=getFourBigDefault("中國古代四大發明",second="活字印刷") }
可變參數
在Java體系中採取“Object... args”,Kotlin中使用關鍵字vararg,表示其後的參數個數是不確定的,以可變字符串爲例,則表示爲“vararg args: String?”。
fun getFourBigVararg(general:String, first:String="造紙術", second:String="印刷術", third:String="火藥", fourth:String="指南針", vararg otherArray: String?):String {
var answer:String = "$general:$first:$second:$third:$fourth"
//循環取出可變參數包含的所有字段
for (item in otherArray) {
answer = "$answer$item"
}
return answer
}
btn_param_vararg.setOnClickListener {
tv_four_answer.text = if (isOdd) getFourBigVararg("古代四大發明") else getFourBigVararg("古代的七大發明","造紙術","印刷術","火藥","指南針","絲綢","瓷器","茶葉")
isOdd = !isOdd
}
可變數組參數
fun getFourBigVararg(general:String, first:String="造紙術", second:String="印刷術", third:String="火藥", fourth:String="指南針", vararg otherArray: Array<String>):String {
var answer:String = "$general:$first:$second:$third:$fourth"
//先遍歷每個數組
for (array in otherArray) {
//再遍歷數組元素
for (item in array) {
answer = "$answer:$item"
}
}
}
btn_param_array.setOnClickListener {
tv_four_answer.text = if (isOdd) getFourBigArray("古代的四大發明") else getFourBigArray("古代的N大發明","造紙術","印刷術","火藥","指南針",arrayOf("絲綢","瓷器","茶葉"),arrayOf("國畫","中醫","武術"))
isOdd = !isOdd
}
2.特殊函數
2.1泛型函數
定義泛型函數時,得在函數名稱前添加“<T>”,表示以T聲明的參數(包括輸入參數和輸出參數),其參數類型必須在參數調用時指定。
fun <T> appendString(tag:String, vararg otherInfo: T?):String {
...}
var count = 0
btn_vararg_generic.setOnClickListener {
tv_function_result.text = when (count%3) {
0 -> appendString<String>("古代的四大發明","造紙術","印刷術","火藥","指南針")
1 -> appendString<Int>("小於10的素數",2,3,5,7)
else -> appendString<Double>("燒錢的日子",5.20,6.18,11.11,12.12)
}
count++
2.2內聯函數
如果參數類型都是繼承自某種類型,那麼允許在定義函數時指定從這個基類泛化開,凡是繼承自該基類的子類,都可以作爲輸入參數進行函數調用,反之無法調用函數。舉個例子,Int、Float和Double都繼承自Number類,但是假如定義一個輸入參數形式爲setArrayNumber(array:Array<Number>)的函數,它並不接受Array<Int>或者Array<Double>的入參。如果要讓該方法同時接收整型和雙精度的數組入參,就得指定泛型變量T來自於基類Number,即將“<T>”或者“<reified T : Number>”,同時在fun前面添加關鍵字inline,表示該函數屬於內聯函數。
//該函數既不接收Array<Int>,也不接收Array<Double>
fun setArrayNumber(array:Array<Number>) {
var str:String = "數組元素依次排列:"
for (item in array) {
str = str + item.toString() + ", "
}
tv_function_result.text = str
}
//只有內聯函數纔可以被具體化
inline fun <reified T : Number> setArrayStr(array:Array<T>) {
var str:String = "數組元素依次排列:"
for (item in array) {
str = str + item.toString() + ", "
}
tv_function_result.text = str
}
var int_array:Array<Int> = arrayOf(1, 2, 3)
var float_array:Array<Float> = arrayOf(1.0f, 2.0f, 3.0f)
var double_array:Array<Double> = arrayOf(11.11, 22.22, 33.33)
btn_generic_number.setOnClickListener {
when (count%3) {
0 -> setArrayStr<Int>(int_array)
1 -> setArrayStr<Float>(float_array)
else -> setArrayStr<Double>(double_array)
}
count++
}
//btn_generic_number.setOnClickListener { setArrayNumber(int_array) }//報錯
2.3簡化函數
如果一個函數的表達式比較簡單,一兩行代碼就可以搞定,那麼使用等號代替大括號。示例:
fun factorial(n:Int):Int {
if (n <= 1) n
else n*factorial(n-1)
}
//簡化函數
fun factorial(n:Int):Int = if (n <= 1) n else n*factorial(n-1)
2.4尾遞歸函數
函數末尾的返回值重複調用了自身函數,該函數叫尾遞歸函數。此時要在fun前加上關鍵字tailrec,
//尾遞歸函數會使編譯器自動優化遞歸,即用循環方式代替遞歸,從而避免棧溢出的情況
tailrec fun findFixPoint(x: Double = 1.0): Double
= if (x == Math.cos(x)) x else findFixPoint(Math.cos(x))
2.5 高階函數
A函數作爲B函數的輸入參數,那麼B函數稱爲高階函數。
//greater方法作爲參數傳入,且其含有2個輸入參數,返回值爲布爾值
//如果第1個參數大於第2個參數,就認爲greater返回true,否則返回false
fun <T> maxCustom(array: Array<T>, greater: (T, T) -> Boolean): T? {
var max: T? = null
for (item in array)
if (max == null || greater(item, max))
max = item
return max
}
var string_array:Array<String> = arrayOf("How", "do", "you", "do", "I'm", "Fine")
btn_function_higher.setOnClickListener {
tv_function_result.text = when (count%4) {
0 -> "字符串數組默認最大值爲${string_array.max()}"
1 -> "字符串數組按長度比較的最大值爲${maxCustom<String>
(string_array, { a, b -> a.length > b.length })}"
2-> " 字符串數組的默認最大值爲${maxCustom(string_array, { a, b -> a > b })}"
else -> "字符串數組去掉空格再比較長度的最大值爲${maxCustom (string_array, { a, b -
> a.trim().length > b.trim().length })}"
}
count++;
}
“{ a, b -> a.length > b.length }”這是Lambda表達式的匿名函數寫法,前半部分表示函數的輸入參數,後半部分表示函數體。按照規範的函數寫法是這樣:
fun anonymous(a:String, b:String):Boolean {
var result:Boolean = a.length > b.length
return result
}
3.增強系統函數
3.1擴展函數
允許開發者給系統類補寫新的方法,而無須另外編寫額外的工具類。
比如系統的Array類除了sort,max等方法,我們可以給它添加一個擴展函數swap
fun Array<Int>.swap(pos1: Int, pos2: Int) {
val tmp = this[pos1] //this表示數組自身
this[pos1] = this[pos2]
this[pos2] = tmp
}
//擴展函數結合泛型函數能更好地擴展函數的功能
fun <T> Array<T>.swap(pos1: T, pos2: T) {
val tmp = this[pos1]
this[pos1] = this[pos2]
this[pos2] = tmp
}
val array:Array<Double> = arrayOf(1.0, 2.0, 3.0, 4.0, 5.0)
btn_function_extend.setOnClickListener {
array.swap(0, 3)
}
3.2 擴展高階函數
給2.5提到的高階函數maxCustom添加擴展函數功能。該函數的目的是求數組元素的最大值,因此不妨加到Array<T>數組中去
fun <T> Array<T>.maxCustomize(greater: (T, T) -> Boolean): T? {
var max: T? = null
for (item in this)
if (max == null || greater(item, max))
max = item
return max
}
string_array.maxCustomize({ a, b -> a.length > b.length })//調用
3.3 日期時間函數
Kotlin無須書寫專門的DateUtil工具類,直接改寫Date類的擴展函數即可,下面是幾個Date的擴展函數函數
//返回的日期時間格式形如 2017-10-01 10:00:00
fun Date.getNowDateTime(): String {
val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
return sdf.format(this)
}
//只返回日期字符串
fun Date.getNowDate(): String {
val sdf = SimpleDateFormat("yyyy-MM-dd")
return sdf.format(this)
}
//只返回時間字符串
fun Date.getNowTime(): String {
val sdf = SimpleDateFormat("HH:mm:ss")
return sdf.format(this)
}
//返回詳細的時間字符串,具體到毫秒
fun Date.getNowTimeDetail(): String {
val sdf = SimpleDateFormat("HH:mm:ss.SSS")
return sdf.format(this)
}
//返回開發者指定格式的日期時間字符串
fun Date.getFormatTime(format: String=""): String {
var ft: String = format
val sdf = if (!ft.isEmpty()) SimpleDateFormat(ft)
else SimpleDateFormat("yyyyMMddHHmmss")
return sdf.format(this)
}
Date().getNowDate()//調用例子
3.4 單例對象
Kotlin使用對象關鍵字“Object”加以修飾,並稱之爲單例對象,相當於Java的工具類。
下面是採取單例對象改寫的日期時間工具代碼:
object DateUtil {
//聲明一個日期時間的屬性
//返回的日期時間格式形如2017-10-01 10:00:00
val nowDateTime: String
get() {
//外部訪問DateUtil.nowDateTime時,會自動調用nowDateTime附屬的get方法得到它的值
val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
return sdf.format(Date())
}
val nowDate: String
get() {
val sdf = SimpleDateFormat("yyyy-MM-dd")
return sdf.format(Date())
}
...
}
DateUtil.nowDateTime//調用