為什麽您應該從Java完全切換到Kotlin
是時候開始使用現代編程語言了!
我想介紹一種新的編程語言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代碼膨脹。
#10Data Class
這是一個POJO,帶有toString()
,equals()
,hashCode()
和copy()
,與Java不同的是,它非常簡介而不會占用上100行代碼:
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解構聲明
某些對象可以被解構,例如對於迭代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")
#15Null安全
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代碼時,便會彈出此內容:
到此為止。感謝您的閱讀!