是时候开始使用现代编程语言了!
我想介绍一种新的编程语言 Kotlin 以及为什么要在下一个项目中考虑它。我曾经更喜欢Java,但是慢慢发现自己会尽可能地编写Kotlin代码。
Kotlin是由JetBrains开发和维护, 它的务实 和简洁 使编码令人有满意且高效的体验。出于以下一些原因,您可以考虑切换到Kotlin:
#0 与Java的互操作性
Kotlin是100%与Java兼容的,也就是可以用Kotlin和Java混合编程 。您实际上可以使用Kotlin继续旧的Java项目上的工作。所有你喜欢的Java框架仍然可用 ,且无论您是用Kotlin编写的任何框架,都容易被您的Java朋友所采用。
#1 熟悉的语法
Kotlin不是学术界出生的怪异语言。它的语法对于来自面向对象领域的程序员来说都会比较熟悉。当然有一些 与Java的差异,例如重新构造的构造函数或val/
var
变量声明。下面的代码段介绍了大多数基础知识:
class Foo {
val b: String = "b" // val means unmodifiable
var i: Int = 0 // var means modifiable
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}") // sum of 4 and 7 is 11
#3 类型推断
Kotlin会在可提高可读性的任何地方推断您的类型:
val a = "abc" // type inferred to String
val b = 4 // type inferred to Int
val c: Double = 0.7 // type declared explicitly
val d: List = ArrayList() // type declared explicitly
#4智能Cast
Kotlin编译器会跟踪您的逻辑并自动cast类型(如果可能) ,这意味着不再需要用instanceof
检查后进行显式强制转换:
if (obj is String) {
print(obj.toUpperCase()) // obj is now known to be a String
}
#5相等判断
你可以停止显示调用equals()
,因为==
操作现在可以直接检查结构是否相等:
val john1 = Person("John")
val john2 = Person("John")
john1 == john2 // true (structural equality)
john1 === john2 // false (referential equality)
#6默认参数
无需使用不同的参数定义几种类似的方法:
fun build(title: String, width: Int = 800, height: Int = 600) {
Frame(title, width, height)
}
#7命名参数
与默认参数结合使用时,命名参数消除了对Builder的需要:
build("PacMan", 400, 300) // equivalent
build(title = "PacMan", width = 400, height = 300) // equivalent
build(width = 400, height = 300, title = "PacMan") // equivalent
#8when表达式
switch被更具可读性和灵活性的when 表达式取代:
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可以将行为添加到公共字段中,这意味着我们可以停止漫不经心的getters & setters代码膨胀。
#10 Data Class
这是一个POJO,带有toString()
,equals()
,hashCode()
和copy()
,与Java不同的是,它非常简介而不会占用上100行代码:
data class Person(val name: String,
var email: String,
var age: Int)
val john = Person("John", "[email protected] ", 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解构声明
某些对象可以被解构,例如对于迭代Map很有用:
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.replaceSpaces(): String {
return this.replace(' ', '_')
}
val formatted = str.replaceSpaces()
标准库扩展了Java原始类型的功能,这对于String
非常有必要:
str.removeSuffix(".txt")
str.capitalize()
str.substringAfterLast("/")
str.replaceAfter(":", "classified")
#15 Null安全
Java是我们应该称之为的几乎 静态类型的语言。JAVA中,一个String
类型变量是不保证的 一定指向一个String
-它可能是指null
。即使我们已经习惯了它,但它否定了静态类型检查的安全性,因此Java开发人员不得不时刻小心NPE(Null Pointer Exception)。
Kotlin通过区分非空类型 和可为空的类型 解决这个问题。类型默认情况下为非null,并且可以通过添加一个?
来允许空值,像这样:
var a: String = "abc"
a = null // compile error
var b: String? = "xyz"
b = null // no problem
每当您访问可为空的类型时,Kotlin在编译时会强制报错防止NPE:
val x = b.length // compile error: b might be null
尽管这看起来很麻烦,但由于Kotlin的一些智能功能,可以轻易搞定——因为有智能的类型转换,它会尽可能将可空类型转换为非空类型:
if (b == null) return
val x = b.length // no problem
我们也可以使用安全的调用?.
,其结果可为null而不抛出NPE:
val x = b.length // compile error: b might be null
可以将安全调用链接在一起,以避免我们在其他语言有时会遇到的编写嵌套if-not-null检查的问题。另外如果我们需要默认值而不是null
,我们可以使用三目运算符?:
:
val name = ship?.captain?.name ?: "unknown"
如果这些都不适合您,并且您确实需要NPE,则必须明确要求:
val x = b?.length ?: throw NullPointerException() // same as below
val x = b!!.length // same as above
#16 更好的Lambda
Kotlin有一个很好的lambda系统-由于一些聪明的设计选择,在可读性和简洁性之间达到了完美的平衡。首先语法是一目了然的:
val sum = { x: Int, y: Int -> x + y } // type: (Int, Int) -> Int
val res = sum(4,7) // res == 11
这里有一些聪明的地方:
如果lambda是方法的最后一个或唯一的参数,则可以移动或省略方法的圆括号。
如果我们选择不声明单参数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创建。查看 Anko 以旨在增强Android开发的DSL为例:
verticalLayout {
padding = dip(30)
editText {
hint = “Name”
textSize = 24f
}
editText {
hint = “Password”
textSize = 24f
}
button(“Login”) {
textSize = 26f
}
}
#17IDE支持
如果您打算开始使用Kotlin,可以有很多选择,但是我强烈建议您使用IntelliJ , 这个IDE直接与Kotlin捆绑在一起 -其功能展示了由同一个人设计语言和IDE的优势。
仅举一个小巧而巧妙的例子,当我第一次尝试从Stack Overflow复制粘贴一些Java代码时,便会弹出此内容:
IntelliJ将通知您是否将Java代码粘贴到Kotlin文件中