Sử dụng cho tùy chọn


271

Đã sử dụng Java 8 được hơn 6 tháng hoặc lâu hơn, tôi khá hài lòng với các thay đổi API mới. Một lĩnh vực tôi vẫn chưa tự tin là khi nào nên sử dụng Optional. Tôi dường như dao động giữa việc muốn sử dụng nó ở mọi nơi có thể null, và không nơi nào cả.

Dường như có rất nhiều tình huống khi tôi có thể sử dụng nó và tôi không bao giờ chắc chắn liệu nó có thêm lợi ích (khả năng đọc / an toàn không) hay chỉ gây thêm chi phí.

Vì vậy, tôi có một vài ví dụ và tôi quan tâm đến suy nghĩ của cộng đồng về việc liệu Optionalcó lợi hay không.

1 - Là kiểu trả về của phương thức công khai khi phương thức có thể trả về null:

public Optional<Foo> findFoo(String id);

2 - Là một tham số phương thức khi tham số có thể là null:

public Foo doSomething(String id, Optional<Bar> barOptional);

3 - Là thành viên tùy chọn của đậu:

public class Book {

  private List<Pages> pages;
  private Optional<Index> index;

}

4 - Trong Collections:

Nói chung tôi không nghĩ:

List<Optional<Foo>>

thêm bất cứ điều gì - đặc biệt là vì người ta có thể sử dụng filter()để xóa nullcác giá trị, v.v., nhưng có cách sử dụng tốt nào Optionaltrong các bộ sưu tập không?

Có trường hợp nào tôi bỏ lỡ không?


2
Một trường hợp tôi thấy hữu ích là, ví dụ, nếu bạn có một bản đồ thay thế. Chẳng hạn Map<Character, String>. Nếu không có sự thay thế tôi có thể sử dụng điều này : Optional.ofNullable(map.get(c)).orElse(String.valueOf(c)). Cũng lưu ý rằng Tùy chọn đã bị đánh cắp từ Guava và nó có cú pháp đẹp hơn nhiều:Optional.fromNullable(map.get(c)).or(String.valueOf(c));
fge

3
Ngoài ra, trong các bộ sưu tập, tốt, có những bộ sưu tập không cho phép giá trị null! Tùy chọn phù hợp với hóa đơn ở đây. Và bạn có thể .filter(Optional::absent)"null giá trị" ra
fge

2
@fge Trong tất cả các công bằng, tôi nghĩ rằng khái niệm Tùy chọn thực sự xuất phát từ FP.
VH-NZZ

2
@fge không được thể hiện tốt hơn với getOrDefault()?
Jim Garrison

Câu trả lời:


206

Điểm chính của Optionallà cung cấp một phương tiện cho một hàm trả về một giá trị để biểu thị sự vắng mặt của một giá trị trả về. Xem cuộc thảo luận này . Điều này cho phép người gọi tiếp tục một chuỗi các cuộc gọi phương thức trôi chảy.

Điều này phù hợp nhất với trường hợp sử dụng số 1 trong câu hỏi của OP. Mặc dù, sự vắng mặt của một giá trị là một công thức chính xác hơn null vì một cái gì đó như IntStream.findFirstkhông bao giờ có thể trả về null.

Đối với trường hợp sử dụng # 2 , chuyển một đối số tùy chọn cho một phương thức, điều này có thể được thực hiện để hoạt động, nhưng nó khá vụng về. Giả sử bạn có một phương thức lấy một chuỗi theo sau là một chuỗi thứ hai tùy chọn. Chấp nhận một Optionalđối số thứ hai sẽ dẫn đến mã như thế này:

foo("bar", Optional.of("baz"));
foo("bar", Optional.empty());

Ngay cả chấp nhận null cũng đẹp hơn:

foo("bar", "baz");
foo("bar", null);

Có lẽ tốt nhất là có một phương thức quá tải chấp nhận một đối số chuỗi đơn và cung cấp mặc định cho lần thứ hai:

foo("bar", "baz");
foo("bar");

Điều này không có giới hạn, nhưng nó đẹp hơn nhiều so với một trong những điều trên.

