Loading
0

我们与Kotlin的故事:从尝试到放弃

技术小学生微信公众号
腾讯云服务器大促销。
华为服务器

Kotlin 现在很流行,它提供了编译时 null 安全,代码更加简洁。它比 Java 更好,你应该切换到 Kotlin,否则就只能坐以待毙。不过,在转向 Kotlin 之前,请先听听这个故事——在这个故事里,那些稀奇古怪的东西让我们忍无可忍,最后不得不使用 Java 重写整个项目。
 

我们尝试过 Kotlin,但现在开始使用 Java 10 重写代码。
 

我有一组自己最喜欢的 JVM 语言,/main 目录下的 Java 代码和 /test 目录下的 Groovy 代码是我最爱的组合。2017 年夏天,我的团队开始了一个新的微服务项目,和往常一样,我们讨论了要使用什么编程语言和技术。我们想尝试新的东西,所以决定试试 Kotlin。由于在 Kotlin 中找不到可替代 Spock 的测试框架,所以我们决定继续在 /test 目录中使用 Groovy(Spek 不如 Spock 好)。2018 年冬天,在使用 Kotlin 数月之后,我们总结了它的优势和劣势,并得出结论:Kotlin 导致我们生产力下降。于是,我们开始使用 Java 重写这个微服务。
 

原因如下:
 

命名遮蔽(name shadowing)

类型推断

编译时 null 安全

类字面量

反向类型声明

Companion 对象

集合字面量

Maybe 语法

数据类

公开类

陡峭的学习曲线
 

命名遮蔽
 

Kotlin 的命名遮蔽对我来说是个最大的惊喜。比如下面这个函数:
 

fun inc(num : Int) {

val num = 2

if (num > 0) {

val num = 3

}

println ("num: " + num)

}

当你调用 inc(1) 时会打印出什么?在 Kotlin 里,方法参数是按值传递,所以我们不能修改 num 参数。这样的设计是对的,因为方法参数本来就不应该被修改。不过,我们可以用相同的名字定义另一个变量,并将它初始化为任何想要的值。现在,在方法作用域内有两个名为 num 的变量。当然,现在一次只能访问一个 num 变量。所以从根本上说,num 的值被改变了。
 

我们还可以在 if 代码块中添加另一个 num(新的代码块作用域)。
 

在 Kotlin 中,调用 inc(1) 时会打印出 2,而在 Java 中,等效代码无法通过编译:

void inc(int num) {

int num = 2; //error: variable 'num' is already defined in the scope

if (num > 0) {

int num = 3; //error: variable 'num' is already defined in the scope

}

System.out.println ("num: " + num);

}
 

命名遮蔽并非 Kotlin 独有,它在编程语言中是很常见的。在 Java 中,我们习惯用方法参数来遮蔽类字段:
 

public class Shadow {

int val;

public Shadow(int val) {

this.val = val;

}

}

Kotlin 中的命名遮蔽做得有点过了,这绝对是 Kotlin 团队的一个设计缺陷。IDEA 团队试图通过为每个被遮蔽的变量显示警告(“Name shadowed”)来解决此问题。两个团队都属于同一家公司,或许他们可以就遮蔽问题达成共识?我认为,IDEA 团队是对的,因为我想象不出遮蔽方法参数有什么用处。
 

类型推断
 

在 Kotlin 中,在使用 var 或 val 声明变量时,通常会让编译器根据右边的表达式猜出变量类型。我们称之为局部变量类型推断,这对程序员来说是一个很大的改进,我们因此可以在不影响静态类型检查的情况下简化代码。
 

例如,这行 Kotlin 代码:

var a = "10"

将由 Kotlin 编译器翻译成:

var a : String = "10"

这是 Kotlin 曾经比 Java 真正好的地方。我故意说“曾经”,那是因为 Java 10 现在也有了局部变量类型推断。
 

Java 10 中的类型推断:

var a = "10";
 

为了公平起见,我需要补充一点,Kotlin 在这方面仍然略胜一筹,因为在 Kotlin 中,可以在其他上下文中使用类型推断,例如,单行代码方法。
 

编译时 null 安全
 

null 安全类型是 Kotlin 的杀手级特性。在 Kotlin 中,类型默认是不可空的。如果你需要一个可空类型,需要添加?,例如:
 

val a: String? = null      // ok

val b: String = null       // compilation error
 

如果使用不带空值检查的可空变量,将无法通过编译,例如:
 

println (a.length)          // compilation error

println (a?.length)         // fine, prints null

println (a?.length ?: 0)    // fine, prints 0
 

一旦使用了这两种类型,不可空的 T 和可空的 T?,那么就可以避免出现 Java 中最常见的异常——NullPointerException。真的吗?事情并没有那么简单。
 

技术小学生微信公众号
华为服务器
腾讯云服务器大促销。

声明:站长码字很辛苦啊,转载时请保留本声明及附带文章链接:https://blog.tag.gg/showinfo-36-23739-0.html
亲爱的:若该文章解决了您的问题,可否收藏+评论+分享呢?
上一篇:搜客盒子:网站服务器IIS日志存储位置及其参数详解
下一篇:SEO竞争学习研究的原因、因素及目的