语句(statement)和表达式(expression)是常常被错误理解的两个重要术语。我们从解释表达式这个术语开始。
表达式(Expression)
在 Kotlin 社区,表达式术语通常和 kotlin 的单表达式函数(single-expression functions)联系在一起:
fun bigger(a: Int, b: Int) = if(a > b) a else b
考虑到这一点,我们应该直观地知道什么是表达式。 问题是,直觉可能会误导我们。 让我们从一个常见的定义开始:
在编程语言中,表达式是一个或者多个显示的值、常量、变量操作数和函数的组合,编程语言能够理解并计算产生另外一个值。
所以 1 + 1
是一个表达式,这和 sumOf(1, 2, 3)
是一样的。注意一个表达式可以包含另外一个表达式。例如,表达式 sumOf(1, 2*3)
包含表达式 2*3
。表达式是代码(会返回值的代码)的每一部分。注意在 Kotlin 中,每一个函数都会至少返回 Unit
,所以每一个函数调用都是一个表达式。那是否意味着所有一切都是表达式?绝对不是!这里有几个示例:
- 变量声明不是表达式(
val a = 10
) - 在 kotlin 中变量或者属性赋值不是表达式(
a = 10
) - 类声明不是表达式(
class A {}
)
它们都不是表达式,但是它们都是语句。
语句(Statement)
我们从另一个常见的定义开始:
在计算机程序中,语句是命令式编程语言的最小独立部件,它描述可被执行的任务。
我觉得这还不是很清晰,所以我还会展示另一个示例。我们来看看下面的代码:
val bestUser = users.filter { it.passing }
.maxBy { it.meanScore }
println("${bestUser.name} ${bestUser.surname}")
这里我看到了很多表达式,但是只有两个语句。第一个是处理 users
集合并将结果存储到 bestUser
变量。第二个语句是打印这个用户的姓名。最简单的判断方法就是:Java 中以分号结束的代码都是语句。在 Kotlin 中它通常是单行代码,但是我们也可以在一行代码中编写多个语句(如果我们使用分号),我们也可以编写占用多行代码的语句:
val bestUsers = users.filter { it.passing }
.sortedBy { -it.meanScore }
.take(10)
print("The best students are: "); println(bestUsers.joinToString());
这里有3个语句。第一个是处理 users
以获得最好的用户,第二个是打印 “The best students are: ”,第三个是打印 bestUsers 拼接出来的一个字符串。
注意单个表达式同时也是语句。就像下面这个 updateUser
函数调用:
updateUser(user)
这样的单个表达式称为表达式语句(expression statement)
。
有趣的现象是在纯函数式编程中没有语句。只有表达式。
为什么要区分它们?
现在当你理解了什么是表达式和语句之后,你会发现当你在图书或者文章中描述代码时是多么的有用。我们一起来看一个例子:
fun showUsers(users: List<User>?) {
users ?: return
val adapters = users.map { UserAdapter(it, ::onUserClicked) }
list.adapter = UserListAdapter(adapters)
}
在上面的代码片段中,我们可以这样描述
showUsers
是怎样定义的。在它的函数体的第一个语句中,检查users
parameter 是否为null
。注意在 Kotlin 中函数参数是只读的(read-only),这一断言将users
转换成一个非空值,其函数的剩余代码中它都不会为 null。所以在第二个语句中,我们可以直接使用而不需要做任何解压。注意我们在通过UserAdapter(it, ::onUserClicked)
表达式将 users 转换成 adapters 时,我们还将onUserClicked
函数作为参数传递。在最后一个语句中,我们将list
的 adapter 指定为一个新创建的UserListAdapter
实例。它包含了为所有 users 创建的 adapters。
注意在描述代码的过程中,语句和表达式帮助我们准确的表达想法。
表达式在 Java 和 Kotlin 中有何不同?
注意,在 Kotlin 和 Java 中表述什么是表达式以及什么不是表达式时,两者有基本的差别。所有的 Kotlin 函数调用都是表达式,因为他们至少会返回 Unit
。调用没有定义任意返回值的 Java 函数时不是表达式。Kotlin 中变量赋值(a = 1
)不是表达式,但是在 Java 中则是,因为这个操作之后会返回被赋予的值(在 Java 中,你可以 a = b = 2
或者 a = 2 * (b = 3))
)。在 Java 中所有的控制结构(if
, switch
) 都不是表达式,而在 Kotlin 中允许 if
, when
, try
返回值:
val bigger = if(a > b) a else b
val color = when {
relax -> GREEN
studyTime -> YELLOW
else -> BLUE
}
val object = try {
gson.fromJson(json)
} catch (e: Throwable) {
null
}