JavaRush /Blog Java /Random-VI /Nghỉ giải lao #37. Một tương lai mới cho Java. Triển vọng...

Nghỉ giải lao #37. Một tương lai mới cho Java. Triển vọng JVM, Kotlin và Java sau năm 2020

Xuất bản trong nhóm
Nguồn: Medium Java chủ yếu bị chỉ trích vì hai điều: tính dài dòng và số lượng mã soạn sẵn được tạo ra trong nhiều trường hợp mà không cần thiết rõ ràng. Mặc dù tôi luôn thích Java nhưng tôi không thể nói rằng những nhận định này là sai. Điều này thực sự đúng: quá nhiều chi tiết trong Java đôi khi có thể rất khó chịu. Tuy nhiên, chúng ta phải thừa nhận rằng chúng ta không sống trong một thế giới lý tưởng, và trong hầu hết các trường hợp, chúng ta phải chọn cái ít tệ hơn trong hai tệ nạn. Nghỉ giải lao #37.  Một tương lai mới cho Java.  Triển vọng JVM, Kotlin và Java sau năm 2020 - 1Kể từ khi ra đời, Java đã không hoàn hảo: tất cả chúng ta đều biết điều này, nhưng câu hỏi thực sự là tại sao trước đây chưa có gì được thực hiện để giải quyết những vấn đề này. Tôi nghĩ lý do duy nhất khiến những thay đổi mất nhiều thời gian như vậy là vì ngôn ngữ Java thiếu sự cạnh tranh và mọi thứ vẫn diễn ra như cũ. Java thống trị thị trường, có lẽ là do thiếu đối thủ cạnh tranh nghiêm túc và những nỗ lực to lớn đầu tiên của Sun và sau đó là Oracle. Mức độ an toàn kiểu cao mà Java cung cấp và cấu trúc tốt của ngôn ngữ đã khiến nó trở nên rất phổ biến đối với các dự án lớn. Ngoài ra, nó là ngôn ngữ đa nền tảng chạy trên máy ảo của riêng nó. Kết hợp với tối ưu hóa hiệu suất tự động thông qua trình biên dịch JIT, tất cả điều này giúp giảm thiểu tác động của mã được viết kém. Nói chung, đó là một loạt lý do khá thuyết phục để sử dụng Java. Nhưng chuyện gì đã xảy ra tiếp theo? Điều đã xảy ra là các ngôn ngữ mới đã xuất hiện trên thị trường có thể chạy trong cùng một JVM với Java. Các ngôn ngữ đã loại bỏ một số bất tiện lớn nhất trong Java và trong một số trường hợp, mang đến cho các nhà phát triển một môi trường dễ chịu hơn với rào cản gia nhập thấp hơn. Trước khi tiếp tục, chúng ta hãy xem lại và xem sơ qua lịch sử của các ngôn ngữ JVM.

Lịch sử ngôn ngữ JVM