Sử dụng các trường hợp # 3# 4 , có Optionaltrong trường lớp hoặc trong cấu trúc dữ liệu, được coi là sử dụng sai API. Đầu tiên, nó đi ngược lại mục tiêu thiết kế chính Optionalnhư đã nêu ở trên. Thứ hai, nó không thêm bất kỳ giá trị nào.

Có ba cách để đối phó với việc không có giá trị trong một Optional: cung cấp giá trị thay thế, gọi hàm để cung cấp giá trị thay thế hoặc ném ngoại lệ. Nếu bạn đang lưu trữ vào một trường, bạn sẽ thực hiện việc này vào thời gian khởi tạo hoặc chỉ định. Nếu bạn thêm các giá trị vào danh sách, như OP đã đề cập, bạn có thêm lựa chọn đơn giản là không thêm giá trị, từ đó "làm phẳng" các giá trị vắng mặt.

Tôi chắc rằng ai đó có thể đưa ra một số trường hợp giả định khi họ thực sự muốn lưu trữ Optionaltrong một lĩnh vực hoặc bộ sưu tập, nhưng nói chung, tốt nhất là tránh làm điều này.


46
Tôi không đồng ý với # 3. Nó có thể hữu ích để có một Optionalnhư một lĩnh vực khi mọi thứ phải được thực hiện hoặc không được thực hiện khi có hoặc không có giá trị.
glglgl 15/03/2015

15
Tôi không thấy lý do tại sao làm if(foo == null)nội bộ sẽ tốt hơn là chỉ lưu trữ trường như optional. Và tôi không thấy lý do tại sao gọi getOptionalFoo()nội bộ một cách rõ ràng tốt hơn là chỉ lưu trữ trường như một Optional. Ngoài ra, nếu một trường có thể nullvà một trường không thể null, tại sao không giao tiếp với trình biên dịch bằng cách tạo chúng Optionalhoặc không Optional.
mogronalol

27
@StuartMarks, đây là một trong những điều chỉ gây khó khăn cho tôi khi tôi nghe nó từ tất cả các Optional<>chuyên gia: "không lưu trữ Optional<>trong một lĩnh vực". Tôi thực sự đang cố gắng để hiểu điểm của khuyến nghị này. Hãy xem xét một cây DOM trong đó một nút có thể có cha hoặc không. Có vẻ như trong trường hợp sử dụng Node.getParent()sẽ trở lại Optional<Node>. Tôi thực sự mong đợi để lưu trữ nullvà bọc kết quả mỗi lần? Tại sao? Điều gì làm cho sự kém hiệu quả này mua cho tôi, ngoài việc làm cho mã của tôi trông xấu xí?
Garret Wilson

7
@GarretWilson Mặt khác, giả sử bạn có Optional<Node> getParent() { return Optional.ofNullable(parent); }. Điều này có vẻ đắt tiền vì nó phân bổ một Optionallần! Nhưng nếu người gọi giải nén nó ngay lập tức, đối tượng cực kỳ ngắn và không bao giờ được quảng bá ra khỏi không gian eden. Nó thậm chí có thể bị loại bỏ bởi phân tích thoát của JIT. Câu trả lời cuối cùng là "nó phụ thuộc" như mọi khi, nhưng sử dụng Optionaltrong các trường có khả năng làm bộ nhớ sử dụng và làm chậm quá trình truyền tải cấu trúc dữ liệu. Và cuối cùng tôi nghĩ rằng nó làm xáo trộn mã, nhưng đây là vấn đề của hương vị.
Stuart Marks

6
@GarretWilson Vậy bạn đã viết blog cho điều đó chưa? Tôi sẽ quan tâm đến điều đó :)
akhil_mittal

78

Tôi đến trễ trò chơi nhưng với giá trị của nó, tôi muốn thêm 2 Cents của mình. Họ đi ngược lại mục tiêu thiết kếOptional , được tóm tắt tốt bằng câu trả lời của Stuart Marks , nhưng tôi vẫn bị thuyết phục về tính hợp lệ của chúng (rõ ràng).

Sử dụng tùy chọn ở mọi nơi

Nói chung

