JavaRush /Java Blog /Random-TW /喝咖啡休息#37。Java 的新未來。2020 年後 JVM、Kotlin 和 Java 前景

喝咖啡休息#37。Java 的新未來。2020 年後 JVM、Kotlin 和 Java 前景

在 Random-TW 群組發布
來源:Medium Java 主要因兩件事而受到批評:冗長以及在許多情況下產生的大量樣板程式碼,但沒有明顯的需求。雖然我一直很喜歡Java,但我不能說這些說法是錯的。確實如此:Java 中過多的細節有時會非常煩人。然而,我們必須承認,我們並不生活在一個理想的世界,大多數情況下我們必須兩害相權取其輕。喝咖啡休息#37。 Java 的新未來。 2020 年後 JVM、Kotlin 和 Java 前景 - 1自誕生以來,Java 並不完美:我們都知道這一點,但真正的問題是為什麼之前沒有採取任何措施來解決這些問題。我認為改變花了這麼長時間的唯一原因是 Java 語言缺乏競爭,事情就這樣了。Java 佔據了市場主導地位,這可能是由於缺乏強有力的競爭對手以及 Sun 和 Oracle 的巨大努力。Java 提供的高水準類型安全性和良好的語言結構使其在大型專案中非常受歡迎。此外,它是一種在自己的虛擬機器上運行的多平台語言。與透過 JIT 編譯器進行的自動效能最佳化相結合,所有這些都可以最大限度地減少編寫不良程式碼的影響。總而言之,這就是使用 Java 的一系列非常令人信服的理由。但接下來發生了什麼事?發生的情況是,新的語言已經進入市場,可以在與 Java 相同的 JVM 中運行。這些語言消除了 Java 中一些最大的不便,並且在某些情況下為開發人員提供了一個更愉快的環境,並且進入門檻更低。在繼續之前,我們先回顧一下並簡要回顧一下 JVM 語言的歷史。

JVM 語言的歷史

首先,我想澄清一件事:我沒有提及一些現有的 JVM 語言,因為它們從未獲得足夠的支持,無法被視為在我們行業中廣泛使用的候選語言。現在讓我們開始簡要概述 JVM 語言的歷史。首先我們要介紹的是 Java,它是 JVM 世界中最古老、最受歡迎的語言。Java 於 1996 年 1 月正式發布,所以語言已經存在了 24 年。不錯吧?Java最初是一種純粹的命令式語言,遵循物件導向的程式設計風格;它也是一種強型別語言。Java 的語法有點類似 C++ 和 C 語言,但它被認為是改進版本,因為用 Java 編寫程式碼比用 C 或 C++ 容易得多。另一方面,他的批評者最大的論點是冗長。第二種 JVM 語言是 Groovy。它自 2003 年就已存在,儘管其第一個標準化版本 1.0 直到 2007 年 1 月才出現。Groovy 的優點是它可以用作腳本語言。Groovy 是一種動態類型語言,因此類型檢查是在執行時完成的。這就是為什麼一些開發人員不喜歡 Groovy 的原因之一。您用 Groovy 編寫程式碼,在編譯時看起來是正確的,但在運行時您意識到有些問題。然後另一種流行語言出現了:我們談論Scala。它於 2004 年發布。他為 JVM 世界帶來了一種新的工作模式:函數式程式設計和聲明式方法。基本上,Scala 是第一個引入不變性概念的語言,然後用於增強 Java。另一方面,批評者不喜歡 Scala,因為它的語法複雜且可讀性較低。JVM 世界中出現的下一種語言是 Clojure,一種純函數式語言。儘管它早在 2007 年就出現了,但它最近變得相當流行。Clojure 是一種基於 LISP 的語言,其特點是簡單且使用簡單的函數。它的缺點之一是它是動態類型的(像 Groovy 一樣)並且學習曲線要陡峭得多,因為它的語法與其他 JVM 語言完全不同。最後,我們有 Kotlin。Kotlin 於 2016 年 2 月首次出現,從那時起它的受歡迎程度就沒有停止增長。它由 JetBrains 開發,主要目標是:解決最著名的 Java 問題。從設計上來說,Kotlin 保留了 Java 的所有優點,但同時也解決了許多問題。這些是最重要的 JVM 語言。正如我所說,我們錯過了一些其他不太流行的語言:Jython、JRuby、Ceylon、Fantom 等。如果您願意,您可以找到現有 JVM 語言的完整列表在維基百科上。您可能已經意識到,Java 在其創建後的前八年或十年內並沒有太多競爭,但從那時起情況發生了變化。那麼,競爭是好事還是壞事呢?