Đầu tiên, tôi muốn làm rõ một điều: Tôi đã không đề cập đến một số ngôn ngữ JVM hiện có vì chúng chưa bao giờ có đủ sự hỗ trợ để được coi là ứng cử viên cho việc sử dụng rộng rãi trong ngành của chúng tôi. Bây giờ chúng ta hãy bắt đầu tổng quan ngắn gọn về lịch sử của các ngôn ngữ JVM. Đầu tiên chúng ta sẽ có Java, ngôn ngữ lâu đời nhất và phổ biến nhất trong thế giới JVM. Java được phát hành chính thức vào tháng 1 năm 1996, như vậy ngôn ngữ này đã tồn tại được 24 năm. Không tệ, phải không? Java ban đầu là một ngôn ngữ mệnh lệnh thuần túy theo phong cách lập trình hướng đối tượng; nó cũng là một ngôn ngữ được đánh máy mạnh mẽ. Cú pháp của Java hơi giống với ngôn ngữ C++ và C, nhưng nó được coi là phiên bản cải tiến vì viết mã bằng Java dễ hơn nhiều so với C hoặc C++. Mặt khác, chúng ta có lập luận lớn nhất trong số những người gièm pha anh ấy - tính dài dòng. Ngôn ngữ JVM thứ hai là Groovy. Nó đã xuất hiện từ năm 2003, mặc dù phiên bản tiêu chuẩn hóa đầu tiên của nó, 1.0, chỉ xuất hiện vào tháng 1 năm 2007. Ưu điểm của Groovy là nó có thể được sử dụng làm ngôn ngữ kịch bản. Groovy là ngôn ngữ được gõ động, do đó việc kiểm tra kiểu được thực hiện trong thời gian chạy. Đây là một trong những lý do khiến một số nhà phát triển không thích Groovy. Bạn viết mã của mình bằng Groovy và nó có vẻ đúng vào thời điểm biên dịch, nhưng sau đó trong thời gian chạy, bạn nhận ra có điều gì đó không ổn. Sau đó, một ngôn ngữ phổ biến khác xuất hiện: chúng ta nói về Scala. Nó được phát hành vào năm 2004. Anh ấy đã mang đến một mô hình làm việc mới cho thế giới JVM: lập trình hàm và cách tiếp cận khai báo. Về cơ bản, Scala là ngôn ngữ đầu tiên đưa ra khái niệm về tính bất biến, sau đó được sử dụng để nâng cao Java. Mặt khác, những người gièm pha không thích Scala vì ngữ pháp phức tạp và khả năng đọc khá thấp. Ngôn ngữ tiếp theo xuất hiện từ thế giới JVM là Clojure, một ngôn ngữ thuần túy chức năng. Nó đã trở nên khá phổ biến gần đây, mặc dù nó đã xuất hiện từ năm 2007. Clojure là ngôn ngữ dựa trên LISP được đặc trưng bởi tính đơn giản và cách sử dụng các hàm đơn giản. Một trong những nhược điểm của nó là nó được gõ động (như Groovy) và quá trình học tập dốc hơn nhiều do cú pháp của nó hoàn toàn khác với các ngôn ngữ JVM khác. Và cuối cùng, chúng ta có Kotlin. Kotlin xuất hiện lần đầu tiên vào tháng 2 năm 2016 và kể từ đó mức độ phổ biến của nó không ngừng tăng lên. Nó được JetBrains phát triển với mục tiêu chính: khắc phục các sự cố Java nổi tiếng nhất. Về mặt thiết kế, Kotlin vẫn giữ được tất cả những ưu điểm của Java nhưng đồng thời giải quyết được nhiều vấn đề. Đây là những ngôn ngữ JVM quan trọng nhất. Như tôi đã nói, chúng tôi đã bỏ lỡ một số ngôn ngữ khác không phổ biến lắm: Jython, JRuby, Ceylon, Fantom, v.v. Nếu muốn, bạn có thể tìm hiểu toàn bộ danh sách các ngôn ngữ JVM hiện cótrên Wikipedia. Có thể bạn đã nhận ra rằng Java không có nhiều cạnh tranh trong tám hoặc mười năm đầu tiên sau khi nó được tạo ra, nhưng mọi thứ đã thay đổi kể từ đó. Vậy cạnh tranh là tốt hay xấu?

Lợi ích của việc tăng cường cạnh tranh

Java đã không thay đổi nhiều trong những năm đầu. Có lẽ là vì nó không cần thiết. Ngôn ngữ này đã được sử dụng rộng rãi và luôn rất phổ biến, mặc dù thực tế là nó chưa hoàn hảo. Nhưng sau đó các đối thủ cạnh tranh xuất hiện, các ngôn ngữ hiện đại hơn cung cấp các tính năng mới và giải quyết một số vấn đề đã gây khó khăn cho các nhà phát triển Java trong một thời gian dài. Ví dụ: hãy xem ngôn ngữ Scala. Mức độ phổ biến của Scala đã tăng lên kể từ năm 2009. Các nhà phát triển hoan nghênh phong cách chức năng mới này, mang lại cho họ tính linh hoạt cao hơn cũng như khả năng viết mã song song một cách an toàn và dễ dàng. Oracle đã phản ứng thế nào với xu hướng mới này? Năm 2014, Java Lambdas và Streams xuất hiện. Tôi nghĩ tất cả chúng ta đều có thể đồng ý rằng đây là lúc Java thực hiện bước tiến lớn nhất để đánh bại Scala. Bây giờ bất kỳ lập trình viên nào cũng biết rằng Scala không còn hợp thời nữa. Nghỉ giải lao #37.  Một tương lai mới cho Java.  Triển vọng JVM, Kotlin và Java sau năm 2020 - 2Một lợi ích khác của việc có nhiều đối thủ cạnh tranh hơn trong thế giới JVM là những cải tiến liên tục được thực hiện đối với trình biên dịch JIT và JVM. Hiện nay có rất nhiều người quan tâm đến việc tối ưu hóa JVM và cải thiện hiệu suất. Vì vậy, cạnh tranh là tốt cho tất cả mọi người! Ngôn ngữ thay thế gần đây nhất cho Java là ngôn ngữ Kotlin. Sự xuất hiện của nó rất quan trọng đối với sự phát triển của Java, vì ngôn ngữ mới, theo một nghĩa nào đó, đã chỉ ra con đường phía trước cho Oracle. Ví dụ về Kotlin cho thấy rằng có thể duy trì các ưu điểm của Java nhưng tạo ra một ngôn ngữ nhỏ gọn hơn để viết mã nhanh hơn. Nếu nhìn vào biểu đồ Google Trends, bạn có thể thấy rằng từ năm 2016 đến 2018, mức độ phổ biến của Kotlin đã tăng lên nhanh chóng. Nhưng trong hai năm qua, sự phấn khích đã giảm đi. Nghỉ giải lao #37.  Một tương lai mới cho Java.  Triển vọng JVM, Kotlin và Java sau năm 2020 - 3Oracle đã xem xét kỹ lưỡng phản ứng của ngành đối với Kotlin. Nếu xem ghi chú phát hành JDK 15 , bạn sẽ thấy rằng một số tính năng Java mới là bản sao của những gì có trong Kotlin. Đây là các mục Java mới , các khối văn bản mới (chuỗi nhiều dòng có ba dấu ngoặc kép) và một toán tử mới switch, về cơ bản là bản sao của toán tử whentrong Kotlin. Mọi thứ chúng ta đã nói đến đều là thứ mà tôi gọi là “Kotlinization của Java”. Bằng cách trở thành một đối thủ cạnh tranh mạnh hơn, Kotlin đã chỉ cho Java con đường phải đi.