Tôi đã viết toàn bộ một bài đăng trên blog về việc sử dụngOptional nhưng về cơ bản nó đi xuống:

  • thiết kế các lớp học của bạn để tránh sự tùy chọn bất cứ nơi nào có thể khả thi
  • trong tất cả các trường hợp còn lại, mặc định sẽ được sử dụng Optionalthay vìnull
  • có thể tạo ra ngoại lệ cho:
    • biến cục bộ
    • trả về giá trị và đối số cho phương thức riêng
    • thực hiện các khối mã quan trọng (không cần đoán, sử dụng một trình lược tả)

Hai trường hợp ngoại lệ đầu tiên có thể làm giảm chi phí cảm nhận của việc đóng gói và hủy ghép các tham chiếu trong Optional. Chúng được chọn sao cho một null không bao giờ có thể vượt qua một cách hợp pháp một ranh giới từ một thể hiện này sang một thể hiện khác.

Lưu ý rằng điều này hầu như sẽ không bao giờ cho phép Optionals trong các bộ sưu tập gần như tệ như nulls. Đừng làm điều đó. ;)

Về câu hỏi của bạn

  1. Đúng.
  2. Nếu quá tải là không có tùy chọn, có.
  3. Nếu các phương pháp khác (phân lớp, trang trí, ...) không có lựa chọn, vâng.
  4. Xin đừng!

Ưu điểm

Làm điều này làm giảm sự hiện diện của nulls trong cơ sở mã của bạn, mặc dù nó không xóa chúng. Nhưng đó thậm chí không phải là điểm chính. Có những lợi thế quan trọng khác:

Làm rõ ý định

Sử dụng Optionalrõ ràng thể hiện rằng các biến là, tốt, tùy chọn. Bất kỳ người đọc mã hoặc người tiêu dùng API nào của bạn sẽ bị đánh vào đầu với thực tế là có thể không có gì ở đó và việc kiểm tra là cần thiết trước khi truy cập giá trị.

Loại bỏ sự không chắc chắn

Không có Optionalý nghĩa của một nullsự xuất hiện là không rõ ràng. Nó có thể là một đại diện pháp lý của một tiểu bang (xem Map.get) hoặc một lỗi thực thi như khởi tạo bị thiếu hoặc thất bại.

Điều này thay đổi đáng kể với việc sử dụng liên tục Optional. Ở đây, đã có sự xuất hiện của nulldấu hiệu cho thấy sự hiện diện của một lỗi. (Bởi vì nếu giá trị được phép bị thiếu, một giá trị Optionalsẽ được sử dụng.) Điều này làm cho việc gỡ lỗi một ngoại lệ con trỏ null dễ dàng hơn nhiều vì câu hỏi về ý nghĩa của điều này nullđã được trả lời.

Thêm kiểm tra Null

Bây giờ không còn gì có thể nullnữa, điều này có thể được thi hành ở mọi nơi. Cho dù với chú thích, xác nhận hoặc kiểm tra đơn giản, bạn không bao giờ phải suy nghĩ về việc đối số này hoặc loại trả về có thể là null. Không thể nào!

Nhược điểm

Tất nhiên, không có viên đạn bạc ...

Hiệu suất

Gói các giá trị (đặc biệt là nguyên thủy) vào một thể hiện bổ sung có thể làm giảm hiệu suất. Trong các vòng lặp chặt chẽ, điều này có thể trở nên đáng chú ý hoặc thậm chí tệ hơn.

Lưu ý rằng trình biên dịch có thể tránh được tham chiếu thêm trong vòng đời ngắn của Optionals. Trong các loại giá trị Java 10 có thể tiếp tục giảm hoặc xóa hình phạt.

Tuần tự hóa

Optionalkhông được tuần tự hóa nhưng một cách giải quyết không quá phức tạp.

Bất biến

Do sự bất biến của các kiểu chung trong Java, các hoạt động nhất định trở nên cồng kềnh khi loại giá trị thực được đẩy vào một đối số kiểu chung. Một ví dụ được đưa ra ở đây (xem "Đa hình tham số") .


Một nhược điểm khác (hoặc giới hạn) là bạn không thể sắp xếp các trường hợp Tùy chọn (xxx), mặc dù Oracle rõ ràng áp đặt hạn chế đó một cách có chủ ý. Tôi nghi ngờ về sự khôn ngoan của việc có sẵn các lớp này khi chúng chỉ được sử dụng trong các trường hợp cụ thể và giả sử nhà phát triển sẽ làm đúng. Giải quyết một vấn đề có thể gây ra một vấn đề khác. Có lẽ nên có cảnh báo trình biên dịch để hỗ trợ nhà phát triển khi sử dụng các lớp Tùy chọn (xxx) theo cách "không mong muốn" (ví dụ như tham số phương thức, trong bộ sưu tập, trong hàm tạo, v.v.) nếu điều đó thực sự không được sử dụng?
skomisa

Khoảng 4, tùy chọn trong các bộ sưu tập: Thực sự đôi khi hữu ích để lưu trữ các tùy chọn trong Lists. Đây là trường hợp khi điều quan trọng là một yếu tố nhất định được đặt tại một chỉ mục nhất định, nhưng yếu tố đó có thể có mặt hay không. Điều đó được truyền đạt rõ ràng bởi một List<Optional<T>>loại. Nếu mặt khác, điều quan trọng chỉ là những đối tượng là thành viên của một số bộ sưu tập thì không có điểm.
Lii

3
Tôi nghĩ trường hợp sử dụng # 2 vẫn còn nhiều nghi vấn. Một Optionalđược truyền vào một phương pháp có thể được null. Vì vậy, những gì bạn đã đạt được? Bây giờ bạn có hai kiểm tra để thực hiện. Xem stackoverflow.com/a/31923042/650176
David V

2
@DavidV nhìn vào danh sách những lợi thế tôi đã đưa ra - tất cả chúng cũng áp dụng cho trường hợp đó. Ngoài ra, nếu bạn tiếp tục Optional(đó là trường hợp nếu bạn sẵn sàng vượt qua nó dưới dạng đối số) nullkhông bao giờ là một giá trị pháp lý. Vì vậy, gọi một phương thức với một tham số nullrõ ràng rõ ràng là một sai lầm.
Nicolai

28

Cá nhân, tôi thích sử dụng Công cụ kiểm tra mã của IntelliJ để sử dụng @NotNull@Nullablekiểm tra vì đây là phần lớn thời gian biên dịch (có thể có một số kiểm tra thời gian chạy) Điều này có chi phí thấp hơn về khả năng đọc mã và hiệu năng thời gian chạy. Nó không nghiêm ngặt như sử dụng Tùy chọn, tuy nhiên sự thiếu nghiêm ngặt này cần được hỗ trợ bởi các bài kiểm tra đơn vị đàng hoàng.

public @Nullable Foo findFoo(@NotNull String id);

public @NotNull Foo doSomething(@NotNull String id, @Nullable Bar barOptional);

public class Book {

  private List<Pages> pages;
  private @Nullable Index index;

}

List<@Nullable Foo> list = ..

Điều này hoạt động với Java 5 và không cần phải bọc và bỏ các giá trị. (hoặc tạo các đối tượng bao bọc)


7
Uhm, đó là những chú thích IDEA? Tôi thích @Nonnullcá nhân của JSR 305 - hoạt động với FindBugs;)
fge

@fge Thiếu các tiêu chuẩn về vấn đề này, nhưng tôi tin rằng các công cụ nói chung có thể cấu hình được và bạn không phải kết thúc với@Nonnull @NotNull etc
Peter Lawrey

4
Đúng là như vậy; IDEA (13.x) đưa ra ba lựa chọn khác nhau ... Meh, tôi luôn kết thúc bằng cách sử dụng JSR 305 anywa
fge

3
Tôi biết điều này đã cũ, nhưng cuộc thảo luận về chú thích & công cụ xứng đáng có liên kết đến stackoverflow.com/questions353896363 - mà - btw đề cập cụ thể đến trường hợp của Java 8.
Stephan Herrmann

25

Tôi nghĩ rằng Guava Tùy chọn và trang wiki của họ đặt nó khá tốt:

Bên cạnh sự gia tăng khả năng đọc đến từ việc đặt tên vô giá trị, ưu điểm lớn nhất của Tùy chọn là tính chống chứng minh ngu ngốc. Nó buộc bạn phải chủ động suy nghĩ về trường hợp vắng mặt nếu bạn muốn chương trình của bạn biên dịch hoàn toàn, vì bạn phải chủ động mở khóa Tùy chọn và giải quyết trường hợp đó. Null làm cho việc quên mọi thứ trở nên dễ dàng một cách đáng lo ngại, và mặc dù FindBugs giúp ích, chúng tôi không nghĩ rằng nó cũng giải quyết vấn đề gần như vậy.

Điều này đặc biệt có liên quan khi bạn trả về các giá trị có thể có hoặc không "hiện diện". Bạn (và những người khác) có nhiều khả năng quên rằng other.method (a, b) có thể trả về giá trị null hơn khả năng bạn quên rằng a có thể là null khi bạn triển khai other.method. Trả lại tùy chọn làm cho người gọi không thể quên trường hợp đó, vì họ phải tự mở khóa đối tượng để mã của họ biên dịch. - (Nguồn: Guava Wiki - Sử dụng và tránh null - Điểm gì? )

Optionalthêm một số chi phí, nhưng tôi nghĩ lợi thế rõ ràng của nó là làm cho nó rõ ràng rằng một đối tượng có thể vắng mặt và nó buộc các lập trình viên xử lý tình huống. Nó ngăn chặn rằng ai đó quên != nullkiểm tra yêu quý .

Lấy ví dụ về 2 , tôi nghĩ rằng nó là mã rõ ràng hơn nhiều để viết:

if(soundcard.isPresent()){
  System.out.println(soundcard.get());
}

hơn

if(soundcard != null){
  System.out.println(soundcard);
}

Đối với tôi, Optionalcàng nắm bắt tốt hơn thực tế là không có soundcard.

2 của tôi về điểm của bạn:

  1. public Optional<Foo> findFoo(String id);- Tôi không chắc chắn về điều này. Có lẽ tôi sẽ trả lại một Result<Foo>cái có thể trống hoặc chứa a Foo. Đó là một khái niệm tương tự, nhưng không thực sự là một Optional.
  2. public Foo doSomething(String id, Optional<Bar> barOptional);- Tôi thích @Nullable và kiểm tra tìm kiếm, như trong câu trả lời của Peter Lawrey - xem thêm cuộc thảo luận này .
  3. Ví dụ về cuốn sách của bạn - Tôi không chắc chắn liệu tôi có sử dụng Tùy chọn nội bộ hay không, điều đó có thể phụ thuộc vào độ phức tạp. Đối với "API" của một cuốn sách, tôi sẽ sử dụng một Optional<Index> getIndex()để chỉ rõ rằng cuốn sách có thể không có chỉ mục.
  4. Tôi sẽ không sử dụng nó trong các bộ sưu tập, thay vì không cho phép các giá trị null trong các bộ sưu tập

Nói chung, tôi sẽ cố gắng giảm thiểu đi qua nulls. (Một khi bị cháy ...) Tôi nghĩ rằng thật đáng để tìm ra những tóm tắt phù hợp và chỉ ra cho các lập trình viên đồng nghiệp những gì một giá trị trả về nhất định thực sự đại diện.


15
Bạn sẽ viết soundcard.ifPresent(System.out::println). Gọi isPresentlà về mặt ngữ nghĩa giống như kiểm tra null.
một oliver tốt hơn

Vấn đề với tôi là mọi thứ với các loại Tùy chọn vẫn có thể là null. Vì vậy, để thực sự an toàn, bạn phải làm một cái gì đó như thế nào if(soundcard != null && soundcard.isPresent()). Mặc dù tạo ra một api trả về Tùy chọn và cũng có thể trả về null là điều tôi hy vọng không ai từng làm.
Simon Baumgardt-Wellander

"Nó buộc bạn phải chủ động suy nghĩ về trường hợp vắng mặt nếu bạn muốn chương trình của bạn biên dịch hoàn toàn, vì bạn phải chủ động mở khóa Tùy chọn và giải quyết trường hợp đó." Tôi không thực sự chắc chắn làm thế nào nó buộc nó, mặc dù tôi không làm việc trong Java rất nhiều. Bạn có thể giải thích Java làm gì để buộc bạn mở khóa và kiểm tra trường hợp! IsPftime chỉ đơn giản để biên dịch không?
nghiền nát

15

Từ hướng dẫn của Oracle :

Mục đích của Tùy chọn không phải là để thay thế mọi tham chiếu null trong cơ sở mã của bạn mà là để giúp thiết kế các API tốt hơn, trong đó, chỉ bằng cách đọc chữ ký của một phương thức mà người dùng có thể biết liệu có mong đợi một giá trị tùy chọn hay không. Ngoài ra, Tùy chọn buộc bạn phải chủ động hủy một Tùy chọn để đối phó với việc không có giá trị; kết quả là, bạn bảo vệ mã của mình trước các ngoại lệ con trỏ null ngoài ý muốn.


3
API chỉ dành cho phần trả về của phương thức, phải không? Tùy chọn không nên được sử dụng làm tham số vì loại xóa? đôi khi tôi sử dụng Tùy chọn nội bộ trong một phương thức, được chuyển đổi từ tham số nullable hoặc dưới dạng trường khởi tạo từ tham số hàm tạo null ... vẫn cố gắng tìm hiểu xem điều đó có hữu ích hơn là chỉ để nó là null - có ai có suy nghĩ gì không?
ycomp

@ycomp Bạn có thể tìm thấy khá nhiều thông tin về những trường hợp trong câu hỏi này hoặc câu hỏi đó . Câu trả lời cho những câu hỏi đó nói nhiều hơn những gì được hỏi và bao gồm các trường hợp khác. Để biết thêm thông tin, hãy duyệt thêm hoặc đặt câu hỏi của riêng bạn, vì có lẽ bạn sẽ không nhận được nhiều sự chú ý ở đây. ; )
ctomek

8

1 - Là kiểu trả về của phương thức công khai khi phương thức có thể trả về null:

Đây là một bài viết tốt cho thấy sự hữu ích của usecase # 1. Có mã này

...
if (user != null) {
    Address address = user.getAddress();
    if (address != null) {
        Country country = address.getCountry();
        if (country != null) {
            String isocode = country.getIsocode();
            isocode = isocode.toUpperCase();
        }
    }
}
...

được chuyển đổi sang đây

String result = Optional.ofNullable(user)
  .flatMap(User::getAddress)
  .flatMap(Address::getCountry)
  .map(Country::getIsocode)
  .orElse("default");

bằng cách sử dụng Tùy chọn làm giá trị trả về của các phương thức getter tương ứng .


2

Đây là một cách sử dụng thú vị (tôi tin) cho ... Các bài kiểm tra.

Tôi dự định sẽ kiểm tra mạnh mẽ một trong những dự án của mình và do đó tôi xây dựng các xác nhận; chỉ có những thứ tôi phải xác minh và những thứ khác tôi không có.

Do đó, tôi xây dựng mọi thứ để khẳng định và sử dụng một xác nhận để xác minh chúng, như thế này:

public final class NodeDescriptor<V>
{
    private final Optional<String> label;
    private final List<NodeDescriptor<V>> children;

    private NodeDescriptor(final Builder<V> builder)
    {
        label = Optional.fromNullable(builder.label);
        final ImmutableList.Builder<NodeDescriptor<V>> listBuilder
            = ImmutableList.builder();
        for (final Builder<V> element: builder.children)
            listBuilder.add(element.build());
        children = listBuilder.build();
    }

    public static <E> Builder<E> newBuilder()
    {
        return new Builder<E>();
    }

    public void verify(@Nonnull final Node<V> node)
    {
        final NodeAssert<V> nodeAssert = new NodeAssert<V>(node);
        nodeAssert.hasLabel(label);
    }

    public static final class Builder<V>
    {
        private String label;
        private final List<Builder<V>> children = Lists.newArrayList();

        private Builder()
        {
        }

        public Builder<V> withLabel(@Nonnull final String label)
        {
            this.label = Preconditions.checkNotNull(label);
            return this;
        }

        public Builder<V> withChildNode(@Nonnull final Builder<V> child)
        {
            Preconditions.checkNotNull(child);
            children.add(child);
            return this;
        }

        public NodeDescriptor<V> build()
        {
            return new NodeDescriptor<V>(this);
        }
    }
}

Trong lớp NodeAssert, tôi làm điều này:

public final class NodeAssert<V>
    extends AbstractAssert<NodeAssert<V>, Node<V>>
{
    NodeAssert(final Node<V> actual)
    {
        super(Preconditions.checkNotNull(actual), NodeAssert.class);
    }

    private NodeAssert<V> hasLabel(final String label)
    {
        final String thisLabel = actual.getLabel();
        assertThat(thisLabel).overridingErrorMessage(
            "node's label is null! I didn't expect it to be"
        ).isNotNull();
        assertThat(thisLabel).overridingErrorMessage(
            "node's label is not what was expected!\n"
            + "Expected: '%s'\nActual  : '%s'\n", label, thisLabel
        ).isEqualTo(label);
        return this;
    }

    NodeAssert<V> hasLabel(@Nonnull final Optional<String> label)
    {
        return label.isPresent() ? hasLabel(label.get()) : this;
    }
}

Điều đó có nghĩa là khẳng định thực sự chỉ kích hoạt nếu tôi muốn kiểm tra nhãn!


2

Optionallớp cho phép bạn tránh sử dụng nullvà cung cấp một sự thay thế tốt hơn:

  • Điều này khuyến khích nhà phát triển thực hiện kiểm tra sự hiện diện để tránh bị bắt NullPointerException.

  • API trở thành tài liệu tốt hơn vì có thể thấy, nơi mong đợi các giá trị có thể vắng mặt.

Optionalcung cấp API thuận tiện để tiếp tục làm việc với đối tượng : isPresent(); get(); orElse(); orElseGet(); orElseThrow(); map(); filter(); flatmap().

Ngoài ra, nhiều khung tích cực sử dụng loại dữ liệu này và trả lại từ API của họ.


2

Trong java, chỉ cần không sử dụng chúng trừ khi bạn nghiện lập trình chức năng.

Chúng không có vị trí làm đối số phương thức (Tôi sẽ giới thiệu ai đó một ngày nào đó sẽ chuyển cho bạn một tùy chọn null, không chỉ là một tùy chọn trống).

Chúng có ý nghĩa đối với các giá trị trả về nhưng chúng mời lớp khách tiếp tục kéo dài chuỗi xây dựng hành vi.

FP và chuỗi ít có vị trí trong một ngôn ngữ bắt buộc như java vì nó làm cho nó rất khó để gỡ lỗi, không chỉ để đọc. Khi bạn bước đến dòng, bạn không thể biết trạng thái cũng như mục đích của chương trình; bạn phải bước vào để tìm ra nó (thành mã thường không phải của bạn và nhiều khung ngăn xếp sâu mặc dù các bộ lọc bước) và bạn phải thêm nhiều điểm dừng để đảm bảo rằng nó có thể dừng trong mã / lambda bạn đã thêm, thay vì chỉ đơn giản là đi bộ if / other / gọi các dòng tầm thường.

Nếu bạn muốn lập trình chức năng, hãy chọn một cái gì đó khác với java và hy vọng bạn có các công cụ để gỡ lỗi đó.


1

Tôi không nghĩ rằng Tùy chọn là một thay thế chung cho các phương thức có khả năng trả về giá trị null.

Ý tưởng cơ bản là: Sự vắng mặt của một giá trị không có nghĩa là nó có khả năng có sẵn trong tương lai. Đó là một sự khác biệt giữa findById (-1) và findById (67).

Thông tin chính của Tùy chọn cho người gọi là anh ta có thể không tính vào giá trị đã cho nhưng có thể có sẵn tại một số thời điểm. Có lẽ nó sẽ biến mất một lần nữa và trở lại sau một lần nữa. Nó giống như một công tắc bật / tắt. Bạn có "tùy chọn" để bật hoặc tắt đèn. Nhưng bạn không có tùy chọn nếu bạn không bật đèn.

Vì vậy, tôi thấy quá lộn xộn khi giới thiệu Tùy chọn ở mọi nơi mà trước đó null có khả năng được trả lại. Tôi vẫn sẽ sử dụng null, nhưng chỉ trong các khu vực hạn chế như gốc cây, khởi tạo lười biếng và phương thức tìm kiếm rõ ràng.


0

Dường như Optionalchỉ hữu ích nếu loại T trong Tùy chọn là một loại nguyên thủy như int, long, char, vv Đối với các lớp học "thật", nó không có ý nghĩa với tôi như bạn có thể sử dụng một nullgiá trị nào.

Tôi nghĩ rằng nó đã được lấy từ đây (hoặc từ một khái niệm ngôn ngữ tương tự khác).

Nullable<T>

Trong C #, điều này Nullable<T>đã được giới thiệu từ lâu để bọc các loại giá trị.


2
Nó là một ripoff của Ổi là Optionaltrong thực tế
FGE

2
@fge OK nhưng khi điều này đã có mặt trong C # (2005, MS.NET 2.0), tôi nghĩ không có Guava. Và ... ai biết C # lấy cái này từ đâu.
peter.petrov

3
@fge "Ripoff of Guava's Options" là một cách thú vị để đặt nó, vì những người Guava tham gia vào các cuộc thảo luận, cung cấp kinh nghiệm của họ, và nói chung là ủng hộ java.util.Optional.
Stuart Marks

6
@fge Không còn nghi ngờ gì nữa, các API của Java bị ảnh hưởng mạnh mẽ bởi Guava. Tôi đang gặp vấn đề với "ripoff" nghe có vẻ như ăn cắp. Những người Guava đã đóng góp rất nhiều ý tưởng có giá trị cho Java 8.
Stuart Marks

6
Bạn đang thiếu điểm. Tùy chọn là được sử dụng thay vì trả về null. Nó an toàn hơn khả năng ném NullPulumException. Xem: oracle.com/technetwork/articles/java/
Mạnh

0

An có ngữ nghĩa tương tự với một thể hiện không thể thay đổi của mẫu thiết kế Iterator :Optional

  • nó có thể hoặc không thể đề cập đến một đối tượng (như được đưa ra bởi isPresent())
  • nó có thể được hủy đăng ký (sử dụng get()) nếu nó tham chiếu đến một đối tượng
  • nhưng nó không thể được nâng lên vị trí tiếp theo trong chuỗi (nó không có next()phương thức).

Do đó, hãy cân nhắc việc trả lại hoặc chuyển một Optionalbối cảnh trong đó trước đây bạn có thể đã cân nhắc sử dụng Java Iterator.


-1

Java SE 8 giới thiệu một lớp mới gọi là java.util.Optional,

Bạn có thể tạo một tùy chọn trống hoặc tùy chọn với giá trị null.

Optional<String> emptyOptional = Optional.empty(); 

Và đây là một Tùy chọn có giá trị khác 0:

String valueString = new String("TEST");
Optional<String> optinalValueString = Optional.of(valueString );

Làm một cái gì đó nếu một giá trị là hiện tại

Bây giờ bạn có một đối tượng Tùy chọn, bạn có thể truy cập các phương thức có sẵn để xử lý rõ ràng sự hiện diện hay vắng mặt của các giá trị. Thay vì phải nhớ kiểm tra null, như sau:

String nullString = null;
if (nullString != null) {
    System.out.println(nullString);
}

Bạn có thể sử dụng phương thức ifPftime (), như sau:

Optional<String> optinalString= null;
optinalString.ifPresent(System.out::println);

package optinalTest;

import java.util.Optional;

public class OptionalTest {
    public Optional<String> getOptionalNullString() {
        return null;
//      return Optional.of("TESt");
    }

    public static void main(String[] args) {

        OptionalTest optionalTest = new OptionalTest();

        Optional<Optional<String>> optionalNullString = Optional.ofNullable(optionalTest.getOptionalNullString());

        if (optionalNullString.isPresent()) {
            System.out.println(optionalNullString.get());
        }
    }
}

bản sao này nhằm đạt được danh tiếng giá rẻ, nhưng không liên quan đến câu hỏi của OP
stinger
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.