增加競爭的好處

Java 在早期並沒有太大變化。可能是因為沒有必要。這種語言被廣泛使用並且一直很受歡迎,儘管它遠非完美。但隨後競爭對手出現了,更現代的語言提供了新功能並解決了一些長期困擾 Java 開發人員的問題。例如,讓我們來看看 Scala 語言。自 2009 年以來,Scala 的受歡迎程度一直在增長。開發人員歡迎這種新的功能風格,這給了他們更大的靈活性以及安全、輕鬆地編寫並行程式碼的能力。甲骨文如何因應這新趨勢?2014 年,Java Lambda 和 Streams 出現。我想我們都同意,這是 Java 向擊敗 Scala 邁出的最大一步。現在任何程式設計師都知道 Scala 不再流行。喝咖啡休息#37。 Java 的新未來。 2020 年後 JVM、Kotlin 和 Java 前景 - 2在 JVM 領域擁有更多競爭對手的另一個好處是 JIT 編譯器和 JVM 不斷改進。現在越來越多的人對優化 JVM 和提高效能感興趣。所以競爭對每個人都有好處!Java 的最新替代品是 Kotlin 語言。它的出現對於Java的發展非常重要,因為這種新語言在某種意義上為Oracle指明了前進的方向。Kotlin 範例表明,可以保留 Java 的優勢,但可以創建更緊湊的語言,從而可以更快地編寫程式碼。如果你查看 Google 趨勢圖,你可以看到從 2016 年到 2018 年,Kotlin 的受歡迎程度快速成長。但在過去的兩年裡,這種興奮感有所下降。喝咖啡休息#37。 Java 的新未來。 2020 年後的 JVM、Kotlin 和 Java 前景 - 3Oracle 仔細研究了業界對 Kotlin 的反應。如果您查看JDK 15 發行說明,您會發現一些新的 Java 功能是 Kotlin 中的功能的副本。這些是新的 Java 條目、新的文字區塊(帶有三引號的多行字串)和新的運算符switch,它本質上是 Kotlin 中運算符的副本when。我們談論的一切就是我所說的「Java 的 Kotlin 化」。透過成為更強大的競爭對手,Kotlin 向 Java 展示了應走的道路。

Java 的“Kotlin 化”

一些即將推出的 Java 功能將在可讀性方面進行重大改進,並將解決 Java 語言的最大弱點之一 - 冗長。有人可能會說,許多已發布的 Java 功能與 Kotlin 的某些功能非常相似。但請注意,其中大部分是預發布版本。這表示如果您安裝 JDK 14 或 JDK 15(當其發佈時),預設情況下您將無法使用它們。Java 功能預覽是版本中引入的新功能,但預設為停用。它們包含在新版本中只是為了收集開發者社群的回饋,因此它們可能仍然會發生變化。這就是為什麼不建議在生產代碼中使用它們的原因。要在編譯時啟用它們,您需要執行以下操作:
javac --enable-preview --release 14
如果您想在運行時啟用它們,您將需要執行以下命令:
java --enable-preview YourClass
當然,您也可以在 IDE 中啟用它們,但請注意不要在所有新專案中預設啟用預覽!讓我們來看看在未來的 Java 版本中會對我們的編碼產生較大影響的變化。

Java貼文

Java Records 是我們許多人長期以來一直渴望的功能。我猜您已經發現自己處於需要為每個現有欄位實作toStringhashCodeequals以及 getter 的情況。Kotlin 有資料類別來解決這個問題,Java 也打算透過發布Scala 已經以案例類別形式提供的記錄類別來解決這個問題。這些類別的主要目的是將不可變資料儲存在物件中。讓我們舉個例子來看看 Java 可以變得多好。這是我們需要編寫多少程式碼來創建和比較我們的類別: Employee
package com.theboreddev.java14;