"Kotlin hóa" Java

Một số tính năng sắp tới của Java sẽ là những cải tiến đáng kể về khả năng đọc và sẽ giải quyết một trong những điểm yếu lớn nhất của ngôn ngữ Java - tính dài dòng của nó. Người ta có thể lập luận rằng nhiều tính năng Java được công bố giống một cách đáng ngờ với một số tính năng của Kotlin. Nhưng xin lưu ý rằng hầu hết chúng đều là phiên bản tiền phát hành . Điều này có nghĩa là nếu bạn cài đặt JDK 14 hoặc JDK 15 (khi nó được phát hành), bạn sẽ không thể sử dụng chúng theo mặc định. Bản xem trước tính năng Java là các tính năng mới được giới thiệu trong một bản phát hành nhưng bị tắt theo mặc định. Chúng chỉ được đưa vào phiên bản mới để thu thập phản hồi từ cộng đồng nhà phát triển, vì vậy chúng vẫn có thể thay đổi. Đây là lý do tại sao không nên sử dụng chúng trong mã sản xuất. Để kích hoạt chúng tại thời điểm biên dịch, bạn sẽ cần phải làm như sau:
javac --enable-preview --release 14
Nếu bạn muốn kích hoạt chúng trong thời gian chạy, bạn sẽ cần chạy như sau:
java --enable-preview YourClass
Tất nhiên, bạn cũng có thể kích hoạt chúng trong IDE của mình, nhưng hãy cẩn thận không bật chế độ xem trước theo mặc định trong tất cả các dự án mới của bạn! Chúng ta hãy xem những thay đổi sẽ có tác động lớn hơn đến việc mã hóa của chúng ta trong các phiên bản Java trong tương lai.

Bài viết Java

Bản ghi Java là một tính năng mà nhiều người trong chúng ta đã yêu thích từ lâu. Tôi đoán bạn đã rơi vào tình huống cần triển khai toString , hashCode , Equals cũng như getters cho mọi trường hiện có. Kotlin có các lớp dữ liệu để giải quyết vấn đề này và Java dự định làm điều tương tự bằng cách phát hành các lớp bản ghi mà Scala đã có dưới dạng các lớp trường hợp . Mục đích chính của các lớp này là lưu trữ dữ liệu bất biến trong một đối tượng. Hãy lấy một ví dụ để xem Java có thể trở nên tốt hơn như thế nào. Đây là số lượng mã chúng ta phải viết để tạo và so sánh lớp của mình 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 +
                '}';
    }
}
Và cũng là đối tượng Addresschứa nó:
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 + '\'' +
                '}';
    }
}
Có lẽ có quá nhiều mã cho một thứ quá đơn giản phải không? Bây giờ chúng ta hãy xem nó trông như thế nào với các mục Java mới:
public record EmployeeRecord(String firstName, String surname, int age, AddressRecord address, double salary) {
}
Và đừng quên lớp Địa chỉ:
public record AddressRecord(String firstLine, String secondLine, String postCode) {
}
Đây chính là điều chúng tôi đã viết trước đó với rất nhiều mã. Đồng ý: điều này thật tuyệt vời. Và số lượng mã chúng ta sẽ tiết kiệm cũng như sự dễ dàng khi viết! Bây giờ chúng ta hãy xem sự khác biệt của toán tử mới là gì switch.

Toán tử cải tiếnswitch

Toán tử mới switchtrong Java sẽ giải quyết một số vấn đề cũ, bao gồm một số lỗi và trùng lặp mã. Với nhà điều hành mới, switchvấn đề này sẽ được giải quyết. Để giải thích điều này bằng một ví dụ, chúng ta sẽ tạo một enum DayOfTheWeektrong Java:
public enum DayOfTheWeek {
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY
}
Sau đó, chúng tôi switchsẽ cho chúng tôi biết vị trí nào trong tuần tương ứng với ngày đó. Trước tiên hãy xem cách chúng ta có thể thực hiện việc này bằng cách sử dụng 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");
Với câu lệnh hiện tại, switchchúng ta sẽ cần sử dụng một biến và nếu chúng ta bỏ lỡ một trong những ngày trong tuần, mã của chúng ta sẽ biên dịch tốt. Đây là một trong những vấn đề với người vận hành switch: họ rất dễ mắc lỗi. Vậy Java 14 cải thiện mọi thứ như thế nào? Chúng ta hãy xem:
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");
Như bạn có thể thấy, các toán tử mới switchcó thể được sử dụng như một biểu thức chứ không chỉ như một câu lệnh. Kết quả ngắn gọn và biểu cảm hơn. Điều này đủ để thuyết phục nhiều người trong chúng ta sử dụng chúng, nhưng một trong những cải tiến chính là giờ đây các câu lệnh switchsẽ không được biên dịch trừ khi chúng tôi bao gồm tất cả các trường hợp trong switch. Nó sẽ hiển thị cho chúng ta lỗi này, ví dụ:
Error:(9, 24) java: the switch expression does not cover all possible input values
Từ giờ trở đi, sẽ không thể bỏ qua trường hợp trong các toán tử của chúng tôi switch. Điều này rất giống với các toán tử whentrong Kotlin mà bạn có thể đọc trong tài liệu . Chúng ta cũng hãy xem các khối văn bản mới.

Khối văn bản

Bạn đã bao giờ phàn nàn về việc gán một blob JSON cho một biến trong Java khó đến mức nào chưa? Java có các chuỗi nhiều dòng mà bạn có thể mô tả bằng cách đặt chúng trong dấu ngoặc kép. Sau khi tính năng này được phát hành chính thức, việc mô tả các chuỗi dài trên nhiều dòng sẽ trở nên dễ dàng hơn nhiều. Chúng ta hãy xem sự khác biệt giữa hai chế độ. Nếu chúng ta muốn sử dụng JSON được định dạng trong một biến thì kết quả sẽ không tốt:
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" +
                "}} ";
Mặt khác, khi các khối văn bản mới được phát hành, mọi thứ sẽ trở nên đơn giản hơn rất nhiều:
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;"
                    }
                }}
                """;
Điều này chắc chắn trông tốt hơn. Tất cả những điều này đã được hỗ trợ trong Kotlin, như bạn có thể thấy trong định nghĩa kiểu của nó . Vì vậy, chúng ta đã thấy rằng Java “kế thừa” nhiều giải pháp cho các vấn đề của riêng nó từ một trong những đối thủ cạnh tranh của nó: Kotlin. Chúng tôi không biết liệu Oracle có phản ứng kịp thời để chống lại sự trỗi dậy của Kotlin hay đã đến quá muộn. Cá nhân tôi tin rằng Java đang có những bước đi đúng đắn, ngay cả khi những thay đổi này được các đối thủ cạnh tranh của nó khởi xướng bằng cách nào đó và có thể đi kèm với một số chậm trễ.

Phần kết luận

Tôi nghĩ cạnh tranh là điều tuyệt vời nhất từng xảy ra với ngôn ngữ Java. Ấn tượng của tôi là nếu không thì Java sẽ tận hưởng được vinh quang của mình. Ngoài ra, các đối thủ cạnh tranh của Java đã chỉ ra rằng có thể có một cách lập trình khác, chỉ ra cách tiến lên phía trước và tránh những cách viết mã lỗi thời và kém hiệu quả. Những thay đổi trong tương lai sẽ khiến Java trở nên mạnh mẽ hơn bao giờ hết, một ngôn ngữ thích nghi với thời kỳ hiện đại, một ngôn ngữ luôn muốn phát triển.
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION