我想告诉你一个名为Kotlin的新编程语言,以及为什么你应该为你的下一个项目考虑它。我曾经更喜欢Java,但去年我发现自己只要能够编写Kotlin,在这一点上我真的想不出Java会是一个更好的选择。
它是由JetBrains开发的,事实上这些是IDE套件背后的人,比如IntelliJ和ReSharper, 在Kotlin中真的很闪亮。它实用而简洁,使编码成为令人满意和高效的体验。
虽然Kotlin编译了JavaScript和很快的机器代码,但我将专注于它的主要环境,即JVM。
所以这里有几个原因你应该完全切换到Kotlin(没有特别的顺序):
0 # Java互操作性
Kotlin与Java可以100%互操作。使用Kotlin的时候我们可以继续使用老的Java库。你喜欢用的java第三方框架在kotlin项目中仍然可用,而且用kotlin写的框架同样可以用在Java项目中
1# 熟悉的语法
Kotlin并不是学术界的奇怪语言。任何来自面向对象编程的程序员都熟悉它的语法,并且可以从一开始就或多或少地理解它。当然,与Java有一些不同之处,例如重写的构造函数或val var变量声明。下面的代码段介绍了大部分基础知识
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# 字符串插值
就好像String.format(),在Kotlin中内置了一个更智能,更易读的字符串格式化功能
val x = 4 val y =7 print("$x 和$y的总和是$(x+y)") // 4 和7的总和是11
3# 类型推断
Kotlin会在您认为可以提高可读性的地方推断您的类型:
val a =“abc”//类型推断为String val b = 4 //类型推断为Int val c:Double = 0.7 //明确声明类型 val d:List <String> = ArrayList()//明确声明类型 • 1 • 2 • 3 • 4
4# 智能类型转换
如果可能,Kotlin编译器会跟踪您的逻辑和自动转换类型。这意味着您不用在做instanceof判断之后做显示的类型转换
if(obj is String){ print(obj.toUpperCase())//这里不用做显示类型转换 } • 1 • 2 • 3
5# == 和 ===
== 等效于java中的equals(),=== 等效于java中的 ==
val john1 = Person("John") val john2 = Person("John") john1 == john2 // true (structural equality) john1 === john2 // false (referential equality) • 1 • 2 • 3 • 4
6# 默认参数
方法有多个不同参数版本的时候,不需要定义多个重载函数
fun build(title: String,width: Int = 800,height: Int =600){ Frame(title,width,height) } • 1 • 2 • 3
7#命名参数
结合默认参数,命名参数消除了对构建器的需求:
build("PacMan", 400, 300) // equivalent build(title = "PacMan", width = 400, height = 300) // equivalent build(width = 400, height = 300, title = "PacMan") // equivalent • 1 • 2 • 3
8# When 表达式
使用when表达式代替switch
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 -> println("x is out of range") } • 1 • 2 • 3 • 4 • 5 • 6 • 7
而且when表达式可以赋值给变量
val res: Boolean = when { obj == null -> false obj is String -> true else -> throw IllegalStateException() } • 1 • 2 • 3 • 4 • 5
9# 属性
自定义的set和get方法可以添加到public字段,这意味着我们可以通过隐式的getter和setter来避免臃肿的代码
class Frame{ var width: Int = 800 var height: Int =600 val pixels: Int get () = width*height } • 1 • 2 • 3 • 4 • 5 • 6
10# 数据类
使用java编写一个POJO,需要重写getter和setter,toString,equals等方法,在Kotlin中实现类似的功能十分简洁
data Persron(val name: String,var email: String,var age: Int) val john = Person("John","john@gmail.com",24) • 1 • 2
11# 运算符重载
可以重载预定义的一组运算符提高可读性
data 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) • 1 • 2 • 3 • 4
12# 解构声明
一些对象可以被解构,特别是在遍历map的时候有用
for((key, value) in map){ print("Key: $key Value: $value") } • 1 • 2 • 3
13# 范围
可读性秒杀java
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) { ... } • 1 • 2 • 3 • 4 • 5
14# 扩展函数
还记得你第一次使用java给List排序吗?在List中你找不到sort方法。然后你不得不通过google学习Collections.sort()。
如果只有一种方法可以向旧类添加新函数; 这样您的IDE可以帮助您在代码完成中找到正确的功能。在Kotlin你可以做到这一点:
fun String.replaceSpaces(): String { return this.replace('','_') } val formatted = str.replaceSpaces() • 1 • 2 • 3 • 4 • 5
15# 空指针安全
在java中如果一个引用指向null,在使用该引用时可能会抛出NullPointException。在Kotlin中将引用分为两种非空类型和可空类型。默认的就是非空类型,可空类型在类型后面添加?
var a: String = "abc"//默认非空类型 a = null //编译报错 var b:String? = "xyz"//可空类型 b = null //没问题 • 1 • 2 • 3 • 4 • 5
无论何时访问可空类型,Kotlin都会强制您防范NPE:
val x = b.length //编译错误:b可能为null • 1
虽然这看起来很麻烦,但由于它的一些功能,它真的很轻松。我们仍然有智能强制转换,它会尽可能地将可空类型转换为非null:
if(b == null)return val x = b.length //没问题 • 1 • 2
我们也可以使用安全调用?.,其值为null而不是抛出NPE
val x = b?.length // x的类型是可以为空的Int • 1 • 2
安全调用可以链接在一起,以避免我们有时用其他语言编写的嵌套if-not-null检查,如果我们想要一个默认值,null我们可以使用elvis运算符?::
val name = ship?.captain?.name?:“unknown” • 1 • 2
如果这些都不适合您,并且您绝对需要NPE,则必须明确要求:
val x = b?.length?:throw NullPointerException()//与下面相同 val x = b!!.length //与上面相同 • 1 • 2
16# 更好的Lambdas
在可读性和简洁性之间完美平衡,这得益于一些聪明的设计选择。语法首先是直截了当的
val sum = {x:Int,y:Int - > x + y} // type:(Int,Int) - > Int val res = sum(4,7)// res == 11 • 1 • 2
这里有聪明的一点:
- 如果lambda是方法的最后一个或唯一参数,则可以移动或省略方法括号。
- 如果我们选择不声明单个参数-lambda的参数,它将在名称下隐式声明it。
这些事实相结合,使以下三行等效:
numbers.filter({x - > x.isPrime()}) numbers.filter {x - > x.isPrime()} numbers.filter {it.isPrime()} • 1 • 2 • 3 • 4
这使我们能够编写简洁的功能代码
persons .filter {it.age> = 18} .sortedBy {it.name} .map {it.email} .forEach {print(it)}