概述
目录
- 1. 定义一个函数
- 2. 表达式函数体
- 3. 更简洁的使用函数
- 3.1 命名参数
- 3.2 默认参数值
- 4. 顶层函数
- 5. 扩展函数
- 6. 可变参数
- 7. 展开运算符
- 8. 集合相关的函数
- 9. 键值对的处理:中缀调用和解构声明
- 10. 字符串和正则表达式的处理
- 11. 和Lambda表达式有关的函数
- 11.1 maxBy函数
- 11.2 在作用域中访问变量
- 11.3 一些集合的函数API
- 11.3.1 filter和map
- 11.3.2 “all” , "any" , "count" , "find":对集合应用判断式
- 11.3.3 groupBy : 把列表转换成分组的map
- 11.3.4 flatMap 和 flatten: 处理嵌套集合中的元素
- 11.3.5 惰性集合操作:序列
- 11.4 带接收者的lambda:"with" 和 "apply"
- 11.4.1 ”with“函数
- 11.4.2 ”apply“函数
1. 定义一个函数
fun max(a: Int, b: Int): Int {
return if (a > b) a else b
}
函数的声明以关键字 fun 开始,函数名称紧随其后:这个例子中函数名称是
max ,接下来是括号括起来的参数列表。参数列表的后面跟着返回类型,它 之间用一个冒号隔开。
2. 表达式函数体
函数体由单个表达式构成的函数,可以去掉花括号和return语句。
fun min(a : Int, b: Int ): Int = if(a<b) a else b
还可以进一步简化max函数,省略返回类型(只有表达式体函数的返回值类型可以省略)
fun min(a : Int, b: Int ) = if(a<b) a else b
3. 更简洁的使用函数
demo: 更改默认的toString打印。
fun<T> joinToString(collection : Collection<T>,
separator : String,
prefix : String,
postfix : String
):String{
val result = StringBuilder(prefix) //开始符
for( (index,element) in collection.withIndex()){
if(index > 0) result.append(separator) //分割符
result.append(element) //添加数据
}
result.append(postfix) //结束符
return result.toString()
}
结果:
val list1 = listOf(1,2,3)
println( joinToString(list1,";","(",")" ))
//输出:(1;2;3)
现在我们来修改这个函数,让它的调用更加简洁
3.1 命名参数
- 可以显式的标明一些参数的名称,如果在调用一个函数时,指明了一个参数的名称,为了避免混淆,它之后的所有参数都需要标明名称
- 在用命名参数来声明函数后,在调用时可以按你自己想要的任意顺序给定参数值
val list1 = listOf(1,2,3)
println( joinToString(list1,separator = ";",prefix = "(",postfix = ")" ))
3.2 默认参数值
Kotlin中可以在声明参数时设置默认参数值。
优点:避免创建重载的函数。
//给参数设置默认值
fun<T> joinToString(collection : Collection<T>,
separator : String = ",",
prefix : String = "[",
postfix : String = "]"
)
现在就可以用所有参数来调用这个函数,或者省略部分函数。
println( joinToString(list1,separator = ";",prefix = "(",postfix = ")" ))
println(joinToString(list1))
println(joinToString(list1,";"))
//结果
(1;2;3)
[1,2,3]
[1;2;3]
注意:当你从Java中调用Kotlin函数的时候,必须显示的指定所有的参数值。
4. 顶层函数
Java 作为 门面向对象的语言,需要所有的代码都写作类的函数。
Kotlin中,可以把函数直接放到代码文件的顶层,不用从属于任何的类。
package dataUtil
fun min(a : Int, b: Int ): Int = if(a<b) a else b
在java中它被编译为
package dataUtil;
public class HelpUtilKt {
public static int min(...){.....}
}
Kotiin 编译生成的类的名称,对应于包含函数的文件的名称。这个文
件中的所有顶层函数编译为这个类的静态函数。因此, 当从 Java 调用这个函数的时候,和调用任何其他静态函数一样非常
import static dataUtil.HelpUtilKt.min;
public class fun {
public static void main(String[] args){
min(1,2);
}
}
修改文件类名:
要改变包含 Kotlin 顶层函数的生成的类的名称,需要为这个文件添加@JvmName 的注解,将其放到这个文件的开头,位于包名的前面:
@file: JvmName("Change")
package dataUtil
fun min(a : Int, b: Int ): Int = if(a<b) a else b
java中的调用:
import static dataUtil.Change.min;
public class fun {
public static void main(String[] args){
min(1,2);
}
}
5. 扩展函数
扩展函数非常简单,它就是一个类的成员函数,不过定义在类的
外面
demo:为String类扩展函数
fun String.lastChar() : Char = this[this.length-1]
//调用
val c = "1232d"
println(c.lastChar())
注意:
-
在扩展函数中,可以直接访问被扩展的类的其他方法和属性,但是扩展函数不能访问私有的或者受保护的成员
-
定义的扩展函数并不会在整个项目范围内生效,如果要使用它,就需要导入。
-
在java中调用扩展函数
char c = lastChar("java");
demo:采用扩展函数更改默认的toString打印。
fun<T> Collection<T>.joinToString( separator : String = ",", prefix : String = "[", postfix : String = "]" ) : String{ val result = StringBuilder(prefix) for( (index,element) in this.withIndex()){ if( index > 0) result.append(separator) result.append(element) } result.append(postfix) return result.toString() }
-
扩展函数不可重写
6. 可变参数
在创建列表时,可以传递任意个数的参数给它:
val list = listOf(1,2,3,4,5)
看一下listof的源代码:
public fun <T> listOf(vararg elements: T): List<T> = if (elements.size > 0) elements.asList() else emptyList()
在Kotlin中使用vararg来说明可变参数,而不再是java中的三个点
7. 展开运算符
在Kotlin中当遇到传递的数据已经包装在数组中时,要求你显示的解包数组。Kotlin中的展开运算符是“*”
val array : Array<String> = arrayOf("two","three","four")
val list2 = listOf("one" , *array)
println(list2)
注:
- 通过展开运算符,可以在单个调用中组合来自数组的值和某些固定值。
- 展开运算符只能展开数组数据,不能展开一个可变长的列表。
8. 集合相关的函数
val set = hashSetOf(1,3,5) //hashSet
val list = arrayListOf(1,3,5) //ArrayList
val map = hashMapOf(1 to "one",7 to "seven") //HashMap
9. 键值对的处理:中缀调用和解构声明
demo1:构建一个map集合
val map = mapOf(1.to("one"),7 to "seven",52.to("fifty-three"))
一般的to函数的调用
1.to("one")
使用中缀符号调用to函数
7 to "seven"
这两者是完全等价的,并且在编译器中它建议我们采用中缀符号
demo2:使用中缀符号调用函数
要允许使用中缀符号调用函数,需要使用infix修饰符来标记这个函数
看一下 to 函数的源码:
public infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)
Kotlin 学习笔记(一)infix函数
10. 字符串和正则表达式的处理
Kotlin提供了一些名为split的,而具有不同参数的重载的扩展函数。
demo1:
val stringS = "12.345-6.A".split("\.|-".toRegex())
demo2:
val stringS2 = "12.345-6.A".split(".","-")
两个的结果都一样,[12, 345, 6, A],但是如果直接在java中使用"12.345-6.A".split(".")会得不到想要的结果,因为“.”在正则表达式中是表示任何字符
11. 和Lambda表达式有关的函数
11.1 maxBy函数
maxBy函数可以在任何集合上调用,且只需要一个实参:一个参数,指定比较那个值来找到最大元素。
data class Person(val name : String, val age : Int)
val people = listOf(Person("Alice",29) , Person("aaa",18))
val maxAge = people.maxByOrNull { it.age }
11.2 在作用域中访问变量
在Kotlin中不会仅限于访问final变量,在lambda内部也可以修改这些非final的变量。
var sun = 0
people.forEach{
if(it.age >= 20){
sun++
}
}
11.3 一些集合的函数API
11.3.1 filter和map
filter函数遍历集合并选出满足判断式的元素。
val list = listOf(1,2,3,4)
val filterList = list.filter { it % 2 == 0 }
注意:filter函数可以从集合中移除你不想要的元素,但是它并不会改变这些元素。
map函数对集合中的每一个元素应用给定的函数并把结果收集到一个新函数。
val list = listOf(1,2,3,4)
val mapList = list.map { it * it }
// 结果:[1, 4, 9, 16]
11.3.2 “all” , “any” , “count” , “find”:对集合应用判断式
函数 | 解释 |
---|---|
all | 检查所有元素是否都满足判别式(Boolean) |
any | 检查集合中是否至少存在一个匹配的元素(Boolean) |
count | 有多少个子元素满足判断式(Int) |
find | 找到一个满足判断式的元素(T) |
使用如下:
val list = listOf(1,2,3,4,5,7,8)
val canBeInClub = { i : Int -> i%2==0}
println(list.all(canBeInClub))
println(list.any(canBeInClub))
println(list.count(canBeInClub))
println(list.find(canBeInClub))
/*结果:
false
true
3
2
*/
11.3.3 groupBy : 把列表转换成分组的map
通过这个函数可以把列表按不同特征划分为不同的分组(返回值类型:Map<K, List>)
使用:
val people = listOf(Person("Alice",29) , Person("aaa",18),Person("ccc",29))
val map = people.groupBy { it.age }
println(map)
//结果:{29=[Person(name=Alice, age=29), Person(name=ccc, age=29)], 18=[Person(name=aaa, age=18)]}
11.3.4 flatMap 和 flatten: 处理嵌套集合中的元素
flatMap:根据作为实参给定的函数对集合中的每个元素做变换,然后把多个列表合并成一个列表。
val strings = listOf("abc","def")
println(strings.flatMap { it.toList() }) //字符串的toList函数把它转换为字符列表
//结果:[a, b, c, d, e, f]
flatten: 如果不需要做任何的变换,只需平铺一个集合,可以使用fatten函数
11.3.5 惰性集合操作:序列
当我们要对一个大型集合执行链式操作时,如果直接用集合来操作,会创建很多中间集合。调用就变得十分低效。此时,使用序列可以更高效。
可以调用拓展函数asSequence把任意集合转换为序列。调用toList来做反向的变换。
val change = list.asSequence()
.map{it * it}
.filter(canBeInClub)
.toList()
注意:序列操作分为两类:中间的和末端的。***一次中间操作返回的是另一个序列。一次末端操作返回的是一个结果。***如果一个操作缺少了末端操作,那么这个序列操作是无效的。
创建序列:
generateSequence函数:给定序列中的前一个元素,这个函数会计算出下一个元素。
val numbers = generateSequence(0) { it+1 }
val numbersTo100 = numbers.takeWhile{ it <= 100}
print(numbersTo100.sum())
注意: 这个例子中的numbers,numbersTo100都是有延期操作的序列。这些序列中的实际数字直到你调用末端操作的时候才会求值。
11.4 带接收者的lambda:“with” 和 “apply”
11.4.1 ”with“函数
可以用它对同一个对象执行多次操作,而不需要反复把对象的名称写出来。
demo:
fun alphabet() : String{
val result = StringBuilder()
for( letter in 'A'..'Z'){
result.append(letter)
}
result.append("nNow I know the alphabet")
return result.toString()
}
使用with函数改写:
fun alphabet() : String{
val result = StringBuilder()
return with(result){
for( letter in 'A'..'Z'){
this.append(letter)
}
append("nNow I know the alphabet") //省略this也可以调用方法
this.toString()
}
}
进一步优化:
fun alphabet() = with(StringBuilder()){
for( letter in 'A'..'Z'){
append(letter)
}
append("nNow I know the alphabet")
toString()
}
说明:
- 它实际上是一个接收两个参数的函数:这个例子中两个参数分别是 stringBuilder lambd 这里利了把 lambda 在括号外的约定,这样整个调用看起来就像是内建的语 功能 。你可以选择把它写成 with ( result, { . . . } ),但可读性就会差很多
- with 函数把它的第 个参数转换成作为第 个参数传给它的 lambda 接收可以显式地通过 this 引用来访问这个接收者。或者,按照惯例,可以省略 this 引用,不用任何限定符直接访问这个值的方法和属性。
11.4.2 ”apply“函数
apply 函数几乎和 with 函数一模一样, 的区别是 apply 始终会返回作为实参传递给它的对象(换句话说,接收者对象) 。
fun alphabet2() = StringBuilder().apply {
for( letter in 'A'..'Z'){
append(letter)
}
append("nNow I know the alphabet")
}.toString()
最后
以上就是机智玫瑰为你收集整理的Kotlin学习篇(2)—— Kotlin的函数的全部内容,希望文章能够帮你解决Kotlin学习篇(2)—— Kotlin的函数所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复