课程名称:移动端架构师
课程章节:Android必备Kotlin核心技术
课程讲师:CrazyCodeBoy LovelyChubby
课程内容:
方法声明
方法参数
方法用法
在Java中对象是一等公民,而在Kotlin中方法是一等公民。
fun functionLearn(days: Int): Boolean { return days > 100 }
//成员方法 class Person { fun test1() { println("成员方法") } } Person().test1()
companion object 实现的类方法
静态类
全局静态
Kotlin中并没有static关键字,不过我们可以借助companion object 来实现类方法的目的。
companion object 实现的类方法
class Person { companion object { fun test2() { println("companion object 实现的类方法") } } } Person.test2()
静态类
如果我们想实现一个工具util的话,可以借助 object来创建一个静态类:
/** * 整个静态类 */ object NumUtil { fun double(num: Int): Int { return num * 2 } }
全局静态
我们可以直接新建一个 Kotlin file 然后定义一些常量、方法。
当方法返回单个表达式时,可以省略花括号并且在 = 符号之后指定代码体即可:
fun double(x: Int): Int = x * 2
当返回值类型可由编译器推断时,显式声明返回类型是可选的:
fun double(x: Int) = x * 2
默认参数
具名参数
可变数量的参数
方法参数可以有默认值,当省略相应的参数时使用默认值。与其Java相比,这可以减少重载数量:
fun read(b: Array<Byte>, off: Int = 0, len: Int = b.size) { /*……*/ }
我们可以通过类型后面的 = 来设置默认值。
如果一个默认参数在一个无默认值的参数之前,那么该默认值只能通过使用具名参数调用该方法来使用:
fun foo(bar: Int = 0, baz: Int) { /*……*/ } foo(baz = 1) // 使用默认值 bar = 0
如果在默认参数之后的最后一个参数是 Lambda 表达式,那么它既可以作为具名参数在括号内传入,也可以在括号外传入:
fun foo(bar: Int = 0, baz: Int = 1, qux: () -> Unit) { /*……*/ } foo(1) { println("hello") } // 使用默认值 baz = 1 foo(qux = { println("hello") }) // 使用两个默认值 bar = 0 与 baz = 1 foo { println("hello") } // 使用两个默认值 bar = 0 与 baz = 1
方法的参数(通常是最后一个)可以用 vararg 修饰符标记:
fun append(vararg str: Char): String { val result = StringBuffer() for (char in str) { result.append(char) } return result.toString() }
允许将可变数量的参数传递给方法:
append('h', 'e', 'l', 'l', 'o')
可变参数的要求:
只有一个参数可以标注为 vararg;
如果 vararg 参数不是列表中的最后一个参数, 可以使用具名参数语法传递其后的参数的值,或者,如果参数具有方法类型,则通过在括号外部传一个 Lambda。
val world = charArrayOf('w', 'o', 'r', 'l', 'd') val result = append('h', 'e', 'l', 'l', 'o',' ', *world)
在 Kotlin 中方法可以在文件顶层声明,这意味着你不需要像一些语言如 Java、C# 那样需要创建一个类来保存一个方法。
此外除了顶层方法,Kotlin 中方法也可以声明在局部作用域、作为成员方法以及扩展方法。
Kotlin 支持局部方法,即一个方法在另一个方法内部:
fun maginc(): Int { fun foo(v: Int): Int { return v * v } val v1 = (0..100).random() return foo(v1) }
局部方法可以访问外部方法(即闭包)的局部变量。
在Java 8的时候开始支持Lambda表达式,目前Lambda语法在Java中已经被广泛的运用,Lambda表达式可以理解为是一种语法糖,值得庆幸的是,Kotlin一经开源成熟就已经支持这种语法。
Lambda表达式的本质其实是匿名方法,因为在其底层实现中还是通过匿名方法来实现的。但是我们在用的时候不必关心起底层实现。不过Lambda的出现确实是减少了代码量的编写,同时也是代码变得更加简洁明了。
Lambda作为方法式编程的基础,其语法也是相当简单的。这里先通过一段简单的代码演示没让大家了解Lambda表达式的简洁之处:
view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(v.getContext(), "Lambda简洁之道", Toast.LENGTH_LONG).show(); } });
VS
view.setOnClickListener { v -> Toast.makeText(v.context, "Lambda简洁之道", Toast.LENGTH_LONG) .show() }
view.setOnClickListener { v -> Toast.makeText(v.context, "Lambda简洁之道", Toast.LENGTH_LONG) .show() }
是匿名方法
二是可传递
语法如下:
无参数的情况 :
val/var 变量名 = { 操作的代码 } //无参数的情况 = val tes1 = { println("无参数") } fun test() { println("无参数") } val test1 = { println("无参数") }
有参数的情况
val/var 变量名: (参数的类型,参数类型,...) -> 返回值类型 = {参数1,参数2,... -> 操作参数的代码} //有参数的lambda表达式 test2 = test3 = test4 fun test2(a: Int, b: Int): Int { return a + b } val test3: (Int, Int) -> Int = { a, b -> a + b} //或者 val test4 = { a:Int, b:Int -> a + b}
可等价于
// 此种写法:即表达式的返回值类型会根据操作的代码自推导出来。 val/var 变量名 = { 参数1 : 类型,参数2 : 类型, ... -> 操作参数的代码 } val test4 = { a:Int, b:Int -> a + b}
Lambda表达式作为方法中的参数的时候,这里举一个例子:
fun test(a : Int, 参数名 : (参数1 : 类型,参数2 : 类型, ... ) -> 表达式返回类型){ ... }
认识it
it并不是Kotlin中的一个关键字(保留字)
it是在当一个高阶方法中Lambda表达式的参数只有一个的时候可以使用it来使用此参数
it可表示为单个参数的隐式名称,是Kotlin语言约定的
实例A:单个参数的隐式名称
// 这里举例一个语言自带的一个高阶方法filter,此方法的作用是过滤掉不满足条件的值。 val arr = arrayOf(1,3,5,7,9) // 过滤掉数组中元素小于2的元素,取其第一个打印。这里的it就表示每一个元素。 println(arr.filter { it < 5 }.component1())
在使用Lambda表达式的时候,可以用下划线(_)表示未使用的参数,表示不处理这个参数。
在遍历一个Map集合的时候,这当非常有用
val map = mapOf("key1" to "value1", "key2" to "value2", "key3" to "value3") map.forEach { (key, value) -> println("$key \t $value") } // 不需要key的时候 map.forEach { (_, value) -> println(value) }
完整的FunctionLambda.kt文件和FunctionLambda2.kt文件代码如下
package com.demo.kotlin fun main() { println("functionLearn:${functionLearn(101)}") Person().test1() Person.test2() println("NumUtil.double:${NumUtil.double(4)}") println("double:${double(3)}") println("append:${append('h', 'e', 'l', 'l', 'o')}") println("magic:${magic()}") test1() //lambda表达式 test5() } //方法声明 fun functionLearn(days:Int):Boolean { return days > 100 } //成员方法 class Person { fun test1() { //成员方法 println("成员方法") } companion object { fun test2() { println("companion object 实现的类方法") } } } //整个静态类,如果我们想实现一个工具util的话,可以借助 object来创建一个静态类 object NumUtil { fun double(num: Int): Int { return num * 2 } } //单表达式方法:当方法返回单个表达式时,可以省略花括号并且在 = 符号之后指定代码体即可 fun double(x: Int): Int = x * 2 /** * 默认值,方法参数可以有默认值,当省略相应的参数时使用默认值。与其Java相比,这可以减少重载数量: * read(array) * read(array, 1) * read(array, 1, 2) */ fun read(b: Array<Byte>, off:Int=0, len:Int=b.size) {} /** * 如果一个默认参数在一个无默认值的参数之前,那么该默认值只能通过使用具名参数调用该方法来使用: * foo(baz = 1) 使用默认值 bar = 0 */ fun foo(bar: Int = 0, baz: Int) {} /** * 可变数量的参数,方法的参数(通常是最后一个)可以用 vararg 修饰符标记: * 可变参数的要求: * 只有一个参数可以标注为 vararg; * 如果 vararg 参数不是列表中的最后一个参数, 可以使用具名参数语法传递其后的参数的值,或者,如果参数具有方法类型,则通过在括号外部传一个 Lambda。 * append('h', 'e', 'l', 'l', 'o') * val world = charArrayOf('w', 'o', 'r', 'l', 'd') * val result = append('h', 'e', 'l', 'l', 'o',' ', *world) */ fun append(vararg str:Char):String { val result = StringBuffer() for (char in str) { result.append(char) } return result.toString() } //局部方法, Kotlin 支持局部方法,即一个方法在另一个方法内部: fun magic(): Int { fun foo(v: Int): Int { return v * v } val v1 = (0..100).random() return foo(v1) } /** * lambda表达式 */ //无参数的情况 = val tes1 = { println("无参数") } fun test() { println("无参数") } val test1 = { println("无参数") } //有参数的lambda表达式 test2 = test3 = test4 fun test2(a: Int, b: Int): Int { return a + b } val test3: (Int, Int) -> Int = { a, b -> a + b} //或者 val test4 = { a:Int, b:Int -> a + b} //Lambda实践如何使用it fun test5() { // 这里举例一个语言自带的一个高阶方法filter,此方法的作用是过滤掉不满足条件的值。 val arr = arrayOf(1,2,3,4,5) println(arr.filter { it < 5 }) // 过滤掉数组中元素小于2的元素,取其第一个打印。这里的it就表示每一个元素。 println(arr.filter { it < 5 }.component1()) //如何使用下划线_, 在使用Lambda表达式的时候,可以用下划线(_)表示未使用的参数,表示不处理这个参数。 val map = mapOf("key1" to "value1","key2" to "value2","key3" to "value3") map.forEach{ (key, value) -> println("$key \t $value")} map.forEach{ (_, value) -> println("$value")} }
package com.demo.kotlin import com.fuzhou.wpsystem.kotlin.Result fun main() { testSum() testToIntSum() testClosure(1)(2) { //闭包 println(it) } testDecode() //结构声明 literal() //方法字面值 } fun testSum() { val list = listOf(1, 2, 3, 4) val result = list.sum { println(it) } println("计算结果:${result}") } /** * 高阶函数--函数作为参数 * 需求:实现一个能够对集合元素进行求和的高阶函数,并且每遍历一个集合元素要有回调 */ fun List<Int>.sum(callback: (Int) -> Unit): Int { var result = 0 for (v in this) { result += v callback(v) } return result } /** * 高阶函数--函数作为返回值 * 需求:实现一个能够对集合元素进行求和的高阶函数,并且返回一个 声明为(scale: Int) -> Float的函数 */ fun List<String>.toIntSum():(scale: Int) -> Float { println("第一层函数") return fun(scale): Float { var result = 0f; for (v in this) { result += v.toInt() * scale } return result } } fun testToIntSum() { val listStr = listOf("1", "2", "3") val result = listStr.toIntSum()(2) println("toIntSum计算结果:${result}") } /** * 闭包(Closure) */ fun testClosure(v1: Int): (v2:Int, (Int) -> Unit) -> Unit { return fun(v2, printer: (Int) -> Unit) { printer(v1 + v2) } } /** * 结构声明 */ fun testDecode() { var result = Result("success", 0) val (msg, code) = result println("msg:${msg} code:${code}") } data class Result(var msg: String, var code: Int) /** * 匿名函数 */ val fun1 = fun(x: Int, y: Int): Int = x + y val fun2 = fun(x: Int, y: Int): Int { return x + y } /** * Kotlin方法字面值 */ fun literal() { //定义一个变量 tmp, 而该变量的类型就是 (Int) -> Boolean var temp: ((Int) -> Boolean?)? = null //{ num -> (num > 10) } 方法字面值 temp = { num -> (num > 10) } println("temp(11):${temp(11)}") }
课程收获
谢谢老师,讲的非常细致,之前对于Lambda表达式还是很抗拒的,感觉晦涩难懂,不想使用,经过本章的学习,自己多练几遍感觉好多了,语法简洁明了,可以少写很多代码,期待后边的继续学习。