[翻译]为什么你应该完全转向 Kotlin
是时候开始使用现代编程语言了
我想告诉你一种叫做 Kotlin 的新编程语言,以及为什么你应该考虑用它进行你的下一个项目。我曾经更喜欢Java。但是去年,我发现可以在任何时候用Kotlin做我想做的事,我实在想不出Java会是一个更好的选择。
Kotlin是由JetBrains开发的,事实上,正是这些人开发了一整套IDE,正因为有IntelliJ和ReSharper的努力,现在的Kotlin 才会如此闪耀。它务实和简洁的语法,使编程成为一个令人满意和有效的体验。
尽管Kotlin可以编译JavaScript,而且很快能编译机器代码,但我在这里将主要专注于其环境,JVM。
这里是几个你们应该完全转向到Kotlin原因(没有特定的顺序):
0# 与Java的互操作性
Kotlin可以100%与Java进行互操作。你可以在Kotlin中继续使用你在旧Java项目中的代码。所有你喜欢的Java框架仍然可用,你在Kotlin中编写的任何框架都很容易被那些依然顽固的死守在Java阵线的朋友们所采纳。
1# 熟悉Kotlin的语法
Kotlin不像那些在学术界出生的奇怪的语言。其语法对于任何熟练面向对象编程(OOP)的程序员来说都是熟悉的,可以从或多或少的了解并开始使用。当然与Java有些差异,如reworked constructors或者像val和var这样的变量声明方式。下面的代码段展示了 Konlin 大部分的基础语法:
class
Foo {
val b: String = "b" // val 表示固定值
var i: Int =0 // var 表示变量
fun hello() {
val str = "Hello"
print("$str World")
}
fun sum(x: Int, y: Int): Int {
return x + y
}
fun maxOf(a: Float, b: Float) = if (a > b) a else b }
2# 字符串操作
它像是内置到Java语言中更智能和更可读的 String.format()。
val x = 4
val y = 7
print("sum of $x and $y is ${x + y}") // 4 加 7 和为 11
3# 类型判断
Kotlin会推测你输入的变量类型,提高了可读性:
**val**
a = "abc" // 推断变量类型为字符串
val b = 4 // 推断变量类型为 Int
val c: Double = 0.7 // 这里明确的指定变量类型
val d: List<String> = ArrayList() // 同样明确的指明变量类型
4# 智能类型转换
如果可能的话, Kotlin编译器会跟从您的逻辑然后 自动转换类型,这意味着再不用通过 instanceof 明确检查转换后的类型:
if (obj is String) {
print(obj.toUpperCase()) // 现在 obj 是一个字符串
}
5# 更直观的等号
您可以停止显式地调用equals(),因为== 运算符现在能检查结构相等性:
val john1 = Person("John")
val john2 = Person("John")
john1 == john2 //true (结构性相等)
john1 === john2 // false(引用性等于)
6# 默认参数
不需要通过使用不同的参数来定义类似的方法:
fun build(title: String, width: Int = 800, height: Int = 600) {
Frame(title, width, height)
}
7# 参数命名
结合默认参数,参数命名消除了对 构建器的需要 :
build("PacMan", 400, 300) // 等效
build(title = "PacMan", width = 400, height = 300) // 等效
build(width = 400, height = 300, title = "PacMan") // 等效
8# 使用When 表达式
做多个条件判断时 ,switch被替换为更可读和灵活的when表达式 :
when
(x) {
1 -> print("x is 1")
2 -> print("x is 2")
3, 4 -> print("x is 3 or 4")
in 5..10 -> print("x is 5, 6, 7, 8, 9, or 10")
else -> print("x is out of range")
}
它既可用作表达式,也可用作语句,并且参数非必要:
val res: Boolean = when {
obj == null -> false
obj is String -> true
else -> throw IllegalStateException()
}
9# 属性
自定义的 set&get 行为可以添加到公共字段中,这意味着可以通过消除无意义的getter和 setter 防止我们的代码过于臃肿 。
class Frame
{
var width: Int = 800
var height: Int = 600
val pixels: Int
get() = width * height
}
10 # Data 类
这是一个POJO(Plain Old Java Object),他会自动包含toString(), equals(), hashCode()和 copy()方法,与Java不同,它不会占用太多行代码:
data class Person(val name: String,
var email: String,
var age: Int)
val john = Person("John", "john@gmail.com", 112)
11# 运算符重载
可以通过重载一组预定义的运算符以提高代码可读性:
data class Vec(val x: Float, val y: Float) {
operator fun plus(v: Vec) = Vec(x + v.x, y + v.y)
}
val v = Vec(2f, 3f) + Vec(4f, 1f)
12# 解构声明
一些对象可以被解构,这对于迭代 maps 是有用的:
for ((key, value) in map) {
print("Key: $key")
print("Value: $value")
}
13# 范围
为了增强可读性,可以这样写:
for (i in 1..100) { ... }
for (i in 0 until 100) { ... }
for (i in 2..10 step 2) { ... }
for (i in 10 downTo 1) { ... }
if (x in 1..10) { ... }
14# 扩展函数
能记起你第一次在Java中排序List的情形吗?你找不到一个 sort()函数,所以你不得不求助于老师或去谷歌学习 怎样使用Collections.sort()。后来当你必须将一个String类型变量全部转换成大写字母,你最终使用了你自己写的帮助函数,因为你并不知道 StringUtils.capitalize()。
如果存在一种方法可以在旧类中添加新的函数,这样您的IDE可以帮助您在代码补全中找到正确的函数。在Kotlin 中你可以做到这一点:
fun String.format(): String {
return this.replace(' ', '_')
}
val formatted = str.format()
标准库扩展的Java原生类型的功能,也是String特别需要的:
str.removeSuffix(".txt")
str.capitalize()
str.substringAfterLast("/")
str.replaceAfter(":", "classified")
15# Null 安全性
或许我们可以把Java称之为最静态的语言。对它而言 ,一个String类型的变量不能保证一定引用为String - 它可能引用为 null 。即使我们习惯了这一点,但这确实会引起静态类型检查的安全性问题,因此Java程序员在开发过程中总是会担心所谓的NPEs(NullPointerException) 。
Kotlin通过区分 非空类型 和 可空类型 来解决这个问题 。默认情况下,类型为非空。但是可以像这样通过添加一个?来使其可空:
var a: String = "abc"
a = null //编译错误
var b: String? = "xyz"
b = null // 没问题
当您访问可空类型时,Kotlin会强制您防范NPEs:
val x = b.length // 编译错误:b可能为null
虽然这可能看起来很麻烦,但由于这些功能,会大大减少出错几率。我们仍然可以使用智能类型转换,尽可能将可空类型转换为非空值:
if (b == null) return
val x = b.length // 没问题
我们还可以使用安全调用?. ,它使变量可空,而不是抛出NPE:
val x= b?.length // x 是一个可空的 int 类型
安全调用可以结合在一起,以避免我们有时像在其他语言编写的嵌套那样的繁琐的if-not-null检查,如果我们想要一个默认值,而不是 null,我们可以使用 elvis 运算符“?:”:
val name = ship?.captain?.name ?: "unknown"
如果上面没有一个适用于你,而你需要一个NPE,您只能明确要求:
val x = b?.length ?: throw NullPointerException() // 与下面一样
val x = b!!.length // 与上述相同
16# 更好的Lambdas
Kotlin 有一个很好的 lambda 系统 - 多亏一些聪明的设计决策,使它在可读性和简洁性之间完美平衡。语法首先是直截了当的:
val sum = { x: Int, y: Int -> x + y } // type: (Int, Int) -> Int
val res = sum(4, 7) // res == 11
更聪明的一点是:
1.如果是在 lambda 表达式的方法的最后一个参数或唯一的参数,则可以移除或省略方法括号。
2.如果我们选择不声明只有单参数 lambda 的表达式,它将被隐式声明为 “it”。
以上条件相结合,使以下三行表达效果相同:
numbers.filter({x -> x.isPrime() })
numbers.filter { x -> x.isPrime() }
numbers.filter { it.isPrime() }
这使我们能够编写简洁的函数编程风格代码 - 只要看看这有多漂亮:
persons
.filter { it.age >= 18 }
.sortedBy { it.name }
.map { it.email }
.forEach { print(it) }
Kotlin 的 lambda 表达式系统结合扩展功能使其成为创建 DSL(Domain-specificlanguage) 的理想选择 。参考 Anko 作为DSL,旨在增强Android开发的一个例子:
verticalLayout
{
padding = dip(30)
editText {
hint = "Name"
textSize = 24f
}
editText {
hint = "Password"
textSize = 24f
}
button("Login") {
textSize = 26f
}
}
17# IDE 支持
如果你打算开始使用 Kotlin,有多种不同 IDE可供你选择。但是我强烈建议您使用与Kotlin 紧密捆绑在一起的IntelliJ ,它展示了使用同一人设计语言和IDE的优势。
只是给你举一个小而聪明的例子,当我第一次尝试从Stack Overflow中复制粘贴一些Java代码时,这个东西弹出来了:
