JavaRush /Blog Java /Random-VI /Nghỉ giải lao #161. Cách xử lý Null trong Java bằng Tùy c...

Nghỉ giải lao #161. Cách xử lý Null trong Java bằng Tùy chọn

Xuất bản trong nhóm
Nguồn: Medium Bài viết này sẽ giúp các bạn hiểu rõ hơn về mục đích của Tùy chọn khi làm việc với code Java. Nghỉ giải lao #161.  Cách xử lý Null trong Java bằng Tùy chọn - 1Khi mới bắt đầu làm việc với mã Java, tôi thường được khuyên nên sử dụng Tùy chọn. Nhưng vào thời điểm đó, tôi không hiểu rõ tại sao sử dụng Tùy chọn lại tốt hơn việc thực hiện xử lý các giá trị null. Trong bài viết này, tôi muốn chia sẻ với bạn lý do tại sao tôi nghĩ tất cả chúng ta nên sử dụng Tùy chọn nhiều hơn và cách tránh tùy chọn quá mức mã của bạn, điều này gây bất lợi cho chất lượng mã.

Tùy chọn là gì?

Tham số Tùy chọn được sử dụng để mang các đối tượng và cho phép các API khác nhau xử lý các tham chiếu null . Hãy xem đoạn mã:
Coffee coffee = new Coffee();
Integer quantity = coffee.getSugar().getQuantity();
Chúng ta có một instance Coffee trong đó chúng ta lấy một ít đường từ một instance của đối tượng Sugar . Nếu chúng ta giả sử rằng giá trị số lượng chưa bao giờ được đặt trong hàm tạo Coffee thì Coffee.getSugar().getQuantity() sẽ trả về NullPointerException . Tất nhiên, chúng ta luôn có thể sử dụng các biện pháp kiểm tra null cũ để khắc phục sự cố.
Coffee coffee = new Coffee();
Integer quantity = 0;
if (coffee.getSugar() != null) {
  quantity = coffee.getSugar().getQuantity();
}
Bây giờ mọi thứ có vẻ ổn. Nhưng khi viết mã Java, tốt hơn hết chúng ta nên tránh thực hiện kiểm tra null . Hãy xem cách thực hiện việc này bằng cách sử dụng Tùy chọn.

Cách tạo Tùy chọn

Có ba cách để tạo các đối tượng Tùy chọn:
  • of(T value) - khởi tạo một đối tượng không null tùy chọn. Xin lưu ý rằng việc sử dụng of() để chỉ một đối tượng null sẽ tạo ra ngoại lệ NullPointerException .

  • ofNullable(T value) - tạo một giá trị Tùy chọn cho một đối tượng có thể là null.

  • trống() - Tạo một phiên bản Tùy chọn đại diện cho một tham chiếu đến null .

// пример использования Optional.of(T Value)
String name = "foo";
Optional<String> stringExample = Optional.of(name)
// пример использования Optional.ofNullable(T Value)
Integer age = null;
Optional<Integer> integerExample= Optional.ofNullable(age)
// пример использования Optional.empty()
Optional<Object> emptyExample = Optional.empty();
Vậy là bạn có một đối tượng Tùy chọn. Bây giờ chúng ta hãy xem hai phương pháp chính cho Tùy chọn:
  • isPresent() - Phương thức này cho bạn biết liệu đối tượng Tùy chọn có chứa giá trị khác null hay không.

  • get() - Lấy giá trị cho Tùy chọn với giá trị hiện tại. Xin lưu ý rằng việc gọi get() trên một Tùy chọn trống sẽ dẫn đến NullPointerException .

Xin lưu ý rằng nếu bạn chỉ sử dụng get()isPresent() khi làm việc với Tùy chọn, bạn đang bỏ lỡ cơ hội! Để hiểu điều này, bây giờ chúng ta hãy viết lại ví dụ trên bằng Tùy chọn.

Cải thiện việc kiểm tra Null bằng tùy chọn

Vậy làm thế nào chúng ta có thể cải thiện đoạn mã trên? Với Tùy chọn, chúng ta có thể hiểu sự hiện diện của một đối tượng bằng cách sử dụng isPresent() và truy xuất nó bằng get() . Hãy bắt đầu bằng cách đóng gói kết quả của Coffee.getSugar() với Tùy chọn và sử dụng phương thức isPresent() . Điều này sẽ giúp chúng tôi xác định xem getSugar() có trả về null hay không.
Coffee coffee = new Coffee();
Optional<String> sugar = Optional.ofNullable(coffee.getSugar());
int quantity = 0;
if (sugar.isPresent()) {
  Sugar sugar = sugar.get();
  int quantity = sugar.getQuantity();
}
Nhìn vào ví dụ này, việc đóng gói kết quả của Coffee.getSugar() vào Tùy chọn dường như không thêm bất kỳ giá trị nào mà chỉ gây thêm rắc rối. Chúng ta có thể cải thiện kết quả bằng cách sử dụng những hàm mà tôi cho là yêu thích của mình từ lớp Tùy chọn:
  • map(Function<? super T,?extend U> mapper) - Ánh xạ giá trị có trong Tùy chọn vào hàm được cung cấp. Nếu tham số Tùy chọn trống thì map() sẽ trả về Tùy chọn.empty() .

  • orElse(T other) là phiên bản "đặc biệt" của phương thức get() . Nó có thể nhận giá trị có trong Tùy chọn. Tuy nhiên, trong trường hợp Tùy chọn trống, điều này sẽ trả về giá trị được truyền cho phương thức orElse() .

Phương thức sẽ trả về giá trị có trong phiên bản Tùy chọn. Nhưng nếu tham số Tùy chọn trống, nghĩa là nó không chứa giá trị, thì orElse() sẽ trả về giá trị được truyền cho chữ ký phương thức của nó, được gọi là giá trị mặc định.
Coffee coffee = new Coffee();

Integer quantity = Optional.ofNullable(coffee.getSugar())
    .map(it -> it.getQuantity())
    .orElse(0);
Điều này thực sự tuyệt vời - ít nhất là tôi nghĩ vậy. Bây giờ, nếu trong trường hợp giá trị trống, chúng ta không muốn trả về giá trị mặc định thì chúng ta cần đưa ra một số loại ngoại lệ. orElseThrow(Supplier<? mở rộng X> ngoại lệSupplier) trả về giá trị có trong các tham số Tùy chọn hoặc ném ra một ngoại lệ nếu Tùy chọn trống.
Coffee coffee = new Coffee();

Integer quantity = Optional.ofNullable(coffee.getSugar())
  .map(it -> it.getQuantity())
  .orElseThrow(IllegalArgumentException::new);
Như bạn có thể thấy, Tùy chọn cung cấp một số lợi thế:
  • tóm tắt kiểm tra null
  • cung cấp API để xử lý các đối tượng null
  • cho phép cách tiếp cận khai báo diễn đạt những gì đang đạt được

Cách trở nên hiệu quả với Tùy chọn

Trong công việc của mình, tôi sử dụng Tùy chọn làm kiểu trả về khi một phương thức có thể trả về trạng thái "không có kết quả". Tôi thường sử dụng nó khi xác định kiểu trả về cho các phương thức.
Optional<Coffee> findByName(String name) {
   ...
}
Đôi khi điều này là không cần thiết. Ví dụ: nếu tôi có một phương thức trả về int , chẳng hạn như getQuantity() trong lớp Sugar thì phương thức đó có thể trả về 0 nếu kết quả là null để biểu thị "không có số lượng". Bây giờ, khi biết điều này, chúng ta có thể nghĩ rằng tham số Sugar trong lớp Coffee có thể được biểu diễn dưới dạng Tùy chọn. Thoạt nhìn, đây có vẻ là một ý tưởng hay vì về mặt lý thuyết, đường không nhất thiết phải có trong cà phê. Tuy nhiên, đây là lúc tôi muốn giải quyết khi không sử dụng Tùy chọn. Chúng ta nên tránh sử dụng Tùy chọn trong các trường hợp sau:
  • Là loại tham số cho POJO , chẳng hạn như DTO . Các tùy chọn không thể tuần tự hóa được, vì vậy việc sử dụng chúng trong POJO sẽ khiến đối tượng không thể tuần tự hóa được.

  • Là một đối số phương pháp. Nếu một đối số của phương thức có thể là null thì từ góc độ mã thuần túy, việc chuyển null vẫn được ưu tiên hơn là chuyển Tùy chọn. Ngoài ra, bạn có thể tạo các phương thức nạp chồng để xử lý một cách trừu tượng sự vắng mặt của đối số phương thức null.

  • Để thể hiện một đối tượng Collection bị thiếu. Bộ sưu tập có thể trống, do đó, Bộ sưu tập trống, chẳng hạn như Bộ hoặc Danh sách trống , phải được sử dụng để thể hiện Bộ sưu tập không có giá trị.

Phần kết luận

Tùy chọn đã trở thành một bổ sung mạnh mẽ cho thư viện Java. Nó cung cấp một cách để xử lý các đối tượng có thể không tồn tại. Vì vậy, cần lưu ý khi phát triển các phương pháp để không rơi vào bẫy lạm dụng. Có, bạn có thể viết mã tuyệt vời để thực hiện kiểm tra null và xử lý null, nhưng cộng đồng Java thích sử dụng Tùy chọn hơn. Nó truyền đạt một cách hiệu quả cách xử lý các giá trị bị thiếu, dễ đọc hơn nhiều so với các kiểm tra Null lộn xộn và dẫn đến ít lỗi hơn trong mã của bạn về lâu dài.
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION