JavaRush /Blog Java /Random-VI /Từ 8 đến 13: tổng quan đầy đủ về các phiên bản Java. Phần...

Từ 8 đến 13: tổng quan đầy đủ về các phiên bản Java. Phần 2

Xuất bản trong nhóm
Bài viết này là phần thứ hai trong bài đánh giá của tôi về những đổi mới trong phiên bản Java 8-13. Phần đầu tiên là ở đây . Không chần chừ gì nữa, hãy chuyển sang ngày 25 tháng 9 năm 2018, khi JDK mới được phát hành:

Java 11

Từ 8 đến 13: tổng quan đầy đủ về các phiên bản Java.  Phần 2 - 1

var (trong lambda)

Từ giờ trở đi, chúng ta có thể chỉ định các loại tham số lambda hoặc bỏ qua chúng khi viết biểu thức lambda (biểu thức lambda được gõ ngầm):
Function<String, String> append = (var string) -> string + " Text";
String appendedString = append.apply("Some");
System.out.println(appendedString);
Bạn cũng có thể thêm chú thích vào tham số lambda mà không cần phải viết tên loại biến đầy đủ:
Function<String, String> append = (@NonNull var string) -> string + " Text";

Z(ZGC)

ZGC là một trình thu gom rác mới không hoạt động. Nó phân bổ bộ nhớ mới nhưng không bao giờ khởi động lại nó. ZGC hứa hẹn sẽ quản lý lượng bộ nhớ lớn với thông lượng cao và độ trễ thấp (ZGC chỉ khả dụng trên nền tảng 64-bit). Tô màu tham chiếu - ZGC sử dụng con trỏ 64 bit với kỹ thuật gọi là tô màu con trỏ. Con trỏ màu lưu trữ thông tin bổ sung về các đối tượng trên heap. Khi bộ nhớ bị phân mảnh, điều này giúp tránh suy giảm hiệu suất khi GC cần tìm chỗ cho phân bổ mới. Việc thu gom rác bằng ZGC bao gồm các bước sau:
  1. thế giới dừng lại: chúng tôi tìm kiếm điểm bắt đầu để tiếp cận các đối tượng trên vùng nhớ heap (chẳng hạn như biến cục bộ hoặc trường tĩnh);
  2. giao điểm của đồ thị đối tượng bắt đầu từ các liên kết gốc. Chúng tôi đánh dấu từng đối tượng mà chúng tôi tiếp cận (ZGC đi qua biểu đồ đối tượng và kiểm tra các điểm đánh dấu màu, đánh dấu các đối tượng có sẵn);
  3. xử lý một số trường hợp khó khăn, chẳng hạn như liên kết yếu;
  4. di chuyển các đối tượng sống, giải phóng các vùng lớn của heap để tăng tốc độ phân bổ.
  5. khi giai đoạn di chuyển bắt đầu, ZGC chia vùng heap thành các trang và xử lý từng trang một;
  6. ZGC kết thúc chuyển động của bất kỳ rễ nào và phần còn lại của chuyển động sẽ diễn ra.
Chủ đề này rất phức tạp và khó hiểu. Một cuộc thảo luận chi tiết sẽ yêu cầu một bài viết riêng, vì vậy tôi sẽ chỉ để nó ở đây:

Epsilon GC

Epsilon là trình thu gom rác xử lý việc cấp phát bộ nhớ nhưng không triển khai bất kỳ cơ chế khôi phục bộ nhớ thực nào. Khi vùng heap Java có sẵn đã cạn kiệt, JVM sẽ tắt. Nghĩa là, nếu bạn bắt đầu tạo một đối tượng trong một mảng vô hạn mà không liên kết với một tham chiếu bằng trình thu gom rác này, thì ứng dụng sẽ gặp sự cố với OutOfMemoryError (và nếu có bất kỳ đối tượng nào khác thì sẽ không, vì nó sẽ dọn sạch các đối tượng không có tham chiếu) . Tại sao nó lại cần thiết? Đây là lý do tại sao:
  1. Kiểm tra năng suất.
  2. Kiểm tra áp lực bộ nhớ.
  3. Kiểm tra giao diện VM.
  4. Công việc cực kỳ ngắn.
  5. Cải thiện độ trễ ở lần thả cuối cùng.
  6. Cải thiện thông lượng ở lần thả cuối cùng.
Liên kết hữu ích: Những đổi mới khác:
  1. ByteArrayOutputStreamcó một phương thức void writeBytes(byte [])ghi tất cả các byte từ đối số vào OutputStream.
  2. FileReaderFileWritercó các hàm tạo mới cho phép bạn chỉ định Bộ ký tự.
  3. Pathlấy hai phương thức mới, of(String, String [])trả về Pathtừ một đối số chuỗi một đường dẫn hoặc chuỗi các chuỗi mà khi kết hợp sẽ tạo thành một chuỗi đường dẫn và of(URI): trả về Đường dẫn từ một URI.
  4. Pattern— đã nhận được một phương thức asMatchPredicate()kiểm tra xem một chuỗi đầu vào nhất định có khớp với một mẫu nhất định hay không (liệu nó có cho phép bạn tạo một vị từ bằng cách sử dụng biểu thức chính quy để bạn có thể lọc dữ liệu trong luồng chẳng hạn hay không).
  5. StringTôi đã chọn ra nhiều phương pháp hữu ích, chẳng hạn như:
    • String strip(): sẽ trả về cho chúng ta một chuỗi là chuỗi này, với tất cả khoảng trắng ở đầu và cuối chuỗi bị loại bỏ (tương tự như Trim(), nhưng xác định khoảng trắng theo cách khác);
    • String stripLeading(): sẽ trả về cho chúng ta chuỗi đó là chuỗi này, loại bỏ mọi khoảng trắng ở đầu chuỗi;
    • String stripTrailing(): sẽ trả về cho chúng ta chuỗi chính là chuỗi này, loại bỏ mọi khoảng trắng ở cuối chuỗi;
    • Stream lines(): sẽ trả về cho chúng ta Streamtừ String, được trích xuất từ ​​chuỗi này, được phân tách bằng dấu phân cách dòng;
    • String repeat(int): sẽ trả về cho chúng ta một chuỗi là chuỗi nối của chuỗi này, được lặp lại một số lần.
    • boolean isBlank(): sẽ trả về true nếu chuỗi trống hoặc chỉ chứa khoảng trắng, ngược lại là false.
  6. Thread— các phương thức destroy() và stop(Ném được) đã bị xóa.
  7. Filescó một số phương pháp mới:
    • String readString(Path): đọc tất cả dữ liệu từ một tệp thành một chuỗi, đồng thời giải mã từ byte thành ký tự bằng mã hóa UTF-8;
    • String readString(Path, Charset): giống như trong phương pháp trên, với điểm khác biệt là việc giải mã từ byte thành ký tự xảy ra bằng cách sử dụng Bộ ký tự được chỉ định;
    • Path writeString (Path, CharSequence, OpenOption []): Ghi một chuỗi ký tự vào một tập tin. Các ký tự được mã hóa thành byte bằng mã hóa UTF-8;
    • Path writeString(Path, CharSequence,Charset, OpenOption []): Phương pháp tương tự như trên, chỉ các ký tự được mã hóa thành byte bằng cách sử dụng mã hóa được chỉ định trong Charset.
Đây là những cải tiến API thú vị nhất (theo ý kiến ​​khiêm tốn của tôi), đây là một số tài liệu để đánh giá chi tiết hơn:

Java 12

Sáu tháng trôi qua và chúng ta thấy giai đoạn tiếp theo trong quá trình phát triển của Java. Vì vậy, đã đến lúc lấy xẻng kiến ​​thức ra và đào bới. Từ 8 đến 13: tổng quan đầy đủ về các phiên bản Java.  Phần 2 - 2

Cập nhật G1

Những cải tiến sau đây đã được thực hiện cho G1:
  1. Đòi lại bộ nhớ được phân bổ không sử dụng

    Trong bộ nhớ heap Java có một thứ gọi là bộ nhớ không được sử dụng (hay nói cách khác là không hoạt động). Trong Java 12, họ đã quyết định khắc phục sự cố này ngay bây giờ:

    • G1 trả về bộ nhớ từ vùng heap trong một GC đầy đủ hoặc trong một vòng lặp song song; G1 cố gắng ngăn GC đầy đủ và bắt đầu một vòng lặp song song dựa trên phân bổ vùng heap. Chúng ta sẽ phải buộc G1 trả lại bộ nhớ từ heap.

    Cải tiến này tập trung vào hiệu suất bằng cách tự động trả lại bộ nhớ từ heap về HĐH khi G1 không được sử dụng.

  2. Hủy bỏ các bộ sưu tập hỗn hợp khi vượt quá thời gian tạm dừng

    G1 sử dụng công cụ phân tích để chọn khối lượng công việc cần thiết cho việc thu gom rác. Nó thu thập các đối tượng sống mà không dừng lại sau khi xác định tập hợp và bắt đầu dọn dẹp. Điều này khiến trình thu gom rác vượt quá mục tiêu thời gian tạm dừng. Trên thực tế, vấn đề này được giải quyết bằng cách cải tiến, vì nếu thời gian cần thiết để hoàn thành bước tiếp theo vượt quá giới hạn hợp lý thì bước này có thể bị gián đoạn.

Điểm chuẩn vi mô

Java 12 đã giới thiệu các thử nghiệm đo điểm chuẩn vi mô để có thể dễ dàng kiểm tra hiệu suất của JVM bằng các điểm chuẩn hiện có. Điều này sẽ rất hữu ích cho những ai muốn làm việc trên chính JVM. Các thử nghiệm bổ sung được tạo bằng cách sử dụng Java Microbenchmark Harness (JMH). Các thử nghiệm này cho phép thử nghiệm hiệu năng liên tục trên JVM. JEP 230 đề xuất giới thiệu khoảng 100 bài kiểm tra, với các bài kiểm tra mới được giới thiệu khi các phiên bản Java mới được phát hành. Đây là một ví dụ về các bài kiểm tra đang được thêm vào .

Shenandoah

Đây là thuật toán thu gom rác (GC) có mục tiêu là đảm bảo thời gian phản hồi thấp (giới hạn thấp hơn là 10-500 ms). Điều này giúp giảm thời gian tạm dừng GC khi thực hiện công việc dọn dẹp đồng thời với việc chạy các luồng Java. Ở Shenandoah, thời gian tạm dừng không phụ thuộc vào kích thước vùng heap. Điều này có nghĩa là thời gian tạm dừng sẽ giống nhau bất kể kích thước vùng heap của bạn. Đây là một tính năng thử nghiệm và không có trong bản dựng tiêu chuẩn (Oracle) của OpenJDK.

Cải thiện chuyển đổi

Java 12 đã cải tiến biểu thức Switch để khớp mẫu. Cú pháp mới L → được giới thiệu. Dưới đây là danh sách các điểm chính của công tắc mới :
  1. Cú pháp mới loại bỏ sự cần thiết của câu lệnh break để ngăn ngừa lỗi.
  2. Chuyển đổi biểu thức không còn thất bại nữa.
  3. Ngoài ra, chúng ta có thể định nghĩa nhiều hằng số trong một nhãn.
  4. trường hợp mặc định hiện được yêu cầu trong biểu thức chuyển đổi.
  5. break được sử dụng trong biểu thức Switch để trả về các giá trị từ chính thanh ghi (trên thực tế, một switch có thể trả về các giá trị).
Hãy xem đây là một ví dụ:
var result = switch (someDay) {
  case "M", "W", "F" -> "MWF";
  case "T", "TH", "S" -> "TTS";
  default -> {
      if(someDay.isEmpty())
            break "Please insert a valid day.";
      else
            break "Looks like a Sunday.";
  }
};
Hướng dẫn dứt khoát để chuyển đổi biểu thức trong Java 13 Các tính năng mới khác:
  1. String:

    transform(Function f)- Áp dụng hàm được cung cấp cho một chuỗi. Kết quả có thể không phải là một chuỗi.
    indent(int x)— thêm x dấu cách vào chuỗi. Nếu tham số âm thì số khoảng trắng ở đầu này sẽ bị xóa (nếu có thể).

  2. Files- lấy một phương thức như mismatch(), lần lượt tìm và trả về vị trí của byte không khớp đầu tiên trong nội dung của hai tệp hoặc -1L nếu không có giá trị không khớp.

  3. Một lớp mới đã xuất hiện -CompactNumberFormat để định dạng số thập phân ở dạng thu gọn. Một ví dụ về dạng thu gọn này là 1M thay vì 1.000.000. Do đó, chỉ cần hai hai thay vì chín ký tự.

  4. Ngoài ra còn có một cái mới enum , NumberFormatStylecó hai giá trị - DÀI và NGẮN.

  5. InputStream có phương thức skipNBytes(long n) : bỏ qua số byte thứ n từ luồng đầu vào.

Các liên kết Java 12 thú vị:

Java 13

Thế giới không đứng yên, nó chuyển động, nó phát triển, giống như Java - Java 13. Từ 8 đến 13: tổng quan đầy đủ về các phiên bản Java.  Phần 2 - 3

Khối văn bản

Java luôn gặp khó khăn một chút khi xác định chuỗi. Nếu chúng tôi cần xác định một dòng có dấu cách, ngắt dòng, trích dẫn hoặc thứ gì khác, điều này gây ra một số khó khăn, vì vậy chúng tôi phải sử dụng các ký tự đặc biệt: ví dụ: \n để ngắt dòng hoặc thoát khỏi một số dòng chính nó. Điều này làm giảm đáng kể khả năng đọc mã và mất thêm thời gian khi viết một dòng như vậy. Điều này trở nên đặc biệt đáng chú ý khi viết các chuỗi hiển thị JSON, XML, HTML, v.v. Kết quả là, nếu chúng ta muốn viết một Json nhỏ, nó sẽ trông giống như thế này:
String JSON_STRING = "{\r\n" + "\"name\" : \"someName\",\r\n" + "\"site\" : \"https://www.someSite.com/\"\r\n" + "}";
Và sau đó Java 13 xuất hiện và cung cấp cho chúng ta giải pháp của nó dưới dạng ba dấu ngoặc kép trước và sau văn bản (mà họ gọi là khối văn bản). Hãy xem ví dụ json trước sử dụng cải tiến này:
String TEXT_BLOCK_JSON = """
{
    "name" : "someName",
    "site" : "https://www.someSite.com/"
}
""";
Đơn giản và rõ ràng hơn nhiều phải không? StringBa phương pháp mới cũng lần lượt được thêm vào để quản lý các khối này:
  • stripIndent(): Loại bỏ các khoảng trắng ngẫu nhiên khỏi một chuỗi. Điều này hữu ích nếu bạn đang đọc các chuỗi nhiều dòng và muốn áp dụng cùng loại loại trừ khoảng trắng ngẫu nhiên xảy ra với một khai báo rõ ràng (về cơ bản là mô phỏng trình biên dịch để loại bỏ khoảng trắng ngẫu nhiên);
  • formatted(Object... args ): tương tự như format(String format, Object... arg), nhưng dành cho khối văn bản;
  • translateEscapes(): Trả về một chuỗi có các chuỗi thoát (chẳng hạn như \r) được dịch sang giá trị Unicode tương ứng.

Cải thiện chuyển đổi

Các biểu thức chuyển đổi đã được giới thiệu trong Java 12 và 13 đã tinh chỉnh chúng. Trong 12 bạn xác định giá trị trả về bằng cách sử dụng break. Trong 13, giá trị trả về được thay thế bằng lợi nhuận. Bây giờ biểu thức switch mà chúng ta có trong phần Java 12 có thể được viết lại thành:
var result = switch (someDay) {
  case "M", "W", "F" -> "MWF";
  case "T", "TH", "S" -> "TTS";
  default -> {
      if(someDay.isEmpty())
          yield "Please insert a valid day.";
      else
          yield "Looks like a Sunday.";
  }
};
Mặc dù việc chấp nhận tạm nghỉ là điều bình thường đối với những lập trình viên đã quen thuộc với Java, nhưng điều đó vẫn khá kỳ lạ. Sự thật đang cố nói với tôi là gì? Từ khóa lợi nhuận mới (tương đối mới) rõ ràng hơn và có thể xuất hiện ở những nơi khác trong tương lai nơi các giá trị được trả về. Đối với những người quan tâm sâu sắc đến chủ đề này, tôi khuyên bạn nên tự làm quen với các tài liệu sau:

Lưu trữ CDS động

CDS - Chia sẻ dữ liệu lớp. Cho phép bạn đóng gói một tập hợp các lớp thường được sử dụng vào một kho lưu trữ mà sau này có thể được tải bởi nhiều phiên bản JVM. Tại sao chúng ta cần điều này? Thực tế là trong quá trình tải các lớp, JVM thực hiện khá nhiều hành động tiêu tốn nhiều tài nguyên, chẳng hạn như đọc các lớp, lưu trữ chúng trong cấu trúc bên trong, kiểm tra tính chính xác của các lớp đã đọc, tìm kiếm và tải các lớp phụ thuộc, v.v. ., và chỉ sau tất cả những điều này thì các lớp mới sẵn sàng hoạt động. Có thể hiểu được rằng rất nhiều tài nguyên bị lãng phí vì các phiên bản JVM thường có thể tải các lớp giống nhau. Ví dụ: Chuỗi, LinkedList, Integer. Chà, hoặc các lớp của cùng một ứng dụng và tất cả những thứ này đều là tài nguyên. Nếu chúng tôi thực hiện tất cả các bước cần thiết chỉ một lần rồi đặt các lớp được thiết kế lại vào một kho lưu trữ có thể được tải vào bộ nhớ của một số JVM, thì điều này có thể tiết kiệm đáng kể dung lượng bộ nhớ và giảm thời gian khởi động ứng dụng. Trên thực tế, CDS có thể tạo ra một kho lưu trữ như vậy. Java 9 chỉ cho phép thêm các lớp hệ thống vào kho lưu trữ. Java 10 - bao gồm các lớp ứng dụng trong kho lưu trữ. Việc tạo ra một kho lưu trữ như vậy bao gồm:
  • tạo danh sách các lớp được ứng dụng tải;
  • tạo một kho lưu trữ rất cần thiết với các lớp mà chúng tôi đã tìm thấy.
Sự đổi mới trong Java 13 cải thiện CDS để có thể tạo kho lưu trữ khi ứng dụng kết thúc. Điều này có nghĩa là hai bước trên bây giờ sẽ được kết hợp thành một. Và một điểm quan trọng hơn: chỉ những lớp được tải khi ứng dụng đang chạy mới được thêm vào kho lưu trữ. Nói cách khác, những lớp vẫn có trong application.jar nhưng vì lý do nào đó không được tải sẽ không được thêm vào kho lưu trữ.

Cập nhật API ổ cắm

API Socket ( java.net.Socket và java.net.ServerSocket ) về cơ bản là một phần không thể thiếu của Java kể từ khi ra đời, nhưng các socket chưa bao giờ được cập nhật trong hai mươi năm qua. Được viết bằng C và Java, chúng rất, rất cồng kềnh và khó bảo trì. Nhưng Java 13 đã quyết định tự điều chỉnh toàn bộ vấn đề này và thay thế việc triển khai cơ sở. Bây giờ, thay vì PlainSocketImpl, giao diện nhà cung cấp được thay thế bằng NioSocketImpl . Việc triển khai mã hóa mới này dựa trên cơ sở hạ tầng phụ trợ giống như java.nio . Về cơ bản, lớp này sử dụng cơ chế khóa và bộ đệm đệm java.util.concurrent (dựa trên phân đoạn) thay vì các phương thức được đồng bộ hóa. Nó không còn yêu cầu mã gốc nữa, giúp việc chuyển sang các nền tảng khác nhau dễ dàng hơn. Tuy nhiên, chúng ta vẫn có cách để quay lại sử dụng PlainSocketImpl , nhưng từ giờ trở đi NioSocketImpl được sử dụng theo mặc định .

Trả lại bộ nhớ cho ZGC

Như chúng ta đã nhớ, trình thu gom rác Z đã được giới thiệu trong Java 11 dưới dạng cơ chế thu gom rác có độ trễ thấp để thời gian tạm dừng GC không bao giờ vượt quá 10 mili giây. Nhưng đồng thời, không giống như các GC HotSpots ảo khác, chẳng hạn như Shenandoah và G1, nó có thể trả lại bộ nhớ động chưa sử dụng cho HĐH. Sửa đổi này bổ sung khả năng J này cho ZGC. Theo đó, chúng tôi giảm dung lượng bộ nhớ cùng với hiệu suất được cải thiện và ZGC hiện trả lại bộ nhớ chưa được cam kết cho hệ điều hành theo mặc định cho đến khi đạt được kích thước vùng nhớ heap tối thiểu được chỉ định. Một điều nữa: ZGC hiện có kích thước heap được hỗ trợ tối đa là 16 TB. Trước đây, 4TB là giới hạn. Những đổi mới khác:
  1. javax.security- đã thêm thuộc tính jdk.sasl.disabledMechanismsđể vô hiệu hóa cơ chế SASL.
  2. java.nio- một phương thức đã được thêm vào FileSystems.newFileSystem (Path, Map <String,?>)- tương ứng, để tạo một tệp mới.
  3. Các lớp java.niobây giờ có các phương thức tuyệt đối (ngược lại với tương đối) getset-. Chúng, giống như lớp trừu tượng cơ sở Buffer, bao gồm một phương thức slice()để truy xuất một phần bộ đệm.
  4. Đã thêm javax.xml.parserscác phương thức để khởi tạo các nhà máy DOM và SAX (có hỗ trợ không gian tên).
  5. Hỗ trợ Unicode đã được cập nhật lên phiên bản 12.1.
Các liên kết thú vị trên Java 13:

Kết quả

Chúng ta có thể xem qua những cải tiến đã công bố trong Java 14, nhưng vì nó sẽ sớm xuất hiện - JDK 14 dự kiến ​​phát hành vào ngày 17 tháng 3 năm 2020, nên tốt nhất nên tiến hành đánh giá riêng, đầy đủ về nó ngay sau khi phát hành . Tôi cũng muốn bạn chú ý đến thực tế là trong các ngôn ngữ lập trình khác có thời gian nghỉ dài giữa các bản phát hành, chẳng hạn như Python 2–3, không có khả năng tương thích: nghĩa là, nếu mã được viết bằng Python 2, bạn sẽ cần phải làm việc chăm chỉ để dịch nó sang 3. Java đặc biệt về mặt này vì nó cực kỳ tương thích ngược. Điều này có nghĩa là chương trình Java 5 hoặc 8 của bạn được đảm bảo chạy trên máy ảo Java 8-13—với một số ngoại lệ mà hiện tại bạn không cần phải lo lắng. Rõ ràng là điều này không hoạt động theo cách khác: ví dụ: nếu ứng dụng của bạn sử dụng các hàm Java 13 đơn giản là không có sẵn trong JVM Java 8. Đó là tất cả những gì tôi có cho ngày hôm nay, tôn trọng những ai đã đọc đến thời điểm này)) Từ 8 đến 13: tổng quan đầy đủ về các phiên bản Java.  Phần 2 - 5
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION