为什么你必须摒弃 Java ,全面转向 Kotlin 语言?
tsejen129
7年前
<h2>是时候开始玩一门现代的编程语言了!</h2> <h2><img src="https://simg.open-open.com/show/d22fafd1d4c10cafa82024d61f577d27.jpg"></h2> <p>我想告诉你一个名为 Kotlin 的新的编程语言,以及为什么你要开始考虑使用它来开发你的下一个项目。我以前喜欢 Java ,但是去年我发现了 Kotlin ,只要有可能我就会用 Kotlin 来写代码。现在我实在无法想象有什么地方只有 Java 能做,而 Kotlin 不能的。</p> <p>Kotlin 是 <strong> <a href="/misc/goto?guid=4958878434256659014" rel="nofollow,noindex">JetBrains</a> </strong> 开发的,这是一家开发了一整套 <a href="/misc/goto?guid=4959749544978156965" rel="nofollow,noindex">IDEs</a> 的公司,诸如 <strong>IntelliJ </strong> 和 <strong>ReSharper</strong> , 还有正在闪耀光芒的 Kotlin。这是一个务实而且简洁的编程语言,真正让人感觉身心愉悦的编程语言,而且效率非常高。</p> <p>尽管 Kotlin 最终编译成 <a href="/misc/goto?guid=4959749545081058530" rel="nofollow,noindex"> <strong>JavaScript</strong> </a> ,很快也将编译成 <strong> <a href="/misc/goto?guid=4959749545158458327" rel="nofollow,noindex">机器码</a> , </strong> 但我们仍将聚焦于其主要的环境 —— JVM。</p> <p>这里有一堆你应该完全转向 Kotlin 语言的理由:</p> <h2>0# <a href="/misc/goto?guid=4958988011971845413" rel="nofollow,noindex">Java 互操作性</a></h2> <p>Kotlin <strong> </strong> 是 <strong>100% 与 Java 具备互操作性的。</strong> 你可以使用 Kotlin 继续你老的 Java 项目开发。所有你熟悉的 Java 框架仍然可用,任何框架,不管是 Kotlin 写的,还是你固执 Java 小伙伴写的都可以。</p> <h2>1# <a href="/misc/goto?guid=4959749545275348071" rel="nofollow,noindex"> <strong>熟悉的语法</strong> </a></h2> <p>Kotlin 不是诞生于学术界的怪异语言。其语法是 OOP 领域的任何开发者都熟悉的,可以或多或少的有一些了解。当然和 Java 还是有些不同的,例如重构后的构造函数以及使用 val 的变量声明等等。下面是一个基本的 Kotlin 示例代码:</p> <pre> <code class="language-kotlin">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 }</code></pre> <h2>2# <a href="/misc/goto?guid=4959749545363667784" rel="nofollow,noindex"> <strong>字符串插值</strong> </a></h2> <p>这相当于是更智能,更具备可读性的 Java 的 String.format() 方法的 Kotlin 实现:</p> <pre> <code class="language-kotlin"><strong>val</strong> x = 4 <strong>val</strong> y = 7 <em>print</em>("sum of $x and $y is ${x + y}") // sum of 4 and 7 is 11</code></pre> <h2>3# <a href="/misc/goto?guid=4959749545442433682" rel="nofollow,noindex">类型推断</a></h2> <p>Kotlin 会自动的对变量的类型进行推断:</p> <pre> <code class="language-kotlin"><strong>val</strong> a = "abc" // type inferred to String <strong>val</strong> b = 4 // type inferred to Int <strong>val</strong> c: Double = 0.7 // type declared explicitly <strong>val</strong> d: List<String> = ArrayList() // type declared explicitly</code></pre> <h2>4# <a href="/misc/goto?guid=4959749545532800322" rel="nofollow,noindex">智能类型转换</a></h2> <p>Kotlin 编译器会跟踪你的逻辑代码并在需要的时候进行自动的类型转换,这意味着我们不需要在显示转换时做更多的 instanceof 检查:</p> <pre> <code class="language-kotlin"><strong>if</strong> (obj <strong>is</strong> String) { <em>print</em>(obj.<em>toUpperCase</em>()) // obj is now known to be a String }</code></pre> <h2>5# <a href="/misc/goto?guid=4959749545614202457" rel="nofollow,noindex">更直观的相等性比较</a></h2> <p>你不再需要调用 equals() ,因为 == 操作符也可以用来比较结构的相等性:</p> <pre> <code class="language-kotlin">val john1 = Person("John") val john2 = Person("John")</code></pre> <pre> <code class="language-kotlin">john1 == john2 // true (structural equality) john1 === john2 // false (referential equality)</code></pre> <h2>6# <a href="/misc/goto?guid=4959749545702541819" rel="nofollow,noindex">默认参数值</a></h2> <p>不需要像 Java 那样定义很多包含不同参数的相似方法:</p> <pre> <code class="language-kotlin"><strong>fun</strong> build(title: String, width: Int = 800, height: Int = 600) { Frame(title, width, height) }</code></pre> <h2>7# <a href="/misc/goto?guid=4959749545788989610" rel="nofollow,noindex">命名参数</a></h2> <p>结合默认参数值,命名参数可以消除 <a href="/misc/goto?guid=4958973079202819638" rel="nofollow,noindex">builders</a> 的使用: </p> <pre> <code class="language-kotlin">build("PacMan", 400, 300) // equivalent build(title = "PacMan", width = 400, height = 300) // equivalent build(width = 400, height = 300, title = "PacMan") // equivalent</code></pre> <h2>8# <a href="/misc/goto?guid=4959749545909282530" rel="nofollow,noindex">When 表达式</a></h2> <p>switch 替换成 when ,代码更具可读性:</p> <pre> <code class="language-kotlin"><strong>when</strong> (x) { 1 -> <em>print</em>("x is 1") 2 -> <em>print</em>("x is 2") 3, 4 -><strong> </strong><em>print</em>("x is 3 or 4") <strong>in</strong> 5..10 -> <em>print</em>("x is 5, 6, 7, 8, 9, or 10") <strong>else</strong> -> <em>print</em>("x is out of range") }</code></pre> <p>支持表达式或者是语句,可以是有参数或者无参数:</p> <pre> <code class="language-kotlin"><strong>val</strong> res: Boolean = <strong>when</strong> { obj == <strong>null</strong> -> false obj <strong>is</strong> String -> true <strong>else</strong> -> <strong>throw</strong> IllegalStateException() }</code></pre> <h2>9# <a href="/misc/goto?guid=4959749546008803756" rel="nofollow,noindex"> <strong>Properties</strong> </a></h2> <p>可以给公共字段自定义 set 和 get 行为,这意味着不再会因为那些没用的 <a href="/misc/goto?guid=4959749546111624525" rel="nofollow,noindex">getters & setters</a> 导致代码疯狂膨胀。</p> <pre> <code class="language-kotlin"><strong>class </strong>Frame { <strong>var</strong> width: Int = 800 <strong>var </strong>height: Int = 600 <strong>val </strong>pixels: Int <strong>get</strong>() = width * height }</code></pre> <h2>10# <a href="/misc/goto?guid=4958988011619585828" rel="nofollow,noindex"> <strong>Data 类</strong> </a></h2> <p>这是一个 POJO 类,包含 toString() , equals() , hashCode() , 和 copy() 方法,和 Java 不同的是,它不会超过 100 行代码:</p> <pre> <code class="language-kotlin"><strong>data class</strong> Person(<strong>val</strong> name: String, <strong>var</strong> email: String, <strong>var</strong> age: Int) <strong>val</strong> john = Person("John", "john@gmail.com", 112)</code></pre> <h2>11# <a href="/misc/goto?guid=4959749546259579055" rel="nofollow,noindex">操作符重载</a></h2> <p>可以重载预定义的一组操作符来提升代码的可读性:</p> <pre> <code class="language-kotlin"><strong>data class</strong> Vec(<strong>val </strong>x: Float, <strong>val </strong>y: Float) { <strong>operator fun</strong> plus(v: Vec) = Vec(x + v.x, y + v.y) } <strong>val </strong>v = Vec(2f, 3f) + Vec(4f, 1f)</code></pre> <h2>12# <a href="/misc/goto?guid=4959749546359787840" rel="nofollow,noindex">解构声明</a></h2> <p>一些对象是可以解构的,一个很有用的例子就是对 Map 进行迭代:</p> <pre> <code class="language-kotlin"><strong>for </strong>((key, value) <strong>in </strong>map) { <em>print</em>("Key: $key") <em>print</em>("Value: $value") }</code></pre> <h2>13# <a href="/misc/goto?guid=4959749546458908032" rel="nofollow,noindex">Ranges</a></h2> <p>完全为了可读性:</p> <pre> <code class="language-kotlin"><strong>for</strong> (i <strong>in</strong> 1..100) { ... } <strong>for</strong> (i <strong>in</strong> 0 until 100) { ... } <strong>for</strong> (i <strong>in</strong> 2..10 step 2) { ... } <strong>for</strong> (i <strong>in</strong> 10 downTo 1) { ... } <strong>if</strong> (x <strong>in</strong> 1..10) { ... }</code></pre> <h2>14# <a href="/misc/goto?guid=4959671725345730315" rel="nofollow,noindex"> <strong>扩展函数</strong> </a></h2> <p>还记得你第一次用 Java 实现一个 List 的排序吗?你找不到一个 sort() 函数,然后你就四处求助,最终找到了 Collections.sort()。后来你需要将一个字符串的首字符变成大写,最终你还是自己写了一个方法来实现,因为你当时还不知道有这么个东西 StringUtils.capitalize() .</p> <p>如果只有一种方法可以向已有的类添加新的函数,这样 IDE 就可以帮助你在代码完成时找到正确的函数。在 Kotlin 里你可以这么做:</p> <pre> <code class="language-kotlin"><strong>fun</strong> String.replaceSpaces(): String { <strong>return</strong> this.<em>replace</em>(' ', '_') } <strong>val </strong>formatted = str.replaceSpaces()</code></pre> <p>标准库扩展了 Java 原来类型的功能,这是字符串对象所需要的:</p> <pre> <code class="language-kotlin">str.<em>removeSuffix</em>(".txt") str.<em>capitalize</em>() str.<em>substringAfterLast</em>("/") str.<em>replaceAfter</em>(":", "classified")</code></pre> <h2>15# <a href="/misc/goto?guid=4959717376395581612" rel="nofollow,noindex"> <strong>Null 安全</strong> </a></h2> <p>Java 是我们应该称之为是一个几乎静态类型的编程语言。Java 的 String 变量类型无法保证它不会等于 null。尽管我们已经习惯了这样的情况,但它否定了静态类型检查的安全性,导致 Java 程序员总是活在各种空指针异常的恐惧中。</p> <p>Kotlin 通过区分非空类型和允许为空类型来解决这个问题。类型默认是不允许为空的,可以通过在后面加一个 ? 问号来表示允许为空,例如:</p> <pre> <code class="language-kotlin"><strong>var</strong> a: String = "abc" a = <strong>null</strong> // 编译错误 <strong>var</strong> b: String? = "xyz" b = <strong>null</strong> // 正确</code></pre> <p>Kotlin 强制你必须在访问一个可为空的类型变量时候必须确保不会发生空指针:</p> <pre> <code class="language-kotlin"><strong>val</strong> x = b.length // 编译错误: b 允许为空</code></pre> <p>虽然看起来有点麻烦,但这的确是 Kotlin 一个微小却又非常重要的特性。我们仍可以使用智能的转换,可以在需要的时候将允许为空的类型转成不允许为空:</p> <pre> <code class="language-kotlin"><strong>if</strong> (b == <strong>null</strong>) <strong>return</strong> <strong>val </strong>x = b.length // 正确</code></pre> <p>我们也可以使用安全调用方法 ?. 该表达式在 b 为空时返回 null,而不是抛出空指针异常:</p> <pre> <code class="language-kotlin"><strong>val </strong>x = b?.length // type of x is nullable Int</code></pre> <p>安全调用可以链接在一起,以避免像其他语言一样存在大量嵌套的 if-not-null 检查,如果我们想要一个默认值而不是 null 时,可以用 ?: 操作符:</p> <pre> <code class="language-kotlin"><strong>val </strong>name = ship?.captain?.name ?: "unknown"</code></pre> <p>如果没有适合你的,那么你应该是需要一个空指针了,你将不得不显式的进行处理:</p> <pre> <code class="language-kotlin"><strong>val </strong>x = b?.length ?: <strong>throw</strong> NullPointerException() // same as below <strong>val </strong>x = b!!.length // same as above</code></pre> <h2>16# <a href="/misc/goto?guid=4959749546627544456" rel="nofollow,noindex">更好的 Lambdas</a></h2> <p>嘿,帅哥,这是一个很好的 Lambda 系统 —— 在完美的可读性和简洁之间取得非常好的平衡,这得益于非常聪明的设计选择。其语法简单直接:</p> <pre> <code class="language-kotlin"><strong>val</strong> sum = { x: Int, y: Int -> x + y } // type: (Int, Int) -> Int <strong>val </strong>res = sum(4,7) // res == 11</code></pre> <p>优点体现在:</p> <ol> <li>如果 lambda 是方法的最后一个参数或者是唯一参数的话,那么方法的括号可以移动或者省略.</li> <li>如果我们选择不去声明单参数的 lambda 表达式的参数,那么 Kotlin 会隐式的将之命名为 it .</li> </ol> <p>结合上述优点,下面的三个不同的语句效果一样:</p> <pre> <code class="language-kotlin">numbers.filter({ x -> x.isPrime() }) numbers.filter { x -> x.isPrime() } numbers.filter { it.isPrime() }</code></pre> <p>这个可以让你编写更加简洁的函数式代码,就像下面这样优雅:</p> <pre> <code class="language-kotlin">persons .filter { it.age >= 18 } .sortedBy { it.name } .map { it.email } .forEach { print(it) }</code></pre> <p>Kotlin 的 lambda 系统和扩展函数结合,可以非常棒的用来开发各种 <a href="/misc/goto?guid=4959638412616651270" rel="nofollow,noindex">DSL</a> 。例如 <a href="/misc/goto?guid=4959668049818350775" rel="nofollow,noindex">Anko</a> 这个 DSL 的例子可以增强 Android 的开发:</p> <p> </p> <p>来自:https://coyee.com/article/12274-why-you-should-totally-switch-to-kotlin</p> <p> </p>