Từ phiên bản Java 8 đến Java 17, có những thay đổi gì? (P1)

Có rất nhiều thứ đã thay đổi trong Java từ khi bắt đầu vào năm 1995 cho đến ngày nay. Java 8 là một bản phát hành  mang tính cách mạng, đã đưa Java trở lại vị trí một trong các ngôn ngữ lập trình tốt nhất hiện nay.

Như lịch công bố trên website Java thì đến tháng 9/2023, Oracle sẽ công bố phiên bản Java 21 LTS. Vậy thì trong bài viết này, mình sẽ điểm lại Java đã thay đổi những gì kể từ phiên bản Java 8 LTS đến Java 17 LTS nhé.

java-release-date Java 8

Lambda Expressions và Stream API

Với việc phát triển thêm tính năng Lambda và Stream API thì Java 8 đã có cuộc cách mạng khi những lập trình viên có thể dễ dàng hơn rất nhiều trong quá trình làm việc.

Thế giới trước khi có biểu thức Lambda?

Mình ví dụ bài toán: 

Mình có một đại lý xe hơi. Để bỏ các thủ tục giấy tờ, mình muốn tạo một phần mềm tìm thấy tất cả những chiếc xe hiện có chạy dưới 50.000km.

Như cách thông thường, chúng ta sẽ làm bằng cách này:

java expression

Để thực hiện điều này, chúng ta sẽ tạo một hàm static với tham số là danh sách ô tô và sẽ trả về một danh sách ô tô đã được lọc theo điều kiện cụ thể.

Sử dụng Stream và Lambda Expression

Vẫn theo ví dụ trên, khách hàng chúng tôi muốn tìm tất cả các xe có cùng tiêu chí.

Đây là giải pháp khi dùng Stream và biểu thức Lambda:

java lambda

Chúng ta cần chuyển danh sách xe thành một luồng bằng cách gọi phương thức stream(). Bên trong phương thức filter() chúng ta đang thiết lập điều kiện của mình. Và điều kiện ở đây là chỉ giữ lại những chiếc xe có số kilometers < 50.000km. Và cuối cùng đóng gói lại vào một danh sách.

Nếu bạn muốn tìm hiểu thêm về biểu thức lambda, hãy đọc thêm bài này nhé!

Method Reference

Trước khi có phương thức tham chiếu

Vẫn cái ví dụ cửa hàng đại lý ô tô, giờ mình muốn in ra tất cả những chiếc xe trong cửa hàng. Khi đó thì mình sẽ sử dụng phương thức tham chiếu.

Một phương thức tham chiếu cho phép chúng ta gọi các hàm trong các lớp bằng một loại cú pháp đặc biệt :: 

Có 4 loại phương thức tham chiếu: 

  • Tham chiếu đến một hàm static
  • Tham chiếu đến một phương thức thể hiện trên một đối tượng
  • Tham chiếu đến một phương thức thể hiện trên một loại
  • Tham chiếu đến một hàm khởi tạo

Khi không dùng phương thức tham chiếu thì mình sẽ làm bằng cách: 

method reference

Chúng ta đang sử dụng biểu thức lambda để gọi hàm toString() trên mỗi ô tô.

Sử dụng phương thức tham chiếu

Đây là cách sử dụng phương thức tham chiếu trong tình huống tương tự:

Method reference

Chúng ta vẫn sử dụng biểu thức lambda, nhưng bây giờ gọi hàm toString() theo phương thức tham chiếu. Nhìn rất ngắn gọn và dễ đọc.

Tìm hiểu thêm phương thức tham chiếu tại đây.

Default Methods

Hãy tưởng tượng chúng ta có một hàm log(String message) và hàm này sẽ in những thông báo khi được gọi.

Sau đó chúng ta lại muốn thêm thời gian vào hàm log để dễ dàng tìm kiếm. Tất nhiên là chúng ta không muốn khách hàng gặp lỗi trong lần chuyển đổi này. Chúng ta sẽ thực hiện việc này bằng cách triển khai phương thức mặc định trong một interface.

Triển khai phương thức mặc định là tính năng cho phép chúng ta tạo dự phòng một implementation của một phương thức trong interface.

Các trường hợp sử dụng

Đây là chương trình ban đầu chúng ta sử dụng:

phương thức mặc định

Chúng ta tạo một interface với chỉ một phương thức và implementing chúng trong classLoggingImplementation

Thêm mới phương thức

Chúng ta sẽ thêm một phương thức mới trong interface. Phương thức nhận tham số thứ hai là ngày tháng hiện tại.

phương thức mặc định

Chúng ta thêm mới phương thức vào trong interface nhưng không implement vào trong tất cả các class. Như vậy code sẽ thông báo lỗi:

Class 'LoggingImplementation' must either be declared abstract 
or implement abstract method 'log(String, Date)' in 'Logging'`.

Sử dụng phương thức mặc định

Sau khi thêm phương thức vào trong interface, compiler sẽ trả về ngoài lê. Chúng ta sẽ triển khai phương thức mặc định cho phương thức mới. 

Thêm từ khóa default cho phép chúng ta thêm phương thức bên trong interface. Bây giờ, class LoggingImplementation không bị lỗi trình biên dịch mặc dù chúng ta không triển khai phương thức mới này bên trong nó.

Nếu bạn còn thắc mắc về Default method, tìm hiểu thêm tại đây nhé

Type Annotations

Type annotations là một tính năng nữa được giới thiệu trong Java 8. Mặc dù trước đây java đã có annotations, nhưng bây giờ chúng ta có thể sử dụng ở bất cứ nơi nào. Điều này có nghĩa chúng ta có thể sử dụng chúng trên:

  • Khai báo biến cục bộ
  • Gọi hàm constructor
  • Type casting
  • Generics
  • Mệnh để clause….

Khai báo biến cục bộ

Khai báo kiểu này sẽ đảm bảo biến cục bộ không thể có giá trị null:

type annotations

Chúng ta sử dụng annotation trên biến cục bộ ở đây. Bộ xử lý có thể đọc annotations @NotNull và đưa ra ngoại lệ khi chuỗi rỗng.

Gọi hàm constructor

Chúng ta muốn đảm bảo rằng không thể tạo một chuỗi rỗng ArrayList

type annotation

Đây là annotation được khai báo trên hàm tạo, điều này đảm bảo danh sách mảng không được trống.

Generics type

Một trong những yêu cầu là mỗi email phải ở dạng @.com. Nếu dùng annotation, chúng ta có thể làm điều đó một cách dễ dàng: 

Đây là một biến chứa danh sách địa chỉ email. Chúng ta sử dụng annotation @Email để đảm bảo từng phần tử trong List emails đúng định dạng.

Repeating Annotations

Trong thực tế, một số lỗi nghiêm trọng khi gặp exception thì cần phải báo luôn cho chủ sở hữu và nhóm quản trị viên bảo mật của công ty.

Việc sử dụng repeating annotations cho phép chúng ta đặt nhiều annotations trên cùng một class.

Tạo một repeating annotation

Với ví dụ trên, chúng ta tạo một annotation có tên là @Notify

repeating annotation

Chúng ta tạo @Notify như một annotation thông thường, tuy nhiên ta sẽ thêm @Repeatable vào annotation đó. Ngoài ra chúng ta phải tạo một vùng chứa mảng đối tượng Notify. Bộ xử lý giờ đây có quyền truy cập vào tất cả Repeating Notify  thông qua vùng chưa @Notifications

Sử dụng Repeating Annotations

Chúng ta có thể thêm repeating annotation nhiều lần ở cùng một class

repeating annotations

Chúng ta có một custom exception class mà chúng ta sẽ throw ra những chỗ exception quan trọng. Khi service của chúng ta nhận exception này thì sẽ gửi cảnh báo đến hai email mà chúng ta đã định nghĩa ở trên.

Java 9

Java 9 giới thiệu một số tính năng mới

  • Java Module System
  • Try-with-resources
  • Diamond Syntax with Inner Anonymous Classes
  • Private Interface Methods

Java Module System

Một module là một nhóm các package, dependencies, và các tài nguyên của chúng. Nó cung cấp một tập hợp các chức năng rộng hơn so với package.

Khi tạo một module mới, chúng ta cần cung cấp một số thuộc tính:

  • Name
  • Dependencies
  • Public Packages – by default, all packages are module private
  • Services Offered
  • Services Consumed
  • Reflection Permissions

Tạo một dự án nhiều module trong Intellij

Đầu tiên, chúng ta tạo một ứng dụng in ra “Hello World” đơn giản. Nhưng sẽ chia ra module thứ nhất in từ “Hello “, module thứ hai in từ “World”

Module java 9Chúng ta có hai Module: Hello module và World module. Bên trong mỗi module, chúng ta tạo thêm một file module-info.java. Tệp này xác định các module trong java, bên trong chúng ta sẽ định nghĩa những module nào cần import và export.

Định nghĩa module thứ nhất

Như đã nói ở trên, thì module Hello để in ra chứ “Hello “. Và module World in ra chữ “World!”. Vậy điều đầu tiên chúng ta cần làm là export module World trong file module-info.java:

java module 9

Chúng ta sử dụng keyword module với tên module để định nghĩa module để tham chiếu đến module hiện tại.

Từ khoá exports để xuất ra những package trong module.

Một số từ khoá khác có thể sử dụng như là: 

  • requires
  • requires transitive
  • exports to 
  • uses
  • provides with

Các bạn có thể tìm hiểu thêm tại đây.

Sau đó chúng ta tạo một hàm để in ra chữ “World!”java-module-9--1

Định nghĩa module thứ hai

Sau khi tạo và export được module World thì chúng ta tạo module Hello:

java-module-9--2

Chúng ta xác định các module phụ thuộc bằng từ khoá requires. Theo mặc định, những module nào không được exports thì là những module private, không được tham chiếu đến các module khác.

Và để gọi module World thì chúng ta sẽ import chúng và gọi hàm print() đã định nghĩa ở module World.

java-module-9--3

Try-with-resources

Try-with-resources là một tính năng cho phép chúng ta khai báo các tài nguyên có thể tự động đóng trong một khối try-catch. Khai báo trong một khối try-catch sẽ yêu cầu JVM giải phóng chúng sau khi thực thi xong.

Kết thúc tài nguyên theo cách thủ công

Chúng ta muốn đọc văn bản bằng BufferedReader. BufferedReader là một closable resource, vì vậy chúng ta cần đóng đúng cách sau khi sử dụng. Vậy thì trước Java 7 chúng ta làm như sau: 

try with resource

Đóng resource với try-with-resources

Try-catch-resource được giới thiệu đầu tiên từ bản Java 7. Vậy nó có những thay đổi gì, hãy xem nhé:

try with resources

Cú pháp trên cung cấp rất nhiều tính năng và quản lý tự động các tài nguyên, tuy nhiên, chúng ta vẫn cần khai báo một biến cục bộ để làm việc với, Java 9 tinh chỉnh thêm cho tính năng này để tránh sự rườm rà.

Diamond Syntax with Inner Anonymous Classes

Chúng ta biết, Java SE 7 đã giới thiệu một tính năng mới: Diamond Operator để tránh mã dư thừa và độ dài, để cải thiện khả năng đọc. Tuy nhiên trong Java SE 8, Oracle Corp (Nhà phát triển thư viện Java) đã phát hiện ra rằng một số hạn chế trong việc sử dụng toán tử Diamond với Anonymous Inner Class. Họ đã khắc phục các vấn đề đó và sẽ phát hành như một phần của Java 9.

diamond syntax

Private Interface Methods

Trong Java 8, chúng ta có thể cung cấp phương thức thực hiện trong các Interfaces bằng cách sử dụng các phương thức Default và Static. Tuy nhiên, chúng ta không thể tạo các phương thức Private trong Interfaces.

Để tránh mã dư thừa và khả năng sử dụng lại nhiều hơn, từ Java 9, chúng ta cũng có thể viết các phương thức private static và private trong một giao diện sử dụng từ khoá ‘private’.

private interface methods

(Còn nữa ~~)

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x