🔧 阿川の電商水電行
Shopify 顧問、維護與客製化
💡
小任務 / 單次支援方案
單次處理 Shopify 修正/微調
⭐️
維護方案
每月 Shopify 技術支援 + 小修改 + 諮詢
🚀
專案建置
Shopify 功能導入、培訓 + 分階段交付

✨前言

大家好!Android工程師們辛苦了。

從事Android開發多年,我認為Kotlin和Java的選擇確實讓人困惑。我自己從Java轉向Kotlin,自2019年Google將Kotlin定位為「推薦語言」後,現場的氛圍也大變樣了。

本文希望能夠比較2025年目前Android開發中兩種語言的實際情況,並分享一些在工作中獲得的真實體驗,讓初學者及考慮轉換的人都能有所參考!

📊 當前市場動向

🔥 Kotlin的優勢確立

老實說,這幾年Kotlin的勢頭可謂驚人。

  • 求人市場的變化:截至2025年,Kotlin的工作機會真的是很多,我周圍常聽到「不會寫Kotlin的人很難找工作」之類的話。
  • 必須技能的化:有超過70%的Android開發職位將Kotlin列為必須條件。已經不是「如果會更好」而是「必須會」了。
  • Google官方的立場:「Kotlin-first」倡議下的開發日益增多,新功能幾乎都是優先以Kotlin開發。

☕ Java的持續重要性

不過Java也不是完全會消失。

  • 企業領域:在後端Java仍然是王者。Spring Boot等企業系統中,它是不可或缺的存在。
  • 遺留專案:現有的Android應用,特別是大型的,往往是用Java編寫的,這使得轉換並不簡單。
  • 學習成本:對於有經驗的Java開發者來說,轉換到Kotlin會有相當大的負擔。從團隊整體來看,這是一個不小的問題。

⚡ 技術比較

🎯 代碼簡潔性

這是我第一次對Kotlin感到震撼的地方,代碼真的變得非常簡潔。經常用Kotlin寫同樣的功能,行數僅為Java的一半以下。

Java

public class MainActivity extends AppCompatActivity {
    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textView = findViewById(R.id.text_view);
        textView.setText("Hello, World!");
    }

    public void setUserData(String name, String email) {
        if (name != null && email != null) {
            // 設定數據處理
        }
    }
}

Kotlin

class MainActivity : AppCompatActivity() {
    private lateinit var textView: TextView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        textView = findViewById(R.id.text_view)
        textView.text = "Hello, World!"
    }

    fun setUserData(name: String?, email: String?) {
        if (name != null && email != null) {
            // 設定數據處理
        }
    }
}

結果:Kotlin實現了約40%的代碼量減少!對於評審來說更加易讀,真是太有幫助了。

🛡️ Null安全性

這真的是革命性的變革。大家是否也有因NullPointerException而苦惱的經驗呢?

Java的NullPointerException地獄

  • 應用崩潰的最大原因(根據實際經驗,發布後的崩潰報告中80%都是因為這個...)
  • 在執行時才會知道,因此一些無法在測試中發現的bug潛伏著。

Kotlin的神之應對

  • 編譯時會檢查Null的安全性
  • 對能夠為Null的變數和不能為Null的變數進行明確區分
// Kotlin - Null安全
var name: String = "必填項" // 不可為Null
var nickname: String? = null // 允許為Null

// 安全調用
nickname?.let { 
    println("暱稱: $it") 
}

🎨 編程範式

我個人認為,這是Kotlin的真正魅力所在。

Java

  • 單一的面向對象編程(不過這樣也清晰)
  • 函數式編程的元素有限(雖然Java 8有Stream API,但使用起來有點麻煩...)

Kotlin

  • 結合了面向對象和函數式編程的優點!
  • 高階函數和Lambda表達式寫起來非常自然,習慣後再回到Java就困難了。
// 函數式編程的例子
val numbers = listOf(1, 2, 3, 4, 5)
val doubled = numbers.map { it * 2 }.filter { it > 4 }

💡 語句與表達式

這雖然看起來不起眼,但卻是相當大的不同。Java中的三元運算符,在變得複雜時會讓人難以閱讀。

在Java中,ifswitch是語句(statement),因此無法返回值。所以經常依賴三元運算符。但在Kotlin中,ifwhen都可以當作表達式(expression)使用,寫起來好得多。

Java

int score = 85;
String grade;
if (score >= 90) {
    grade = "A";
} else if (score >= 80) {
    grade = "B";
} else {
    grade = "C";
}
// 三元運算符
String result = (score >= 80) ? "Pass" : "Fail";

Kotlin

val score = 85
val grade = if (score >= 90) {
    "A"
} else if (score >= 80) {
    "B"
} else {
    "C"
}
val result = if (score >= 80) "Pass" else "Fail"

🔍 equals 和 ==, ===

作為Java新手,這個差異讓我犯了不少錯誤😅

Java中==.equals()的區別,當初真的非常困惑。但在Kotlin中則更直觀,使用==進行內容比較,===用於參考比較。記住這兩點就可以了。

Java

String a = new String("text");
String b = new String("text");
System.out.println(a == b);      // false (參考不同)
System.out.println(a.equals(b)); // true (內容相同)

Kotlin

val a = String("text".toCharArray())
val b = String("text".toCharArray())
println(a === b) // false (參考不同)
println(a == b)  // true (內容相同)

📚 集合的可變性

這真的是Kotlin的精妙設計!在類型層級上對「可變與不可變」進行了明確區分,大大減少了bug的發生。

在Kotlin中,編譯時就能區分只讀集合(List, Map, Set)和可變集合(MutableList, MutableMap, MutableSet)。而在Java中要等到執行時才能知道,因此經常會因不小心變更而出錯。

Java

List<String> list = new ArrayList<>();
list.add("Apple"); // 可變
List<String> readOnlyList = List.of("Banana");
// readOnlyList.add("Cherry"); // UnsupportedOperationException

Kotlin

val list: List<String> = listOf("Apple")
// list.add("Banana") // 編譯錯誤

val mutableList: MutableList<String> = mutableListOf("Banana")
mutableList.add("Cherry") // OK

⏰ 延遲初始化 (Lazy Initialization)

lateinitlazy的存在,讓Android開發變得輕鬆多了...!特別是在處理Activity中的View時特別有用。

Kotlin在語言層面上提供這樣的機制,lateinit用於varlazy用於val,各自有分工。

Java

// 需要手動實現
private TextView textView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    textView = findViewById(R.id.text_view); // 在這裡初始化
}

Kotlin

// lateinit: 後期一定會初始化的聲明
private lateinit var textView: TextView

// lazy: 在第一次訪問時初始化
val heavyObject: HeavyObject by lazy {
    HeavyObject()
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    textView = findViewById(R.id.text_view) // 初始化
}

🎛️ 預設參數

在Java中,寫多個重載讓人疲憊的經歷,Kotlin的預設參數真的是太方便,讓代碼變得簡潔明了。

Java

void drawCircle(int x, int y, float radius) {
    // ...
}
void drawCircle(int x, int y) {
    drawCircle(x, y, 10.0f); // 重載支持
}

Kotlin

fun drawCircle(x: Int, y: Int, radius: Float = 10.0f) {
    // ...
}

// 調用
drawCircle(10, 10) // radius為10.0f
drawCircle(10, 10, 20.0f) // radius為20.0f

📋 數據類和copy

data class真的是神機能!特別是copy()方法超級方便,一旦用了就再也捨不得放棄。能輕鬆享受不變對象的好處。

Java (Record, 16+)

// 使用Java 16以後的Record來實現不變性
public record User(String name, int age) {}

User user1 = new User("Alice", 30);
// 手動創建一個更改後的副本
User user2 = new User(user1.name(), 31);

Kotlin

data class User(val name: String, val age: Int)

val user1 = User("Alice", 30)
// 使用copy方法輕鬆複製和更改
val user2 = user1.copy(age = 31)

✨ 智能類型轉換

當我第一次看到這個時會驚訝「哇,竟然可以自動轉換?」但實際使用後,發現這非常便利。因為編譯器的聰明設計,可以安心使用。

Java

void process(Object obj) {
    if (obj instanceof String) {
        String str = (String) obj; // 需要明確的類型轉換
        System.out.println(str.length());
    }
}

Kotlin

fun process(obj: Any) {
    if (obj is String) {
        // 自動將obj轉換為String類型
        println(obj.length)
    }
}

🔧 擴展函數

這是Kotlin中我最喜歡的功能之一!可以在現有類別中新增函數,最初讓我懷疑「這是魔法嗎?」。相比創建工具類,這樣更加自然地擴增了功能。

Java

// 工具類
public class StringUtils {
    public static String shout(String s) {
        return s.toUpperCase() + "!!!";
    }
}
// 使用時
String excited = StringUtils.shout("hello");

Kotlin

// 擴展String類的shout()函數
fun String.shout(): String {
    return this.uppercase() + "!!!"
}
// 使用時
val excited = "hello".shout()

🔒 finalopen

這個差異起初讓我困惑。Java是「默認為open」,而Kotlin則是「默認為final」。這是出於安全性的設計,能防止意外的繼承或重寫。

Java

public class Vehicle { // 可繼承
    public void drive() {} // 可重寫
}
public final class Car extends Vehicle { // 不可繼承
    @Override
    public final void drive() {} // 不可重寫
}

Kotlin

open class Vehicle { // open允許繼承
    open fun drive() {} // open允許重寫
}
class Car : Vehicle() { // 默認為final (不可繼承)
    override fun drive() {} // 默認為final (不可再次重寫)
}

📝 字符串模板和多行字符串

那段使用+進行字符串連接的Java時光,讓我懷念不已😅 Kotlin的字符串模板直觀,提升了可讀性並減少了bug。

Java

String name = "Alice";
int age = 30;
// 使用`+`連接或是使用String.format
String text = "Name: " + name + ", Age: " + age;

// Java 15+ 的多行字符串
String html = """
              <html>
                  <body>
                      <p>Hello, World</p>
                  </body>
              </html>
              """;

Kotlin

val name = "Alice"
val age = 30
// 字符串模板
val text = "Name: $name, Age: $age"

// 多行字符串(原始字符串)
val html = '''
    <html>
        <body>
            <p>Hello, ${name.uppercase()}</p>
        </body>
    </html>
    '''.trimIndent()

⚡ 性能比較

常常有人問「性能怎麼樣?」實際情況如何,我來跟大家談談。

🏎️ 執行速度

  • 基本性能:因為同樣運行在JVM上,基本上是相當的。幾乎感受不到差異。
  • 執行效率:Java由於語法較簡單,在細緻的優化上有一些優勢。
  • 編譯速度:新版K2編譯器帶來了顯著改善!之前Kotlin編譯速度太慢讓人煩躁,但現在感覺非常流暢。

🤝 互操作性

這個其實非常重要。Kotlin和Java之間實現了100%的互操作性。

在我們的現場,也逐漸將現有的Java專案中引入Kotlin。反過來,Kotlin專案中的Java函數也能毫無問題地使用。正因如此,轉換的難度大幅降低。

// 從Kotlin調用Java類
val javaObject = JavaClass()
javaObject.javaMethod()

// 從Java調用Kotlin類
KotlinClass kotlinObject = new KotlinClass();
kotlinObject.kotlinMethod();

📚 Kotlin專用庫的興起

※2025年追記:在過去一到兩年內,Android生態系統正朝Kotlin中心迅速變化!

🎯 Kotlin優先的庫群

最近的Android開發中,越來越多的庫是Kotlin原生的。而且,這些庫許多在Java中則難以使用(或完全無法使用)。

主要的Kotlin專用庫

  • Jetpack Compose - UI工具包(專為Kotlin設計)
  • Ktor Client - HTTP客戶端(支持Kotlin多平台)
  • kotlinx.coroutines - 異步處理(suspend function僅支持Kotlin)
  • kotlinx.serialization - JSON序列化(Kotlin優化的註解處理)
  • Koin - 輕量級依賴注入(Kotlin DSL)
  • Exposed - 數據庫ORM(Kotlin DSL)

🔥 Jetpack Compose的影響

特別是Jetpack Compose的問世,讓局勢發生了劇變:

// Jetpack Compose(僅以Kotlin編寫)
@Composable
fun UserCard(user: User) {
    Card(
        modifier = Modifier.fillMaxWidth().padding(16.dp)
    ) {
        Column {
            Text(
                text = user.name,
                style = MaterialTheme.typography.h6
            )
            Text(
                text = user.email,
                style = MaterialTheme.typography.body2
            )
        }
    }
}

這真的非常革命性,現在根本提不起興致再用XML格式編寫佈局了😅

📊 截至2025年的狀況

  • 新建專案: 選擇Kotlin為前提的庫已成為常態。
  • 現有專案: 更新現代化的過程中,轉向Kotlin幾乎是必須的。
  • 招聘市場: 「有Jetpack Compose經驗」已成為必需條件。

根據我的實際經驗,最近我參加的一個專案中被要求「用Java新增功能」,實話說讓我感到困惑。要應用最新的最佳實踐,現在Kotlin已經不可或缺了。

📝 總結

專案選擇的指針

適合使用Kotlin的情況

  • 新建的Android應用專案
  • 採用現代架構
  • 重視開發效率和代碼質量
  • 利用Jetpack Compose

適合使用Java的情況

  • 遺留系統的維護和擴展
  • 在既有Java開發團隊中繼續開發
  • 與後端技術保持一致

技術選擇的要點

在當前的Android開發中,新建專案時Kotlin已成為標準選擇。但是,對於專案的性質、團隊的技能以及與現有系統的集成需求,進行綜合評估是非常重要的。

這兩種語言都運行在Java虛擬機(JVM)上,實現相互操作,因而可以考慮逐步遷移或混合開發作為現實的選項。

參考資料


原文出處:https://qiita.com/yun_bow/items/3cac8534a3a43e5d74b8


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝12   💬9   ❤️4
553
🥈
我愛JS
📝3   💬9   ❤️7
189
🥉
AppleLily
📝1   💬4   ❤️1
68
#4
xxuan
💬1  
3
#5
💬1  
3
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
🔧 阿川の電商水電行
Shopify 顧問、維護與客製化
💡
小任務 / 單次支援方案
單次處理 Shopify 修正/微調
⭐️
維護方案
每月 Shopify 技術支援 + 小修改 + 諮詢
🚀
專案建置
Shopify 功能導入、培訓 + 分階段交付