1. 普通函数
// 无返回值
fun print(msg: String) {
println(msg)
}
// 正常写法,有返回值
fun sum(num1: Int = 0, num2: Int = 0): Int {
return num1 + num2
}
// 当只有一行代码的时候,可以省略函数体部分
fun sum(num1: Int = 0, num2: Int = 0): Int = num1 + num2
2. 标准函数
2.1 let 使用
1、let既不是操作符,也不是关键字,它是一个函数,当调用了对象的let函数,然后Lambda表达式中的代码就会立即执行,并且这个对象也会作为参数传递到Lambda表达式中
2、let函数搭配?.来使用时,Lambda表达式中的被传递进来的对象肯定非空
3、let函数可以处理全局变量的判空问题,而if语句无法做到这点
fun eatA(a: A?) {
a?.let { a1 ->
a1.eat()
}
}
2.2 with 使用
1、with函数接收两个参数,第一个参数是一个任一类型的对象,第二个参数使Lambda表达式
2、with函数会在Lambda表达式中提供第一个参数对象的上下文,并使用Lambda表达式的最后一行代码作为返回值返回
fun withDemo() {
val list = listOf('a', 'b', 'c', 'd', 'e')
val result = with(StringBuilder()) {
// 在Lambda中,StringBuilder为上下文
for (c in list) {
append(c)
}
toString()
}
println(result)
// 打印结果:abcde
}
2.3 run 使用
1、run函数的使用方法跟场景跟with函数十分类似,只是语法上做了稍微的修改,run函数不能直接被调用,必须通过调用对象的run函数才行
fun runDemo() {
val list = listOf('a', 'b', 'c', 'd', 'e')
val sb = StringBuilder()
val result = sb.run {
// 在Lambda中,StringBuilder为上下文
for (c in list) {
append(c)
}
toString()
}
println(result)
// 打印结果:abcde
}
2.4 apply 使用
1、apply函数和run函数也是极为类型,只是apply函数无法指定返回值,而是会自动返回调用对象本身
fun applyDemo() {
val list = listOf('a', 'b', 'c', 'd', 'e')
val sb = StringBuilder()
val result = sb.apply {
// 在Lambda中,StringBuilder为上下文
for (c in list) {
append(c)
}
}
println(result.toString())
// 打印结果:abcde
}
2.5 repeat 使用
1、用于将字符串重复打印n次
fun repeatDemo() {
val str = "abc"
println(str.repeat(3))
// 打印结果:abcabcabc
}
repeat 源码:
public actual fun CharSequence.repeat(n: Int): String {
require(n >= 0) { "Count 'n' must be non-negative, but was $n." }
return when (n) {
0 -> ""
1 -> this.toString()
else -> {
when (length) {
0 -> ""
1 -> this[0].let { char -> String(CharArray(n) { char }) }
else -> {
val sb = StringBuilder(n * length)
for (i in 1..n) {
sb.append(this)
}
sb.toString()
}
}
}
}
}
3. 静态函数
3.1 companion object
companion object 这个关键字实际上会在类内部创建一个伴生类,定义在伴生类里面的方法为伴生类内部的实例方法,使用的时候可像静态方法那样的方式调用该方法,但其并不是真正的静态方法
class StaticMethodTest {
companion object {
fun doAction() {
println("do action")
}
}
}
class Test {
fun main() {
StaticMethodTest.doAction()
}
}
3.2 单例类
与其他主流语言不同的是,kotlin极度弱化了静态方法这个概念,其提供了一种比静态方法更好的语法特性,仅需在类名前将class替换成object关键字,即可将该类变成一个单例类
注意:object 关键字不能与 companion object 同时存在
// 单例类
object StaticMethodTest {
fun doAction() {
println("do action")
}
}
class Test {
fun main() {
StaticMethodTest.doAction()
}
}
3.3 @JvmStatic
若想真正的定义静态方法,Kotlin为我们提供了两种方式:注解和顶层方法
先来讲讲注解,前面的单例类与伴生类调用方法的语法形式上模仿了静态方法的调用方式,但其并不是真正的静态方法,为此我们可以在单例类或者伴生类的方法上加个@JvmStatic注解,那么Kotlin编译器就会将该方法变成真正的静态方法
// 单例类
object ObjectMethodTest {
@JvmStatic
fun doAction() {
println("do action1")
}
}
class CompanionObjectTest {
companion object {
@JvmStatic
fun doAction() {
println("do action2")
}
}
}
class Test {
fun main() {
// 调用单例类中的静态方法
ObjectMethodTest.doAction()
// 调用伴生类中的静态方法
CompanionObjectTest.doAction()
}
}
3.4 顶层方法
顶层方法是指那些没有定义在任何类中的方法,在编写的时候,我们需要创建一个新的Kotlin File/Class文件,但其需要选择File文件
Kotlin编译器会将所有的顶层方法全部编译成静态方法,因此只要定义了顶层方法,那么其就是静态方法
定义了顶层方法后,调用方式就跟调用静态方法一样:
// 在Kotlin中
class Test {
fun main() {
// 调用顶层方法(TopStaticMethod.kt)
doAction()
}
}
// 在JAVA中
public class Main {
public static void main(String[] args) {
// 调用Kotlin顶层方法
// Kotlin文件名叫做TopStaticMethod,Kotlin编译器会自动创建一个叫做TopStaticMethodKt类
// 在JAVA中调用Kotlin顶层方法时,就可像调用静态方法的方式调用
TopStaticMethodKt.doAction();
}
}
4. 扩展函数
什么是扩展函数?扩展函数是即使不修改某个类的源码情况下,仍然可以打开这个类,并可以向该类添加新的函数
例如给定一串字符串,里面各种字符都有,而我们需要写个函数,从该字符串中删除除了英文字母之外的字符,得到一个新的字符串,通过我们会写个工作类,然后写个静态方法,调用其静态方法实现;但在Kotlin中,其支持我们向String类中添加一个扩展函数,在使用的时候,即可直接调用其方法实现
首先,编写扩展函数的时候,我们需要创建一个File文件,类似顶层方法的写法,文件名建议尽量与被扩展的类的类名一致
其次,定义扩展函数的时候,需要在方法名前加上被扩展的类名,例如String类
此时,定义完String扩展函数后,那么函数中就拥有了该String实例的上下文,因此该函数就不需要接收一个字符串参数了,而是直接遍历this即可,因为现在this代表着字符串本身
// 在String.kt文件中定义
fun String.filterChar(): String {
val sb = StringBuilder()
for (char in this) {
if (char.isLetter()) {
sb.append(char)
}
}
return sb.toString()
}
// 在main方法中使用
fun main(args: Array<String>) {
println("123abcde456".filterChar())
// 打印结果为:abcde
}
5. 运算符重载
在Kotlin中,允许我们对运算符进行重载,运算符重载使用的是operator关键字,只要在指定函数前面加上operator关键字,就可以实现运算符重载的功能,例如我们对String类的times()方法进行重载,实现重复打印n次
步骤与扩展函数编写类似
首先,创建一个File文件,定义一个扩展函数,该函数即是times(),并在该方法前加上operator的关键字修饰
随后,在main函数中,直接通过调用.times(n)方式直接调用
// 在String.kt文件中,定义一个扩展函数,并也是运算符*对应的函数
operator fun String.times(count: Int) = repeat(count)
// 在main方法中调用
fun main(args: Array<String>) {
println("abc".times(3))
// 打印结果为:abcabcabc
}