Kotlin 與 Java 核心區(qū)別(超詳細(xì)+代碼對(duì)比)
Kotlin 是基于 JVM、完全兼容 Java的現(xiàn)代化編程語(yǔ)言,由 JetBrains 開(kāi)發(fā),2017 年成為 Google 官方推薦的 Android 開(kāi)發(fā)語(yǔ)言,可以直接調(diào)用 Java 代碼,Java 也能調(diào)用 Kotlin 代碼,但語(yǔ)法、設(shè)計(jì)理念、開(kāi)發(fā)效率有巨大差異。
我會(huì)從10 個(gè)核心維度詳細(xì)對(duì)比,每個(gè)點(diǎn)都配Java 代碼 ? Kotlin 代碼示例,新手也能看懂。
一、空安全(最大區(qū)別!Kotlin 從根源避免空指針)
Java 最大的痛點(diǎn):空指針異常(NullPointerException),幾乎所有開(kāi)發(fā)者都踩過(guò)坑。
Kotlin 默認(rèn)區(qū)分可空類型和非空類型,從編譯期就禁止空指針。
Java 代碼(會(huì)報(bào)空指針)
// Java:默認(rèn)所有變量都可以為 null,編譯器不檢查
String name = null;
// 編譯通過(guò),但運(yùn)行直接崩潰:NullPointerException
System.out.println(name.length());
Kotlin 代碼(編譯期直接報(bào)錯(cuò),杜絕空指針)
// 1. 非空類型(默認(rèn)):不能賦值為 null,編譯報(bào)錯(cuò)
var name: String = null // 報(bào)錯(cuò):Null can not be a value of a non-null type String
// 2. 可空類型(必須加 ? 聲明)
var name: String? = null
// 直接調(diào)用會(huì)編譯報(bào)錯(cuò),必須做非空判斷
name.length // 報(bào)錯(cuò):Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver
// 安全調(diào)用:如果為 null,直接返回 null,不崩潰
println(name?.length) // 輸出:null
總結(jié):Kotlin 空安全讓空指針異常幾乎消失,Java 全靠手動(dòng)判空。
二、語(yǔ)法簡(jiǎn)潔度(Kotlin 代碼量少 40%+)
Kotlin 省略了 Java 大量冗余語(yǔ)法:分號(hào)、new 關(guān)鍵字、getter/setter、構(gòu)造方法等。
1. 定義變量
Java
// 必須寫類型、分號(hào)
String name = "張三";
final int age = 20; // 常量
Kotlin
// var 可變變量,val 只讀變量(等價(jià)Java final)
var name = "張三" // 自動(dòng)推導(dǎo)類型,無(wú)需分號(hào)
val age = 20
2. 定義實(shí)體類(Java 10行 = Kotlin 1行)
Java(寫半天 getter/setter/構(gòu)造方法)
public class User {
private String name;
private int age;
// 構(gòu)造方法
public User(String name, int age) {
this.name = name;
this.age = age;
}
// getter/setter
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
}
Kotlin(一行搞定,自動(dòng)生成所有方法)
// 自動(dòng)生成:構(gòu)造方法、getter、setter、equals、toString 等
data class User(val name: String, val age: Int)
總結(jié):Kotlin 大幅減少樣板代碼,開(kāi)發(fā)效率更高。
三、方法定義與 Lambda 表達(dá)式
1. 基礎(chǔ)方法
Java
// 必須寫返回值、修飾符、分號(hào)
public int add(int a, int b) {
return a + b;
}
Kotlin
// 自動(dòng)推導(dǎo)返回值,單表達(dá)式直接省略花括號(hào)和 return
fun add(a: Int, b: Int) = a + b
2. Lambda 簡(jiǎn)化(集合遍歷)
Java
List<Integer> list = Arrays.asList(1,2,3);
// 冗余語(yǔ)法
list.forEach(new Consumer<Integer>() {
@Override
public void accept(Integer i) {
System.out.println(i);
}
});
Kotlin
val list = listOf(1,2,3)
list.forEach { println(it) } // it 代表當(dāng)前元素,極簡(jiǎn)
四、默認(rèn)參數(shù)與具名參數(shù)(Kotlin 獨(dú)有)
Java 沒(méi)有默認(rèn)參數(shù),必須寫方法重載,代碼冗余;Kotlin 直接支持默認(rèn)參數(shù)。
Java(方法重載)
public void printInfo(String name, int age) { ... }
public void printInfo(String name) { printInfo(name, 18); } // 重載
public void printInfo() { printInfo("匿名", 18); } // 重載
Kotlin(默認(rèn)參數(shù))
// 直接給參數(shù)賦默認(rèn)值,調(diào)用時(shí)可傳參也可不傳
fun printInfo(name: String = "匿名", age: Int = 18) {
println("姓名:$name,年齡:$age")
}
// 調(diào)用:自由組合參數(shù)
printInfo() // 輸出:姓名:匿名,年齡:18
printInfo("張三") // 輸出:姓名:張三,年齡:18
printInfo(age = 20) // 具名參數(shù),指定傳哪個(gè)
五、擴(kuò)展函數(shù)(Kotlin 獨(dú)有,超級(jí)實(shí)用)
Kotlin 可以不修改原類,直接給現(xiàn)有類添加新方法;Java 必須繼承類或?qū)懝ぞ哳悺?/p>
示例:給 String 類添加「獲取字?jǐn)?shù)」方法
Java(必須寫工具類)
public class StringUtils {
public static int getWordCount(String str) {
return str.length();
}
}
// 調(diào)用:繁瑣
StringUtils.getWordCount("hello");
Kotlin(直接擴(kuò)展 String 類)
// 給 String 類擴(kuò)展方法,全局可用
fun String.getWordCount() = this.length
// 調(diào)用:像調(diào)用原生方法一樣自然
"hello".getWordCount() // 輸出:5
場(chǎng)景:給系統(tǒng)類、第三方庫(kù)添加功能,無(wú)需繼承,無(wú)侵入性。
六、智能類型轉(zhuǎn)換(Kotlin 獨(dú)有)
Java 判空后必須強(qiáng)制類型轉(zhuǎn)換;Kotlin 編譯器自動(dòng)識(shí)別,無(wú)需強(qiáng)轉(zhuǎn)。
Java
Object obj = "abc";
if (obj instanceof String) {
// 必須手動(dòng)強(qiáng)轉(zhuǎn)
String str = (String) obj;
System.out.println(str.length());
}
Kotlin
val obj: Any = "abc"
if (obj is String) {
// 編譯器自動(dòng)轉(zhuǎn)換為 String,無(wú)需強(qiáng)轉(zhuǎn)
println(obj.length)
}
七、靜態(tài)成員與頂層函數(shù)
Java 用 static 定義靜態(tài)成員;Kotlin 沒(méi)有 static 關(guān)鍵字,用伴生對(duì)象/頂層函數(shù)替代。
Java
public class Utils {
public static void show() {
System.out.println("靜態(tài)方法");
}
}
// 調(diào)用
Utils.show();
Kotlin
// 方式1:伴生對(duì)象(等價(jià)Java static)
class Utils {
companion object {
fun show() = println("伴生對(duì)象方法")
}
}
// 方式2:頂層函數(shù)(直接寫在文件里,全局調(diào)用)
fun show() = println("頂層函數(shù)")
// 調(diào)用(和靜態(tài)方法一樣)
Utils.show()
show()
八、區(qū)間與循環(huán)(Kotlin 更直觀)
Java
// 遍歷 1-10
for (int i = 1; i <= 10; i++) { ... }
Kotlin
// 區(qū)間表達(dá)式:1..10 代表 1到10
for (i in 1..10) { ... }
// 倒序、步長(zhǎng)
for (i in 10 downTo 1 step 2) { ... }
九、異常處理
Java 必須捕獲受檢異常(Checked Exception);Kotlin 取消了受檢異常,更靈活。
Java
// 必須 try-catch 或 throws,否則編譯報(bào)錯(cuò)
public void readFile() throws IOException {
FileReader reader = new FileReader("test.txt");
}
Kotlin
// 無(wú)需強(qiáng)制捕獲,編譯通過(guò),運(yùn)行時(shí)異常正常處理
fun readFile() {
val reader = FileReader("test.txt")
}
十、協(xié)程(Kotlin 獨(dú)有,替代 Java 線程)
Kotlin 原生支持協(xié)程,輕量級(jí)異步編程,替代 Java 的 Thread/AsyncTask/回調(diào)地獄。
Java(異步回調(diào),代碼嵌套混亂)
new Thread(() -> {
// 耗時(shí)操作
String result = requestApi();
// 切回主線程
runOnUiThread(() -> textView.setText(result));
}).start();
Kotlin(協(xié)程,線性代碼寫異步)
// 極簡(jiǎn)異步,無(wú)回調(diào)嵌套
lifecycleScope.launch {
// 耗時(shí)操作(自動(dòng)切子線程)
val result = requestApi()
// 自動(dòng)切主線程
textView.text = result
}
總結(jié):Kotlin 協(xié)程讓異步代碼簡(jiǎn)潔、易讀、易維護(hù),Java 線程方案臃腫易出錯(cuò)。
核心區(qū)別速查表
| 特性 | Java | Kotlin |
|---|---|---|
| 空安全 | 無(wú),易空指針 | 編譯期檢查,杜絕空指針 |
| 代碼量 | 冗余,樣板代碼多 | 簡(jiǎn)潔,少 40%+ 代碼 |
| 擴(kuò)展函數(shù) | 不支持 | 原生支持,無(wú)侵入擴(kuò)展 |
| 智能轉(zhuǎn)換 | 必須手動(dòng)強(qiáng)轉(zhuǎn) | 自動(dòng)類型轉(zhuǎn)換 |
| 默認(rèn)參數(shù) | 不支持,需重載 | 原生支持 |
| 協(xié)程 | 無(wú),依賴線程 | 原生支持,輕量級(jí)異步 |
| 實(shí)體類 | 需手寫 getter/setter | 一行 data class 搞定 |
| Lambda | 語(yǔ)法繁瑣 | 極簡(jiǎn),支持 it 關(guān)鍵字 |
總結(jié)
- 兼容性:Kotlin 完全兼容 Java,可混合開(kāi)發(fā),無(wú)縫遷移;
- 安全性:Kotlin 空安全、智能轉(zhuǎn)換大幅降低崩潰率;
- 效率:Kotlin 語(yǔ)法極簡(jiǎn)、擴(kuò)展函數(shù)、協(xié)程讓開(kāi)發(fā)速度翻倍;
- 定位:Java 是老牌嚴(yán)謹(jǐn)語(yǔ)言,Kotlin 是現(xiàn)代化高效語(yǔ)言,現(xiàn)在主流開(kāi)發(fā)優(yōu)先選 Kotlin。