譯者 | 劉汪洋
審校 | 重樓
學(xué)習(xí) Java 的過程中,我意識到在 90 年代末 OOP 正值鼎盛時(shí)期,Java 作為能夠真正實(shí)現(xiàn)這些概念的語言顯得尤為突出(盡管我此前學(xué)過 C++,但相比 Java 影響較?。?。我特別欣賞 Java 的平臺獨(dú)立性。
相比簡單性,我更看重結(jié)構(gòu)和一致性,這也是我堅(jiān)持使用 Java 的主要原因。
在我的職業(yè)生涯中,我遇到了一些質(zhì)量不高的 Java 代碼庫,這讓我對 Java 產(chǎn)生了些失望。然而,在參與了許多其他優(yōu)秀的項(xiàng)目之后,我重新燃起了對 Java 的熱愛。
我注意到那些批評和抱怨 Java 的通常是一些年輕人,他們接觸 JavaScript 的機(jī)會(huì)更多。與JavaScript 相比,Java 可能看起來更加笨重和受限——充斥著模板代碼,擁有嚴(yán)格的類型系統(tǒng)等等。但如果讓我選擇,我無疑會(huì)更愿意處理一個(gè)次優(yōu)的 Java 代碼庫,而不是 JavaScript 的。
只有在你積累了一定的工作經(jīng)驗(yàn),處理過分散在幾十個(gè)甚至上百個(gè)文件中的代碼后,你才會(huì)開始意識到,Java 所謂的“限制”其實(shí)是為了防止你陷入困境的安全措施。
“只有兩種編程語言:被人們抱怨的和沒人使用的?!边@是 C++ 之父 Bjarne Stroustrup 的著名言論。
關(guān)于 Java 的看法,確實(shí)存在不少爭議。相比之下,C++ 也有它的問題。這種語言深受愛恨交織的評價(jià),仿佛是一種難以擺脫的復(fù)雜關(guān)系。
Python 也同樣面臨批評。
很多討論集中在全局解釋器鎖(GIL)上,它被認(rèn)為是阻礙有效多線程實(shí)現(xiàn)的主要障礙。由于Python 核心很多部分都依賴于 GIL,因此它可能無法被完全移除。為了解決這一問題,開發(fā)者不得不通過使用多個(gè)進(jìn)程和創(chuàng)建消息傳遞機(jī)制來實(shí)現(xiàn)進(jìn)程間的通信。此外,為了解決性能瓶頸,除非對關(guān)鍵代碼使用C/C++進(jìn)行重寫,否則 Python 的執(zhí)行速度通常較慢。當(dāng)然,Python 2 到 3 的過渡也引起了一些問題。
此外,我曾經(jīng)參與過一個(gè) Django 項(xiàng)目。那時(shí),我認(rèn)為 Python 相比于類型嚴(yán)格的語言更有優(yōu)勢,盡管它適用于某些場景,但并不適合那些有著成千上萬個(gè)類的復(fù)雜系統(tǒng)。
當(dāng)這個(gè)項(xiàng)目由我一人擴(kuò)展至多人參與,代碼量超過 1 萬行時(shí),它變得極其難以維護(hù)。
之后我轉(zhuǎn)向 Java,這是一個(gè)令人開眼界的經(jīng)歷。它讓我深刻認(rèn)識到自己對 Java 及其生態(tài)系統(tǒng)的熱愛。因此,我決定記錄下我所喜愛的 Java 生態(tài)系統(tǒng)方面的內(nèi)容。這樣,當(dāng)有人對 Java 有所非議時(shí),你就有 25 個(gè)理由來反駁他們。
1. 成熟的生態(tài)系統(tǒng)
Java 已經(jīng)發(fā)展了 25 多年,作為一個(gè)在這個(gè)生態(tài)系統(tǒng)中工作的開發(fā)者,回顧其成熟過程非常有趣。
Java 廣泛的生態(tài)系統(tǒng)最大的優(yōu)勢在于它提供了豐富的庫、構(gòu)建工具和框架選擇。
JVM 生態(tài)系統(tǒng)極為豐富,幾乎對于每個(gè)問題都有一個(gè)最佳的庫解決方案,而且這些庫通常都表現(xiàn)出高性能并得到良好維護(hù)。在構(gòu)建工具方面,也有多種選擇,例如 Gradle、Maven 和 Bazel 等,它們能夠提供快速且可復(fù)制的構(gòu)建過程。對于那些不太熟悉 Java 生態(tài)系統(tǒng)的人來說,Java 還為日志記錄、數(shù)據(jù)庫連接、消息傳遞和應(yīng)用服務(wù)器等各種功能提供了默認(rèn)實(shí)現(xiàn),這些都是非常好的入門點(diǎn)。
以日志記錄為例,假設(shè)你的應(yīng)用程序需要進(jìn)行日志記錄。Java 提供了與 JDK 無縫集成的默認(rèn)日志記錄選項(xiàng)。如果你對默認(rèn)選項(xiàng)不滿意,或覺得它不夠好,那么你還可以選擇其他優(yōu)秀的日志記錄庫,因?yàn)槟J(rèn)的日志記錄僅僅是日志記錄 API 的一個(gè)基本實(shí)現(xiàn)。
不僅僅是日志記錄,Java 生態(tài)系統(tǒng)還為數(shù)據(jù)庫連接、消息傳遞、應(yīng)用服務(wù)器、Servlets 等提供了豐富的選擇。
2. “一次編寫,到處運(yùn)行”(WORA)
“一次編寫,到處運(yùn)行”是用來描述 Java 語言跨平臺優(yōu)勢的常用口號?,F(xiàn)在學(xué)習(xí) Java 的許多開發(fā)者可能沒有意識到這一功能對軟件開發(fā)的重大意義。
讓我們來回顧一下背景。在 Java 誕生的十年前,C++ 是主流的編程語言。然而,開發(fā)者們面臨的一個(gè)主要挑戰(zhàn)是 C++ 的平臺依賴性。用 C++ 編寫的代碼往往需要針對不同的操作系統(tǒng)或硬件架構(gòu)進(jìn)行重新編譯和修改。
Geeks for Geeks
3. 向后兼容性
想象一下,如果每次 Java 發(fā)布新版本,都要求你重寫程序代碼,那將是多么昂貴和耗時(shí)的過程,尤其是對于大型組織而言。
Java 已經(jīng)發(fā)展多年,這意味著有許多基于舊版本 Java 構(gòu)建的軟件產(chǎn)品,它們是許多企業(yè)的核心,扮演著關(guān)鍵角色。
在企業(yè)級開發(fā)中,項(xiàng)目規(guī)模通常龐大且復(fù)雜,這些系統(tǒng)要遷移到最新的 Java 版本需要細(xì)致的規(guī)劃和執(zhí)行。
Java 對向后兼容性的承諾極為重要,它向那些投入巨大資源開發(fā)系統(tǒng)的開發(fā)者或組織保證,他們的系統(tǒng)可以持續(xù)運(yùn)行并維護(hù),而無需進(jìn)行全面重寫。Java(JVM)的向后兼容性也簡化了遷移過程,促進(jìn)了新功能和改進(jìn)的采用,同時(shí)保障了現(xiàn)有系統(tǒng)的穩(wěn)定性。
4. Java 的強(qiáng)類型系統(tǒng)
Java 是一種強(qiáng)類型語言,與 Python 等松散類型的語言形成對比。如果你使用過 Python,你會(huì)立刻感受到將不同類型的值賦給同一變量的靈活性,而語言會(huì)動(dòng)態(tài)適應(yīng)。
int age = 25;
String name = "John";
但這種靈活性是有代價(jià)的。我曾在一個(gè)涉及復(fù)雜計(jì)算的金融應(yīng)用程序上工作,該程序包含不同的數(shù)值數(shù)據(jù)類型。Java 的強(qiáng)類型特性意味著,編譯器會(huì)標(biāo)出任何嘗試混合不兼容數(shù)據(jù)類型的操作,或是執(zhí)行可能導(dǎo)致數(shù)據(jù)丟失或意外結(jié)果的行為。而使用像 Python 這樣的語言時(shí),一些這樣的明顯錯(cuò)誤可能在運(yùn)行時(shí)被忽略。
這也是 Java 在開發(fā)企業(yè)級應(yīng)用程序,尤其是在像銀行和金融等對可靠性和安全性有高要求的領(lǐng)域中,格外受歡迎的一個(gè)原因。除了減少運(yùn)行時(shí)錯(cuò)誤的需求,Java 的強(qiáng)類型系統(tǒng)通過明確變量、參數(shù)和返回值的預(yù)期數(shù)據(jù)類型,提高了代碼的可讀性。
5. 更快的發(fā)布周期 - 持續(xù)改進(jìn)
過去,作為 Java 開發(fā)者,我們習(xí)慣于每隔幾年等待一次重大更新來獲得新的 Java 特性。但為了適應(yīng)現(xiàn)代編程的需求,自 Java 9 發(fā)布以后,Java 的發(fā)布節(jié)奏改為了每六個(gè)月一次。對于那些不急于迅速遷移到新版本的企業(yè)組織,Oracle 提出了每三年發(fā)布一個(gè)長期支持(LTS)版本的策略。
更頻繁且規(guī)模更小的發(fā)布減少了升級到新 Java 版本的復(fù)雜性和風(fēng)險(xiǎn)。開發(fā)者不太可能遇到重大的兼容性問題,因?yàn)檫@些漸進(jìn)的變化被設(shè)計(jì)為更加向后兼容。
6. 優(yōu)秀的集成開發(fā)環(huán)境(IDE)
Java 經(jīng)歷了漫長的發(fā)展,引入了許多變化和特性,使其非常適合現(xiàn)代開發(fā)。然而,這一切都得益于像 IntelliJ IDEA、Eclipse 和 NetBeans 這樣的強(qiáng)大集成開發(fā)環(huán)境(IDE)的支持。
我無法想象在沒有智能代碼補(bǔ)全、自動(dòng)重構(gòu)、無縫版本控制集成等功能的環(huán)境下進(jìn)行編程會(huì)是什么體驗(yàn)。然而,也很重要的是要認(rèn)識到這并非始終如此,尤其是在 Java 早期。
快速發(fā)展到如今,像 IntelliJ IDEA 和 Eclipse 這樣的現(xiàn)代 IDE 使 Java 開發(fā)變得更加輕松。這些IDE 與 Maven 和 Gradle 等構(gòu)建工具無縫集成,處理編譯、依賴解析和項(xiàng)目管理。像智能代碼補(bǔ)全這樣的功能減少了 Java 編寫的繁瑣性,內(nèi)置的靜態(tài)代碼分析工具簡化了調(diào)試過程,而插件系統(tǒng)則允許開發(fā)者根據(jù)個(gè)人偏好自定義他們的開發(fā)環(huán)境。
7. GraalVM 原生鏡像的支持
我們已經(jīng)探討了 JVM 如何作為一個(gè)強(qiáng)大的平臺推動(dòng) Java 的輝煌。然而,JVM 長期以來也面臨著啟動(dòng)速度慢的問題,這在當(dāng)前追求微服務(wù)、無服務(wù)器計(jì)算及快速啟動(dòng)和資源優(yōu)化的開發(fā)環(huán)境中顯得尤為突出。
為了解決這一問題,業(yè)界已在減少內(nèi)存占用和加快 Java 應(yīng)用啟動(dòng)速度方面做出了不懈努力。在這其中,我特別關(guān)注的是 GraalVM 原生鏡像技術(shù)。Oracle GraalVM 是一種高性能 JDK,它通過采用 Graal 編譯器這一替代的即時(shí)編譯器(JIT),提升了 Java 及其他基于 JVM 應(yīng)用的性能。
GraalVM 還引入了一種原生鏡像工具,它能夠?qū)崿F(xiàn) Java 字節(jié)碼的提前編譯(AOT),從而達(dá)到幾乎瞬間啟動(dòng)應(yīng)用的效果。Graal 編譯器在此過程中既是 AOT 編譯器,又能生成原生可執(zhí)行文件。簡而言之,它將 Java 字節(jié)碼轉(zhuǎn)化為原生可執(zhí)行文件。
以下是一個(gè)使用遞歸反轉(zhuǎn)字符串的簡單 Java 程序示例:
public class Example {
public static void main(String[] args) {
String str = "Native Image is awesome";
String reversed = reverseString(str);
System.out.println("反轉(zhuǎn)后的字符串是:" + reversed);
}
public static String reverseString(String str) {
if (str.isEmpty())
return str;
return reverseString(str.substring(1)) + str.charAt(0);
}
}
你可以對這個(gè)程序進(jìn)行編譯,然后基于 Java 類創(chuàng)建一個(gè)原生鏡像。
javac Example.java
native-image Example
原生鏡像構(gòu)建器會(huì)將 Example 類提前編譯成一個(gè)獨(dú)立的可執(zhí)行文件 example
,并保存在當(dāng)前工作目錄中。您接下來可以直接運(yùn)行這個(gè)可執(zhí)行文件:
./example
原生可執(zhí)行文件體積小,啟動(dòng)迅速,同時(shí)顯著減少了 CPU 和內(nèi)存的需求,非常適合于容器和云部署環(huán)境,其中成本優(yōu)化至關(guān)重要。
隨著 JDK 21、項(xiàng)目 Loom 和 ZGC 的最新進(jìn)展,我對這些技術(shù)的發(fā)展充滿期待。GraalVM 的原生鏡像現(xiàn)在也支持虛擬線程。我們可以創(chuàng)建使用 Spring Boot(通過 Spring Boot 3.2)和 Java 21 虛擬線程的 GraalVM 原生鏡像。
8. 開源庫和框架的重要性
開源庫和框架是 Java 在我的工具集中占據(jù)重要位置的核心原因之一。
圖片來源:Google
這些庫和框架為我提供了一系列易于集成的構(gòu)建模塊,省去了自行為常見功能重新設(shè)計(jì)和實(shí)現(xiàn)的工作。它們就像一個(gè)隨時(shí)可以取用的代碼商店,其中存放著大量經(jīng)過嚴(yán)格測試和精心編寫的代碼。
這些庫的多樣性意味著我不再受限于單一的解決方案。我總能找到最適合我的需求的庫。開源性質(zhì)還促進(jìn)了透明度和責(zé)任感,意味著我可以深入探究源代碼,了解其背后的工作機(jī)制,甚至可以做出自己的貢獻(xiàn)。
Java 的開源庫涵蓋廣泛,包括用于 JSON 解析的庫(如 Jackson 和 Gson)、日志庫(如 Log4j、SLF4j 和 LogBack)、單元測試庫(如 JUnit、Mockito 和 PowerMock),還有數(shù)據(jù)庫連接庫、消息傳遞庫等。
Java 的廣泛框架生態(tài)系統(tǒng)也是其成功的部分原因。Spring 和 Spring Boot 是我偏愛的組合之一。此外,我還使用過 Jakarta Faces、Struts、Hibernate 和 Quarkus 等其他框架。
9. 多線程的支持
Java 對多線程的支持允許我設(shè)計(jì)能夠同時(shí)處理多任務(wù)的應(yīng)用程序,涵蓋數(shù)據(jù)處理、用戶交互管理和后臺計(jì)算等方面。Java 通過實(shí)現(xiàn) Runnable 接口或繼承 Thread 類來實(shí)現(xiàn)多線程功能。
Java 的 java.util.concurrent 包提供了一系列先進(jìn)的工具,進(jìn)一步便利了并發(fā)應(yīng)用程序的開發(fā),包括 ExecutorService、ScheduledExecutorService、Future、CyclicBarrier 等。
public class MyRunnable implements Runnable {
public void run() {
// 在新線程中要執(zhí)行的代碼
}
}
MyRunnable myRunnable = new MyRunnable();
Thread myThread = new Thread(myRunnable);
myThread.start();
現(xiàn)代計(jì)算標(biāo)準(zhǔn)中,多核處理器已成為常態(tài),即一個(gè)芯片上集成了多個(gè)處理器核心。Java 對多線程的支持使得我們能夠充分利用多核 CPU 的能力,這意味著我們可以開發(fā)出更高性能的 Java 應(yīng)用程序,適用于游戲、視頻編輯、科學(xué)模擬等資源密集型活動(dòng)。
10. Java 面向?qū)ο蟮奶匦?/h3>
你可能會(huì)想,Java 并非唯一的面向?qū)ο缶幊陶Z言,它與 Python、C++ 等語言相比有何特殊之處?區(qū)別在于,Java 從一開始就是基于面向?qū)ο笤瓌t設(shè)計(jì)的,而不是像其他語言那樣后來才加入面向?qū)ο缶幊蹋∣OP)的元素或支持。
Java 對面向?qū)ο缶幊痰乃拇笤瓌t——抽象、繼承、多態(tài)和封裝——的堅(jiān)持,使它成為構(gòu)建復(fù)雜、可擴(kuò)展和易于維護(hù)的軟件系統(tǒng)的理想選擇。我認(rèn)為,Java 對 OOP 范式的深入支持帶來了許多優(yōu)勢,如有助于構(gòu)建模塊化、靈活、易讀、易維護(hù)和可擴(kuò)展的應(yīng)用程序。
11. 內(nèi)存管理和垃圾回收
圖片來源:Digital Ocean
讓我們以一個(gè)類比來看待這個(gè)問題:就像許多人都不喜歡倒垃圾一樣,我也不喜歡手動(dòng)管理內(nèi)存。在需要手動(dòng)內(nèi)存管理的情況下,開發(fā)者需要負(fù)責(zé)分配和釋放內(nèi)存,這就像決定何時(shí)倒垃圾一樣。如果忘記釋放內(nèi)存,就會(huì)導(dǎo)致內(nèi)存泄漏和性能問題。
而 Java 的自動(dòng)內(nèi)存管理則像是一個(gè)可靠的垃圾回收服務(wù)。在 Java 中,垃圾收集器自動(dòng)識別并處理不再需要的內(nèi)存,從繁瑣的內(nèi)存管理中釋放了開發(fā)者。
在使用 C++ 的過程中,我體驗(yàn)到了內(nèi)存管理的兩面性。C++ 提供了對內(nèi)存管理的細(xì)致控制,但這也給開發(fā)者帶來了避免內(nèi)存泄漏的巨大責(zé)任。
相比之下,Java 讓開發(fā)者不必?fù)?dān)心底層系統(tǒng)的細(xì)節(jié),也無需手動(dòng)進(jìn)行垃圾回收、處理底層操作系統(tǒng)的問題或追蹤內(nèi)存分配與釋放。垃圾收集器會(huì)自動(dòng)識別并回收不再使用的內(nèi)存,減少了內(nèi)存泄漏的風(fēng)險(xiǎn)。
作為開發(fā)者,這意味著我可以將更多精力集中在業(yè)務(wù)邏輯和應(yīng)用程序的高層設(shè)計(jì)上。如果你是團(tuán)隊(duì)中的一員,Java 的自動(dòng)內(nèi)存管理還可以提升開發(fā)周期的效率和整體生產(chǎn)力。
12. 可觀測性和監(jiān)控
在過去,很多開發(fā)者主要致力于單體應(yīng)用的開發(fā)和維護(hù)。處理故障和修復(fù)漏洞相對直接,因?yàn)檎麄€(gè)應(yīng)用都集中在一個(gè)統(tǒng)一的代碼庫中。這就像在一張?jiān)敱M的地圖上導(dǎo)航,追蹤問題相對容易。
然而,隨著微服務(wù)、無服務(wù)器計(jì)算和分布式系統(tǒng)的興起,情況發(fā)生了顯著的變化。由于微服務(wù)作為獨(dú)立服務(wù)通過網(wǎng)絡(luò)通信,識別和解決問題變得更加復(fù)雜。當(dāng)問題發(fā)生時(shí),它們可能不再局限于單個(gè)代碼庫。以下是我在使用 Java 進(jìn)行開發(fā)時(shí),最青睞的一些監(jiān)控工具。
標(biāo)準(zhǔn)分析工具:
VisualVM.
VisualVM 對我來說就像是探索 Java 應(yīng)用內(nèi)部世界的可靠伙伴。它融合了 JConsole 和 VisualGC 的功能,為我提供了一個(gè)用于監(jiān)控線程、堆使用情況和 CPU 性能的可視化平臺。此外,它與各種 JDK 工具的兼容性極佳,是一款十分可靠的監(jiān)控工具。
YourKit.
YourKit 在我的工具箱中就像一位秘密特工。它能夠深入到方法級別,揭示程序的執(zhí)行時(shí)間和內(nèi)存分配情況。它提供了一種簡單、易用且安全的方法,在云環(huán)境、容器和集群中進(jìn)行性能分析。
應(yīng)用性能監(jiān)控(APM)工具:
New Relic.
New Relic 是我的首選應(yīng)用性能監(jiān)控工具。它就像一個(gè)全天候監(jiān)視我的應(yīng)用程序的私人助手,提供從實(shí)時(shí)洞察到詳細(xì)的事務(wù)跟蹤。它的警報(bào)系統(tǒng)就像我的安全網(wǎng),確保我對任何異常行為及時(shí)獲得通知。
AppDynamics.
AppDynamics 是我的性能監(jiān)控藝術(shù)家!它采用全面的監(jiān)控方式,觀察并可視化整個(gè)技術(shù)棧,從數(shù)據(jù)庫和服務(wù)器到云原生和混合環(huán)境。我特別欣賞它如何幫助我理解性能對最終用戶體驗(yàn)的影響,讓它不僅僅是一個(gè)監(jiān)控工具,更是一種用戶滿意度的衡量工具。
日志解決方案:
Log4j.
Log4j 在日志框架界就像一位可靠的元老。無論遇到何種情況,它都能忠實(shí)地記錄下事件和錯(cuò)誤。其在配置 Appender 和過濾器方面的靈活性,使其成為適應(yīng)各種日志需求的堅(jiān)實(shí)選擇。
SLF4J.
SLF4J 就像我手頭的日志瑞士軍刀。它本身并不直接記錄日志,而是作為一個(gè)外觀層,允許我無縫切換不同的日志實(shí)現(xiàn)。這種靈活性使它成為在多個(gè)庫中進(jìn)行日志管理的理想選擇,尤其是當(dāng)這些庫有各自的日志偏好時(shí)。
Java 的可觀測性:
Digma:連續(xù)反饋(CF)。
在軟件開發(fā)中,如果不能直觀地看到代碼在實(shí)際環(huán)境中的運(yùn)行效果,就難以做出明智的設(shè)計(jì)決策和評估更改的影響。Digma 通過在可觀測性和代碼之間建立聯(lián)系,為一種新型的開發(fā)方法鋪平了道路。
Digma是一個(gè)連續(xù)反饋工具 ,旨在簡化從 OpenTelemetry 可觀測性源收集和處理代碼數(shù)據(jù)的過程。Digma 作為 IDE 插件在本地運(yùn)行,邊編碼邊收集代碼的數(shù)據(jù),從追蹤到日志和指標(biāo),讓你能夠?qū)崟r(shí)捕捉問題并獲取深入洞察。
Prometheus 和 Grafana
Prometheus 和 Grafana 是我不可或缺的動(dòng)態(tài)雙人組合。Prometheus 負(fù)責(zé)從應(yīng)用程序中抓取指標(biāo),而 Grafana 則將這些指標(biāo)轉(zhuǎn)換成美觀且可自定義的儀表板。這些工具的開源性質(zhì)和活躍的社區(qū)使它們成為我日常可觀測性的重要組成部分。
Elastic Stack (ELK)
Elastic Stack 結(jié)合了基于 AI 和搜索的開放、可擴(kuò)展的全棧可觀測性功能。Elasticsearch、Logstash 和 Kibana 一起構(gòu)成了一個(gè)強(qiáng)大的工具組合,用于搜索、分析和可視化日志。它們將日志、指標(biāo)和追蹤數(shù)據(jù)關(guān)聯(lián)起來,為我提供了一個(gè)全面的調(diào)查工具包。
13. 函數(shù)式編程的支持
自從 Java 8 推出以來,函數(shù)式編程已成為 Java 支持的另一種編程范式。在函數(shù)式編程中,函數(shù)被視為“一等公民”,這意味著它們可以被賦值給變量、作為參數(shù)傳遞,甚至作為返回值。
Java 中的函數(shù)式編程特性為編程語言增添了吸引力。對我而言,采用 Java 中的函數(shù)式編程特性是一場規(guī)則改變的游戲。Lambda 表達(dá)式和函數(shù)接口的引入,不僅讓我寫出的代碼更加簡潔,而且表達(dá)力更強(qiáng)。利用 Stream API,我的應(yīng)用程序得以在多核處理器上執(zhí)行并行處理,從而獲得性能上的提升。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
int sum = list.stream().reduce(0, (a, b) -> a + b);
System.out.println(sum);
}
}
我發(fā)現(xiàn),函數(shù)式編程所倡導(dǎo)的聲明式風(fēng)格使代碼更易于閱讀和理解。對不可變性的重視以及避免副作用的原則,對我編寫的代碼產(chǎn)生了積極影響,使其更加可預(yù)測和易于維護(hù)。而在測試方面,純函數(shù)的普遍應(yīng)用使得測試工作更加容易。
14. Java 豐富的文檔
團(tuán)隊(duì)項(xiàng)目的經(jīng)歷讓人深刻理解文檔的重要性。對我個(gè)人來說,我認(rèn)為文檔就像是代碼的用戶手冊,它解釋了代碼的作用、實(shí)現(xiàn)方式及其原因。對于初學(xué) Java 的人來說,這就像身邊有一個(gè)導(dǎo)師。
Java 文檔包括豐富的代碼示例、教程、開發(fā)者指南和 API 文檔,你可以借此快速開發(fā)原型,并將其擴(kuò)展到真實(shí)世界的應(yīng)用程序。
文檔的時(shí)效性同樣重要。Java 的文檔始終保持最新,定期進(jìn)行修訂,以反映生態(tài)系統(tǒng)中的新發(fā)展。這些文檔由開發(fā)者和專家編寫,其結(jié)構(gòu)也便于查找特定類別、方法或概念的信息。
15. 構(gòu)建工具和依賴管理
在常規(guī)的 Java/Spring Boot 項(xiàng)目中,通常會(huì)遇到幾十甚至幾百個(gè)直接和間接依賴。嘗試手動(dòng)管理這些依賴可能會(huì)帶來極大的挑戰(zhàn),尤其是在處理大型企業(yè)項(xiàng)目時(shí),問題如版本兼容性等更加復(fù)雜。使用構(gòu)建工具可以在團(tuán)隊(duì)成員之間統(tǒng)一構(gòu)建過程,確保每個(gè)開發(fā)人員的本地運(yùn)行環(huán)境保持一致。
image.png
構(gòu)建工具如 Maven 和 Gradle 極大簡化了構(gòu)建、測試和管理依賴的過程,為開發(fā)人員節(jié)約了寶貴的時(shí)間和精力。這些工具能自動(dòng)從倉庫獲取依賴項(xiàng)并檢查更新,省去了跟蹤依賴項(xiàng)更新和安全補(bǔ)丁的麻煩。
此外,構(gòu)建工具還為項(xiàng)目結(jié)構(gòu)和配置強(qiáng)制實(shí)施一定的約定和標(biāo)準(zhǔn),使項(xiàng)目易于理解和與其他 Java 開發(fā)人員協(xié)作。
16. 強(qiáng)大的測試功能
雖然我們開發(fā)人員可能害怕解決漏洞和與 QA 工程師合作,但我們也認(rèn)識到全面測試是確保我們的應(yīng)用程序盡可能無漏洞的關(guān)鍵方法之一。
選擇一個(gè)具有強(qiáng)大測試功能的編程語言可以大大減輕開發(fā)負(fù)擔(dān),并有助于構(gòu)建更可靠、易于維護(hù)的代碼庫。這也是為什么我推崇 Java 作為構(gòu)建穩(wěn)定軟件的首選編程語言的原因之一。
在 Java 領(lǐng)域,無論是單元測試、集成測試還是端到端測試,都有一整套成熟的工具集來編寫全面的測試用例。在這些工具中,JUnit 被廣泛認(rèn)為是單元測試的行業(yè)標(biāo)準(zhǔn)。它提供了一種簡潔且高效的方式來撰寫和執(zhí)行測試。JUnit 的核心特點(diǎn)是使用各種注解,如 @Test、@Before、@After、@BeforeClass 和 @AfterClass,來定義測試方法的生命周期。這種設(shè)計(jì)讓開發(fā)者在執(zhí)行測試前能夠輕松地設(shè)定必要的前置條件。
// EmployeeServiceTest.java
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.ArrayList;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*;
@SpringBootTest
public class EmployeeServiceTest {
@Mock
private EmployeeRepository employeeRepository;
@InjectMocks
private EmployeeService employeeService;
@Test
public void testGetAllEmployees() {
// 模擬倉庫響應(yīng)
when(employeeRepository.findAll()).thenReturn(new ArrayList<>());
// 測試 getAllEmployees 方法
List<Employee> result = employeeService.getAllEmployees();
// 斷言
assertEquals(0, result.size());
// 驗(yàn)證倉庫方法調(diào)用情況
verify(employeeRepository, times(1)).findAll();
}
}
使用 JUnit 編寫測試既簡潔又高效,同時(shí)它能夠與眾多流行的 Java 集成開發(fā)環(huán)境(IDE),如 Eclipse、IntelliJ IDEA 和 NetBeans 完美兼容。
在 Java 生態(tài)系統(tǒng)中,還有其他幾種對測試非常有幫助的工具。例如,TestNG 適用于集成測試,Cucumber 便于實(shí)現(xiàn)行為驅(qū)動(dòng)開發(fā),而 Selenium 則專門用于自動(dòng)化功能測試和回歸測試用例的編寫。此外,Mockito 作為一款功能強(qiáng)大的模擬框架,能夠與 JUnit、TestNG 等其他測試框架結(jié)合使用,以提高測試的靈活性和效率。
17. 龐大的社區(qū)
Java 社區(qū)在我作為一名 Java 開發(fā)者的成長過程中起著至關(guān)重要的作用。我已經(jīng)無數(shù)次從這個(gè)社區(qū)中獲得了幫助和指導(dǎo)。無論我面臨著一個(gè)棘手的問題、探索新的庫,還是尋求在實(shí)施新方案時(shí)的最佳實(shí)踐,Java 社區(qū)都是一個(gè)寶貴的知識源泉。
Java 社區(qū)是最活躍和響應(yīng)迅速的社區(qū)之一,我?guī)缀蹩偸悄軌蜓杆購纳鐓^(qū)中獲得幫助。例如,在 Reddit 的 r/java 社區(qū),有數(shù)以萬計(jì)的 Java 開發(fā)者交流和分享。在 Stack Overflow、Github 等平臺上,從初學(xué)者到資深專業(yè)人士的各種開發(fā)者都活躍在這些社區(qū)中。這種多樣性是社區(qū)強(qiáng)大的基石,意味著你能夠獲得來自不同領(lǐng)域和經(jīng)驗(yàn)層次的豐富專業(yè)知識。
除了在線社區(qū),許多 Java 活動(dòng)、會(huì)議和聚會(huì)為開發(fā)者提供了面對面交流、分享經(jīng)驗(yàn)和學(xué)習(xí)的機(jī)會(huì)。這些聚會(huì)加強(qiáng)了人際網(wǎng)絡(luò)和協(xié)作,并且為 Java 開發(fā)者間的社群感做出了貢獻(xiàn)。
18. Java 注解的支持
Java 注解自 Java 5 引入以來,一直是一個(gè)受歡迎且有爭議的話題。注解的引入標(biāo)志著從 Hibernate 或 Spring XML 配置文件的廣泛使用向更現(xiàn)代化的編程方法轉(zhuǎn)變。注解使我們能夠?qū)⑿畔?、指令或配置直接嵌入到源代碼中,放置在所需的確切位置。
// 預(yù)定義注解
@Deprecated
@Override
@SuppressWarnings
@SafeVarargs
@FunctionalInterface
// 元注解
@Retention
@Documented
@Target
@Inherited
@Repeatable
// 自定義注解
// 也可以創(chuàng)建我們自己的自定義注解。
同時(shí),我們也能夠創(chuàng)建自己的自定義注解。
Java 注解無疑增強(qiáng)了代碼的清晰度和表達(dá)性,減少對外部文檔的依賴。注解還有助于減少某些樣板代碼,例如,通過注解,我們可以定義依賴注入、ORM 映射和事務(wù)邊界等方面的功能。
盡管注解方便并具有多種優(yōu)勢,但一些開發(fā)者對某些注解還持懷疑態(tài)度。
19. 安全功能
我們編寫的程序不僅包含代碼行,還處理著用戶個(gè)人數(shù)據(jù)、財(cái)務(wù)信息和專有商業(yè)資料等敏感信息。用戶期望我們保護(hù)他們的信息,提供安全的使用環(huán)境。對企業(yè)而言,特別是那些涉及軟件開發(fā)或創(chuàng)新領(lǐng)域的企業(yè),防止知識產(chǎn)權(quán)泄露尤為關(guān)鍵。有效保護(hù)源代碼、算法和專有信息對于維持企業(yè)的競爭優(yōu)勢非常重要。
Java 提供了許多功能,使得開發(fā)安全應(yīng)用程序變得更加容易。這些功能包括加密、公鑰基礎(chǔ)設(shè)施(PKI)、安全通信、認(rèn)證和訪問控制等。此外,您還可以使用豐富的 API 和工具,輕松地將安全措施集成到您的 Java 應(yīng)用程序中,涵蓋從加密到智能卡 I/O 以及其他確保通信安全的認(rèn)證協(xié)議。
要了解更多可利用的安全功能,您可以參閱官方 Java 安全指南。
20. 豐富的 API 集
image.png
Java 以其豐富的應(yīng)用程序編程接口(API)著稱,為開發(fā)者提供了與各種軟件組件、庫和服務(wù)進(jìn)行標(biāo)準(zhǔn)化交互的方式。這些 API 提供了豐富的類、接口和方法集合,以便直接使用。
假設(shè)你正在從零開始構(gòu)建一輛汽車。使用 Java API 就像是在組裝供應(yīng)商生產(chǎn)的零部件,而不是自己制造這些零件。在這種情況下,您可以挑選完全滿足您需求的 API。這些 API 是標(biāo)準(zhǔn)化的、文檔完備的,且易于使用。
Java API 的優(yōu)勢在于它抽象了組件構(gòu)建的復(fù)雜細(xì)節(jié),讓您能夠?qū)W⒂诮M裝一個(gè)完全功能的汽車,即您的應(yīng)用程序。這些 API 能夠幫助您在網(wǎng)絡(luò)、IO、文件處理、數(shù)據(jù)庫連接、多線程等眾多領(lǐng)域完成各種任務(wù)。
Java API 分為多個(gè)包,其中一些最常用的包括 java.lang、java.util、java.io和 java.net。
21. Java 的性能提升
我選擇 Java 作為主要編程語言,部分原因是它不斷提高的性能,這讓我對 Java 更加忠誠和信任。
Java 性能方面的進(jìn)展在解決問題和構(gòu)建高性能應(yīng)用程序方面表現(xiàn)卓越,這些應(yīng)用能滿足現(xiàn)代客戶的需求。其中一些顯著的改進(jìn)包括:
Java 虛擬機(jī)(JVM)在每個(gè)新版本中都會(huì)推出一些重大優(yōu)化。這些優(yōu)化包括即時(shí)(JIT)編譯器的提升、垃圾收集機(jī)制的加強(qiáng),以及更為高效的運(yùn)行時(shí)分析,共同作用于提高程序執(zhí)行速度和降低內(nèi)存消耗。
Project Valhalla 引入的值類型特性,為我們定義了更加高效、緊湊的數(shù)據(jù)結(jié)構(gòu),這不僅減少了內(nèi)存消耗,還提高了緩存的局部性。在處理大規(guī)模數(shù)據(jù)時(shí),這種改進(jìn)帶來了顯著的性能提升。
最近,JDK 21 的發(fā)布引入了 15 項(xiàng)新特性,其中包括關(guān)鍵的封裝機(jī)制 API、虛擬線程,以及字符串模板和結(jié)構(gòu)化并發(fā)的預(yù)覽功能,這些更新顯著提升了 Java 的整體性能和功能。
JDK 21 中的虛擬線程和其他特性的飛躍
22. 結(jié)構(gòu)化并發(fā)的發(fā)展
結(jié)構(gòu)化并發(fā) API,作為 JDK 21 中的一個(gè)預(yù)覽特性,旨在簡化并發(fā)編程。它通過將不同線程中的相關(guān)任務(wù)視為單一工作單位,增強(qiáng)了錯(cuò)誤處理、取消、可靠性和可觀測性。這一特性并非意在替代 java.util.concurrent 中現(xiàn)有的并發(fā)工具。
結(jié)構(gòu)化并發(fā)特性將使開發(fā)者能夠擺脫在使用如 ExecutorService 和 Future 這類現(xiàn)有構(gòu)造進(jìn)行并發(fā)編程時(shí)所面臨的管理任務(wù)和子任務(wù)的復(fù)雜性。傳統(tǒng)上,任務(wù)和子任務(wù)之間缺乏固有的關(guān)系,這導(dǎo)致在錯(cuò)誤處理、取消和可觀測性方面的挑戰(zhàn)。提出的結(jié)構(gòu)化并發(fā)方法尋求將代碼的語法結(jié)構(gòu)與任務(wù)的運(yùn)行時(shí)層次結(jié)構(gòu)對齊,使并發(fā)編程更加可讀、可維護(hù)和可靠。這種方法在處理并發(fā)時(shí)將提供更清晰和更直觀的編程模型。
23. 虛擬線程
JDK 21 正式推出了 Virtual Threads(虛擬線程)這一特性,該特性最初在 JDK 19 和 JDK 20 中作為預(yù)覽功能亮相。傳統(tǒng)上,每一個(gè) java.lang.Thread 實(shí)例都綁定于一個(gè)平臺線程,與一個(gè)底層操作系統(tǒng)線程相關(guān)聯(lián)并貫穿其整個(gè)生命周期。
然而,虛擬線程帶來了一種新的編程范式。盡管 java.lang.Thread 的實(shí)例依然存在,但它們以一種不同的方式運(yùn)行,允許在底層操作系統(tǒng)線程上執(zhí)行 Java 代碼,而非獨(dú)占一個(gè)線程。這一創(chuàng)新實(shí)現(xiàn)了多個(gè)虛擬線程高效地共享同一個(gè)操作系統(tǒng)線程的能力。不同于平臺線程,虛擬線程不會(huì)占用珍貴的操作系統(tǒng)線程資源,并且它們的數(shù)量可以遠(yuǎn)超操作系統(tǒng)線程的限制。
虛擬線程是 JDK 21 中的一大亮點(diǎn),對于需要處理大量并發(fā)任務(wù)的應(yīng)用程序來說,尤其是任務(wù)數(shù)量可能超過數(shù)千的場景,它們能夠顯著提升程序性能。
如今,根據(jù)應(yīng)用程序的具體需求,開發(fā)者可以在虛擬線程和傳統(tǒng)的平臺線程之間做出選擇。
24. Switch 語句的模式匹配
這一特性源于 JDK 17 的提案,并在 JDK 18、JDK 19 和 JDK 20 中經(jīng)歷了一系列的完善和改進(jìn)?,F(xiàn)在,它將成為 JDK 21 的一部分,基于來自 Java 社區(qū)的反饋和經(jīng)驗(yàn),進(jìn)行了進(jìn)一步的優(yōu)化。
這個(gè)特性旨在增強(qiáng) switch 表達(dá)式和語句的功能和通用性。它著重于增強(qiáng) case 標(biāo)簽中模式的作用,以提供處理 null 值的更大靈活性,并通過要求模式匹配的 switch 語句全面覆蓋所有可能的輸入值,提高了 switch 語句的安全性。
如果你已經(jīng)在使用 switch 表達(dá)式和語句,無需擔(dān)憂;其目標(biāo)是確?,F(xiàn)有代碼能夠繼續(xù)像目前一樣正常運(yùn)行,無需作出任何修改。
25. 字符串模板
JDK 21 終于引入了長期以來開發(fā)者期盼的字符串模板特性,支持字符串插值。此前,唯一的選擇是拼接多個(gè)字符串或使用 string.format,這些方式不免顯得繁瑣。但在 Java 21 中,這一切將成為過去。新特性允許開發(fā)者將 Java 的字符串字面量和文本塊與字符串模板結(jié)合使用。
例如:
int x = 10;
int y = 20;
String s = STR."\{x} + \{y} = \{x + y}";
該特性的主要目的是簡化動(dòng)態(tài)字符串的創(chuàng)建,通過在運(yùn)行時(shí)編譯表達(dá)的值來實(shí)現(xiàn)。它還旨在提高代碼的可讀性,并解決與 StringBuilder 和 StringBuffer 類相關(guān)的冗余問題。此外,字符串模板還旨在解決與其他編程語言中現(xiàn)有的字符串插值技術(shù)相關(guān)的安全問題。
總結(jié)
Java 的易用性和性能都有了顯著的提升,這使得代碼更容易閱讀和維護(hù)。在 Java 中,你不必?fù)?dān)心自己或同事的代碼是否夠高級或復(fù)雜。我們也不妨承認(rèn),Java 開發(fā)人員的收入通常很高,這是因?yàn)樵S多大型的公司和組織都選擇 Java 作為他們的主要編程語言,從而創(chuàng)造了很多的工作機(jī)會(huì)。我認(rèn)識的一些人還在使用 Java 8,他們對此很滿意。
常見問題解答
為什么 Java 成為一種流行的編程語言?
Java 憑借其平臺獨(dú)立性、穩(wěn)健性以及強(qiáng)大的社區(qū)支持而廣受歡迎。它在從網(wǎng)站開發(fā)到企業(yè)級應(yīng)用各個(gè)領(lǐng)域廣泛應(yīng)用。
使用 Java 進(jìn)行企業(yè)級應(yīng)用開發(fā)有哪些優(yōu)勢?
Java 提供了穩(wěn)定性強(qiáng)、易于擴(kuò)展的開發(fā)環(huán)境,支持多線程處理,并配備了眾多框架和庫,例如 Spring Boot,這些特性極大地簡化了企業(yè)級應(yīng)用的開發(fā)。
Java 如何支持跨平臺開發(fā)?
Java 通過“一次編寫,到處運(yùn)行”的理念實(shí)現(xiàn)了跨平臺兼容性,允許開發(fā)者在任何裝有 Java 虛擬機(jī) (JVM) 的設(shè)備上運(yùn)行 Java 代碼。
譯者介紹
劉汪洋,51CTO社區(qū)編輯,昵稱:明明如月,一個(gè)擁有 5 年開發(fā)經(jīng)驗(yàn)的某大廠高級 Java 工程師,擁有多個(gè)主流技術(shù)博客平臺博客專家稱號。
原文標(biāo)題:25 REASONS WHY JAVA IS STILL AROUND IN 2023,作者:Digma