2.4.1 表达式比语句更安全 2021-07-12

我们先来写一段Java代码。刚开始我们还是采用熟悉的if语句用法:

void ifStatement(Boolean flag){

String a = null

if(flag){

a = "dive into kotlin";

}

System.out.printlin(a.toUpperCase);

}

非常简单的代码,由于if在这里不是一个表达式,所以我们只能够在外部对变量a进行声明。仔细思考一下,这段代码存在潜在的问题:

1. a必须在if语句外部声明,它被初始化为null。这里的if语句的作用就是对a进行赋值,这是一个副作用。在这个例子中,我们忽略了else分支,如果flag的条件判断永远为true,那么程序运行并不会出错;否则,将会出现“java.lang.NullPointerException”的错误,即使程序依旧会编译通过。因此,这种语句创建副作用的方式很容易引发Bug。

2. 继续思考,现在的逻辑虽然简单,然而如果变量a来自上下文其他更远的地方,那么这种危险会更加容易被忽略。典型的例子就是一段并发控制的程序,业务开发会变得非常不安全。

接下来,我们再来创建一个Kotlin的版本,现在if会被作为表达式使用:

fun isExpression(flag: Boolean){

      val a = if(flag) "dive into Kotlin"  else  ""

      println(a.toUpperCrase())

}

下面分析Kotlin的版本:

1. 表达式让代码变得更加紧凑了。我们可以把赋值语句与if表达式混合使用,就不存在变量a没有初始值的情况。

2. 在if作为表达式时,else分支也必须被考虑,这很容易理解,因为表达式具备类型信息,最总它的类型就是if,else多个分支类型的相同类型或公共父类型。

可以看出,基于表达式的方案彻底消除了副作用,让程序变得更加安全。当然,这并不是说表达式不会有副作用,实际上我们当然可以用表达式写出带有副作用的语句,就像这样子:

val a = 1

fun foo() = if(a>0){

a= 2//副作用,a的值变化了

a

}else 0

然而从设计角度而言,语句的作用就是服务于创建副作用的,相比较表达式的目的则是为了创造新值。在函数式编程中,原则上表达式是不允许包含副作用的。

--------------------------------

一切皆表达式

撇开Haskell不谈,在一些极力支持函数式编程的语言中,比如Scala和F#,即使它们不是纯函数式语言,也都实现了一个特性,即一切皆表达式。一切皆表达式的设计让开发者在设计业务时,促进了为了避免创造副作用的逻辑设计,从而让程序变得更加安全。

-----------------

由于把百分之百兼容Java作为设计目标,Kotlin并没有采纳一切皆表达式的设计,然而它在Java的基础上也在很大程度上增强了这一点。正如另一个接下来要提及的例子,就是Kotlin中的函数。与Java的函数不同,Kotlin中所有的函数调用也都是表达式。

你可能感兴趣的:(2.4.1 表达式比语句更安全 2021-07-12)