import java.util.Objects;

public class Employee {
    private final String firstName;
    private final String surname;
    private final int age;
    private final Address address;
    private final double salary;

    public Employee(String firstName, String surname, int age, Address address, double salary) {
        this.firstName = firstName;
        this.surname = surname;
        this.age = age;
        this.address = address;
        this.salary = salary;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getSurname() {
        return surname;
    }

    public int getAge() {
        return age;
    }

    public Address getAddress() {
        return address;
    }

    public double getSalary() {
        return salary;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return age == employee.age &&
                Double.compare(employee.salary, salary) == 0 &&
                Objects.equals(firstName, employee.firstName) &&
                Objects.equals(surname, employee.surname) &&
                Objects.equals(address, employee.address);
    }

    @Override
    public int hashCode() {
        return Objects.hash(firstName, surname, age, address, salary);
    }

    @Override
    public String toString() {
        return "Employee{" +
                "firstName='" + firstName + '\'' +
                ", surname='" + surname + '\'' +
                ", age=" + age +
                ", address=" + address +
                ", salary=" + salary +
                '}';
    }
}
還有Address它所包含的物件:
import java.util.Objects;

public class Address {
    private final String firstLine;
    private final String secondLine;
    private final String postCode;

    public Address(String firstLine, String secondLine, String postCode) {
        this.firstLine = firstLine;
        this.secondLine = secondLine;
        this.postCode = postCode;
    }

    public String getFirstLine() {
        return firstLine;
    }

    public String getSecondLine() {
        return secondLine;
    }

    public String getPostCode() {
        return postCode;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Address address = (Address) o;
        return Objects.equals(firstLine, address.firstLine) &&
                Objects.equals(secondLine, address.secondLine) &&
                Objects.equals(postCode, address.postCode);
    }

    @Override
    public int hashCode() {
        return Objects.hash(firstLine, secondLine, postCode);
    }

    @Override
    public String toString() {
        return "Address{" +
                "firstLine='" + firstLine + '\'' +
                ", secondLine='" + secondLine + '\'' +
                ", postCode='" + postCode + '\'' +
                '}';
    }
}
對於如此簡單的事情來說,程式碼可能太多了,對吧?現在讓我們看看新的 Java 條目會是什麼樣子:
public record EmployeeRecord(String firstName, String surname, int age, AddressRecord address, double salary) {
}
我們不要忘記 Address 類別:
public record AddressRecord(String firstLine, String secondLine, String postCode) {
}
這和我們之前用這麼多程式碼寫的東西是一樣的。同意:這太棒了。以及我們將節省的程式碼量以及編寫的方便性!現在讓我們看看 new 運算子有什麼區別switch

改進的算子switch

Java中的新運算子switch將解決一些舊問題,包括一些錯誤和程式碼重複。有了新的運營商,switch這個問題將得到解決。為了用一個例子來解釋這一點,我們將DayOfTheWeek在 Java 中建立一個枚舉:
public enum DayOfTheWeek {
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY
}
之後,我們的switch將告訴我們一周中的哪個位置對應於這一天。讓我們先看看目前如何使用 Java 11 來做到這一點。
final DayOfTheWeek dayOfTheWeek = DayOfTheWeek.THURSDAY;

        int position = 0;

        switch (dayOfTheWeek) {
            case MONDAY:
                position = 1;
                break;
            case TUESDAY:
                position = 2;
                break;
            case WEDNESDAY:
                position = 3;
                break;
            case THURSDAY:
                position = 4;
                break;
            case FRIDAY:
                position = 5;
                break;
            case SATURDAY:
                position = 6;
                break;
            case SUNDAY:
                position = 7;
                break;
        }

        System.out.println("Day " + dayOfTheWeek + " is in position " + position + " of the week");
對於當前的語句,switch我們需要使用一個變量,如果我們錯過了一周中的某一天,我們的程式碼將可以正常編譯。這是操作員的問題之一switch:他們太容易出錯。那麼 Java 14 有何改進呢?我們來看一下:
final DayOfTheWeek dayOfTheWeek = DayOfTheWeek.THURSDAY;

