【函数声明】

可见性修饰符 关键字 函数名称 (参数列表) : 返回值类型 {函数体}

  • 用于创建类实例的工厂函数可以与抽象返回类型具有相同的名称。
public fun getNum(x:Int, y:Int): Int{
    return x + y
}

//工厂函数
interface Foo
class FooImpl : Foo
fun Foo(): Foo = FooImpl()

【返回值类型】

关键字

说明

Unit

返回值无类型。不显示声明返回值类型都会返回Unit类型,类似Java中void用法

Nothing

没有返回值。函数不return会执行失败(抛异常),异常就是 Nothing 类型

Any

所有类型的父类。提供了 equals()、hashCode()、toString()

//没有返回值类型返回的是Unit,可不写
fun show(name: String): Unit { print("...") }    //fun show(name: String) { print("...") }

fun fail(message:String):Nothing{
    throw IllegalStateException(message)
}

public inline fun TODO(reason: String) : Nothing = throw NotImplementedError("An operation is not implemented :$reason")

【默认参数值】(函数重载)

可以预先给参数指定默认值(缺省值),不必像 Java 那样写一大串重载函数。

fun getStudent(age: Int, sex: String = woman){
    println("年龄:$age,性别:$sex")
}

getStudent(18, man)    //打印:年龄:18,性别man,传入会覆盖默认值
getStudent(20)         //打印:年龄:20,性别woman,不传入使用默认值

上面函数在Java中调用只相当于提供了:

void getStudent(int age,String name){}

如果过想在Java中也当作重载函数使用,需要使用 @JvmOverloads 注解来修饰函数,同样适用于构造函数和静态函数。而如果一个函数不想被Java调用 则使用 @JvmSynthetic。

@JvmOverloads
fun getStudent(age: Int, sex: String = woman){
    println("年龄:$age,性别:$sex")
}

 上面函数在Java中调用相当于提供了:

void getStudent(int age){}
void getStudent(int age,String name){}

【具名参数】(命名参数)

在传递参数的时候,指定参数的名称。这样做的好处就是可以不必按照参数的顺序去传值,参数特别多的时候,它们都很像容易传错。(一旦其中有一个参数使用了命名传参,它前面的不用管(当然是按照参数列表顺序赋值的不然报错),它后面的所有参数都要使用命名传参)。

fun getStudent(name: String, age: Int) {
    println("姓名$name,年龄$age")
}

getStudent(age = 10, name = "张三")    //打印:姓名张三,年龄10

【单表达式函数】

函数返回单个表达式时,返回值类型自动推断可以不写,可以省略 return 使用 = 赋值为表达式结果。

//返回值类型可以不写,自动推断
fun getNum(x:Int, y:Int) = x + y
fun getName(name: String) = println("名字是:$name")


//可以直接 return 表达式的结果
fun generateAnswerString(countThreshold: Int): String {
    return if (count > countThreshold) {
        "I have the answer."
    } else {
        "The answer eludes me."
    }
}

//还可以将 return 关键字替换为赋值运算符
fun generateAnswerString(countThreshold: Int): String = if (count > countThreshold) {
        "I have the answer"
    } else {
        "The answer eludes me"
    }

【可变参数】(变长参数)

函数的参数数量不确定,Java 通过三个点表示(String...str),Kotlin 通过关键字 vararg 修饰,表示该类型的数量可变,通常应该把它放在参数列表的最后一个。

//Java
void method(String name, Int...scores){}

//Kotlin
fun method(name: String, vararg scores: Int) {
    var scoreString = scores.joinToString(",")    //可变参数在函数体中自动变为数组类型使用
    println("姓名:$name, 得分:$scoreString")
}

//使用
val scores = intArrayOf(5,1,6,4)
//Kotlin中需要使用展开运算符 *, 表示将数组中的元素逐个传入到变长参数中(Java可直接传数组)
method("张三",*scores)    //打印: 姓名:张三, 得分:5,1,6,4

【参数泛型】
更详细介绍参见这篇笔记《Kotlin - < >泛型》

fun <T> show(t: T){ return t}

【反引号中的函数名】

  • 解决关键字冲突:Kotlin 和 Java 各自有不同的保留关键字
  • 强行将一个不合法名称变得合法:做测试的时候也能使用空格和特殊符号命名函数(空格无法用于 Android 项目)
//使用特殊符号和空格
fun `**This is a test for function Show()**`(){
    println("哈哈哈")
}

//使用数字开头命名
fun `123`(){}

//Kotlin调用Java中名称为is()的函数

MyJava.`is`()

【局部函数】(内部函数)

函数内部也可以定义函数。局部函数可以直接访问外部函数的局部变量、常量。

fun outer(){
    val a = 3
    val b = 3
    fun inner(){
        println("结果是: + $a + $b")
    }
}

【成员函数】(方法)

方法和函数几乎一模一样,唯一的区别是必须声明在类里面。方法必须通过类的实例调用,每个方法可以在方法内部拿到这个方法的实例。

fun eat() = Unit    //函数

class Person{
    fun eat() = Unit    //方法
}

【空函数】

强制要求重载但又不需要使用的函数

override fun aaa(a: Int) = Unit