        int position = switch (dayOfTheWeek) {
            case MONDAY -> 1;
            case TUESDAY -> 2;
            case WEDNESDAY -> 3;
            case THURSDAY -> 4;
            case FRIDAY -> 5;
            case SATURDAY -> 6;
            case SUNDAY -> 7;
        };

        System.out.println("Day " + dayOfTheWeek + " is in position " + position + " of the week");
正如您所看到的,新運算子switch可以用作表達式,而不僅僅是用作語句。結果更簡潔和富有表現力。這足以說服我們許多人使用它們,但主要改進之一是,現在switch除非我們涵蓋switch. 它會向我們顯示這個錯誤,例如:
Error:(9, 24) java: the switch expression does not cover all possible input values
從現在開始,我們的運算子將無法跳過大小寫switch。這與 Kotlin 中的運算符非常相似,您可以在文件when中閱讀有關內容。我們也看一下新的文字區塊。

文字區塊

您是否曾經抱怨過在 Java 中將JSON blob指派給變數有多困難?Java 具有多行序列,您可以將它們括在三引號中來描述它們。一旦這個功能正式發布,用多行描述長序列將變得更加容易。讓我們看看兩種模式之間的差異。如果我們想在變數中使用格式化的 JSON,結果會很糟糕:
final String text = "{\"widget\": {\n" +
                "    \"debug\": \"on\",\n" +
                "    \"window\": {\n" +
                "        \"title\": \"Sample Konfabulator Widget\",\n" +
                "        \"name\": \"main_window\",\n" +
                "        \"width\": 500,\n" +
                "        \"height\": 500\n" +
                "    },\n" +
                "    \"image\": { \n" +
                "        \"src\": \"Images/Sun.png\",\n" +
                "        \"name\": \"sun1\",\n" +
                "        \"hOffset\": 250,\n" +
                "        \"vOffset\": 250,\n" +
                "        \"alignment\": \"center\"\n" +
                "    },\n" +
                "    \"text\": {\n" +
                "        \"data\": \"Click Here\",\n" +
                "        \"size\": 36,\n" +
                "        \"style\": \"bold\",\n" +
                "        \"name\": \"text1\",\n" +
                "        \"hOffset\": 250,\n" +
                "        \"vOffset\": 100,\n" +
                "        \"alignment\": \"center\",\n" +
                "        \"onMouseUp\": \"sun1.opacity = (sun1.opacity / 100) * 90;\"\n" +
                "    }\n" +
                "}} ";
另一方面,當新的文字區塊發佈時,一切都會變得簡單得多:
final String multiLineText = """
                {"widget": {
                    "debug": "on",
                    "window": {
                        "title": "Sample Konfabulator Widget",
                        "name": "main_window",
                        "width": 500,
                        "height": 500
                    },
                    "image": {\s
                        "src": "Images/Sun.png",
                        "name": "sun1",
                        "hOffset": 250,
                        "vOffset": 250,
                        "alignment": "center"
                    },
                    "text": {
                        "data": "Click Here",
                        "size": 36,
                        "style": "bold",
                        "name": "text1",
                        "hOffset": 250,
                        "vOffset": 100,
                        "alignment": "center",
                        "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
                    }
                }}
                """;
這絕對看起來更好。所有這些都已在 Kotlin 中得到支持,您可以在其類型定義中看到。所以我們看到 Java 從它的競爭對手之一:Kotlin 那裡「繼承」了許多針對自身問題的解決方案。我們不知道 Oracle 是否及時應對了 Kotlin 的崛起,或者是否來得太晚了。就我個人而言,我相信 Java 正在向前邁出正確的一步,即使這些變化是由其競爭對手以某種方式發起的,並且可能會出現一些延遲。

結論

我認為競爭是 Java 語言有史以來發生過的最好的事情。我的印像是,否則 Java 就會固步自封。此外,Java 的競爭對手已經表明,不同的程式設計方式是可能的,顯示如何前進並避免過時且低效的程式碼編寫方式。未來的變化將使Java比以往任何時候都更強大,一種適應現代時代的語言,一種想要發展的語言。
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION