java java se_Java 8 SE可选,严格的方法
java java se
大約兩周前,Stephen Colebourne提出了使用Optional的實用方法 。 如果您閱讀了它,您可能會從我以前的建議中猜到我不同意。
總覽
我必須以免責聲明開頭,然后我將直接解釋為什么我認為他的方法不那么理想。
所有不歸因于他人的報價均摘自Stephen的帖子。 雖然并非絕對必要,但我建議先閱讀它。 但是別忘了回來!
我創建了三個要點,這些要點在整個帖子中都會介紹: Stephen版本 , 基本版本和擴展版本中的相同示例。
免責聲明
Stephen Colebourne是Java的傳奇人物。 引用Markus Eisele的Java英雄關于他的文章:
Stephen Colebourne是OpenGamma的技術人員。 他以其在開源和博客中的工作而聞名。 他創建了Joda-Time,現在將其進一步開發為JSR-310 / ThreeTen。 他為關于Java未來的辯論做出了貢獻,包括為泛型和FCM閉包的鉆石運算符提出的建議,這兩者都接近于Java 7和8中已采用的更改。Stephen是會議的常任發言人,JavaOne Rock Star和Java Champion。 。
我很高興為斯蒂芬的房地產聯盟做出貢獻,這增強了我對他作為一個非常有能力的開發商和一個非常有思想的人的看法。
所有這些都表明,如果有疑問,請相信他。
事實是,他的方法根植于公理,即Optional應該僅用作返回類型。 這完全符合那些首先介紹該課程的人的建議。 引用Brian Goetz的話 :
當然,人們會做他們想要的。 但是,添加此功能時我們確實有明確的意圖,并且它并不是通用的Maybe或Some類型,這是許多人希望我們這樣做的原因。 我們的意圖是為庫方法返回類型提供一種有限的機制,其中需要一種明確的方式來表示“無結果”,而為此使用null則極有可能導致錯誤。
[…]幾乎永遠不要將其用作某些內容或方法參數的字段。因此,如果有疑問,請相信他對我的看法。
發布時間由JD漢考克在CC-BY 2.0 。
并置
當然,比只相信任何人更好的是下定決心。 因此,與斯蒂芬的觀點相反,這是我的觀點。
基本要點
這些是斯蒂芬的五個基本要點:
這是我的:
例子
讓我們比較例子。 他的是:
Address.java,作者:Stephen Colebourne
public class Address {private final String addressLine; // never nullprivate final String city; // never nullprivate final String postcode; // optional, thus may be null// constructor ensures non-null fields really are non-null// optional field can just be stored directly, as null means optionalpublic Address(String addressLine, String city, String postcode) {this.addressLine = Preconditions.chckNotNull(addressLine);this.city = Preconditions.chckNotNull(city);this.postcode = postcode;}// normal getterspublic String getAddressLine() {return addressLine;}public String getCity() {return city;}// special getter for optional fieldpublic Optional<String> getPostcode() {return Optional.ofNullable(postcode);}// return optional instead of null for business logic methods that may not find a resultpublic static Optional<Address> findAddress(String userInput) {return... // find the address, returning Optional.empty() if not found}}我喜歡此類的任何使用者都不能接收null。 我不喜歡您仍然需要如何處理-在課堂上還是在課堂上。
這將是我的(基本)版本:
我的Address.java(基本版)
public class Address {// look ma, no comments requiredprivate final String addressLine;private final String city;private final Optional<String> postcode;// nobody has to look at this constructor to check which parameters are// allowed to be null because of course none are!public Address(String addressLine, String city, Optional<String> postcode) {this.addressLine = requireNonNull(addressLine,"The argument 'addressLine' must not be null.");this.city = requireNonNull(city,"The argument 'city' must not be null.");this.postcode = requireNonNull(postcode,"The argument 'postcode' must not be null.");}// of course methods that might not have a result// return 'Optional' instead of nullpublic static Optional<Address> findAddress(String userInput) {// find the address, returning Optional.empty() if not found}// getters are straight forward and can be generatedpublic String getAddressLine() {return addressLine;}public String getCity() {return city;}// look how the field's type matches the getter's type;// nice for bean-based code/toolspublic Optional<String> getPostcode() {return postcode;}}這里根本沒有空值。
差異性
約束問題
在對象內,開發人員仍然被迫考慮null并使用!= null檢查對其進行管理。 這是合理的,因為null問題受到了限制。 該代碼將全部作為一個單元編寫和測試(您確實編寫測試不是嗎?),因此null不會引起很多問題。
您看到他的構造函數如何允許其中一個參數為null嗎? 找出哪一個需要您離開正在做的事情并查看其他類的代碼的唯一方法。 這不是什么大事,但是沒有必要。
即使撇開這一點,問題也沒有受到應有的限制。 假設每個人都不喜歡注釋 ,我們必須假定它們不存在,這使構造函數內部和getter的返回類型告訴您該字段可為空。 這不是讓您跳出來的最佳信息。
很明顯可選很明顯
public class Address {// look ma, no comments requiredprivate final String addressLine;private final String city;private Optional<String> postcode;// nobody has to look at these constructors to check which parameters are// allowed to be null because of course none are!public Address(String addressLine, String city, Optional<String> postcode) {this.addressLine = requireNonNull(addressLine,"The argument 'addressLine' must not be null.");this.city = requireNonNull(city,"The argument 'city' must not be null.");this.postcode = requireNonNull(postcode,"The argument 'postcode' must not be null.");}public Address(String addressLine, String city, String postcode) {// use 'requireNonNull' inside Optional factory method// if you prefer a verbose exception message;// otherwise 'Optional.of(postcode)' sufficesthis(addressLine, city, Optional.of(requireNonNull(postcode,"The argument 'postcode' must not be null.")));}public Address(String addressLine, String city) {this(addressLine, city, Optional.empty());}// now if some method needs to use the postcode,// we can not overlook the fact that it is optionalpublic int comparePostcode(Address other) {// without Optionals we might overlook that the postcode// could be missing and do this:// return this.postcode.compareTo(other.postcode);if (this.postcode.isPresent() && other.postcode.isPresent())return this.postcode.get().compareTo(other.postcode.get());else if (this.postcode.isPresent())return 1;else if (other.postcode.isPresent())return -1;elsereturn 0;}// of course methods that might not have a result// return 'Optional' instead of nullpublic static Optional<Address> findAddress(String userInput) {// find the address, returning Optional.empty() if not found}// getters are straight forward and can be generatedpublic String getAddressLine() {return addressLine;}public String getCity() {return city;}// look how the field's type matches the getter's type;// nice for bean-based code/toolspublic Optional<String> getPostcode() {return postcode;}// in case this 'Address' is mutable// (which it probably shouldn't be but let's presume it is)// you can decide whether you prefer a setter that takes an 'Optional',// a pair of methods to set an existing and an empty postcode, or bothpublic void setPostcode(Optional<String> postcode) {this.postcode = requireNonNull(postcode,"The argument 'postcode' must not be null.");}public void setPostcode(String postcode) {// again you might want to use 'requireNonNull'// if you prefer a verbose exception message;this.postcode = Optional.of(requireNonNull(postcode,"The argument 'postcode' must not be null."));}public void setEmptyPostcode() {this.postcode = Optional.empty();}}他的測試論據可能會被數字打斷。 如果所有測試都包含所有字段,則每個可選字段將使測試數量加倍,因為每個測試都應在null和non-null情況下運行。 我更喜歡將類型系統作為第一道防線。
另一方面,這種痛苦可能會說服開發人員在單個類中找到可選項較少的解決方案。
性能
Stephen正確指出,為方法返回值創建的實例然后被快速丟棄(這對于Optional的使用是典型的),幾乎沒有成本。 與Optional字段不同,后者在整個包含對象的整個生命周期中都存在,并增加了從該對象到Optional的有效負載的間接附加層。
對他來說,這是更喜歡null的原因。
雖然很容易斷言這是“過早的優化”,但作為工程師,我們有責任了解我們所使用系統的限制和功能,并仔細選擇應強調的點。
我同意。 但是對我來說,謹慎選擇的一部分意味著要首先介紹。 而且,如果有人向我展示令人信服的論點,即在他的具體情況下,將某些Optional字段替換為可為空的字段會帶來明顯的性能提升,那么我會立即刪除它們的愚蠢框。 但是在所有其他情況下,我堅持使用我認為更易于維護的代碼。
順便說一句,對于使用數組而不是ArrayLists或使用char-arrays而不是字符串,可以使用相同的參數。 我敢肯定,如果沒有明顯的性能提升,沒有人會遵循該建議。
但是,討論中的這個重復主題值得關注。 我將嘗試尋找一些時間來介紹一些我認為很有趣的用例。
可序列化
盡管這只是次要點,但應注意,該類可以是可序列化的,如果任何字段為Optional(因為Optional不實現Serializable),則該類是不可能的。
我認為這是可以解決的 。 但是,這會導致一些額外的工作。
方便
我的經驗是,在設置程序或構造函數上使用Optional對調用者很煩,因為它們通常具有實際對象。 強制調用者將參數包裝在Optional中是一種麻煩,我希望不要對用戶造成影響。 (即便利性勝過輸入的嚴格性)雖然編寫令人討厭的代碼可能很有趣,但我明白了他的觀點。 所以不要強迫用戶,不要重載您的方法 :
重載構造函數以避免創建可選項
public class Address {// look ma, no comments requiredprivate final String addressLine;private final String city;private Optional<String> postcode;// nobody has to look at these constructors to check which parameters are// allowed to be null because of course none are!public Address(String addressLine, String city, Optional<String> postcode) {this.addressLine = requireNonNull(addressLine,"The argument 'addressLine' must not be null.");this.city = requireNonNull(city,"The argument 'city' must not be null.");this.postcode = requireNonNull(postcode,"The argument 'postcode' must not be null.");}public Address(String addressLine, String city, String postcode) {// use 'requireNonNull' inside Optional factory method// if you prefer a verbose exception message;// otherwise 'Optional.of(postcode)' sufficesthis(addressLine, city, Optional.of(requireNonNull(postcode,"The argument 'postcode' must not be null.")));}public Address(String addressLine, String city) {this(addressLine, city, Optional.empty());}// now if some method needs to use the postcode,// we can not overlook the fact that it is optionalpublic int comparePostcode(Address other) {// without Optionals we might overlook that the postcode// could be missing and do this:// return this.postcode.compareTo(other.postcode);if (this.postcode.isPresent() && other.postcode.isPresent())return this.postcode.get().compareTo(other.postcode.get());else if (this.postcode.isPresent())return 1;else if (other.postcode.isPresent())return -1;elsereturn 0;}// of course methods that might not have a result// return 'Optional' instead of nullpublic static Optional<Address> findAddress(String userInput) {// find the address, returning Optional.empty() if not found}// getters are straight forward and can be generatedpublic String getAddressLine() {return addressLine;}public String getCity() {return city;}// look how the field's type matches the getter's type;// nice for bean-based code/toolspublic Optional<String> getPostcode() {return postcode;}// in case this 'Address' is mutable// (which it probably shouldn't be but let's presume it is)// you can decide whether you prefer a setter that takes an 'Optional',// a pair of methods to set an existing and an empty postcode, or bothpublic void setPostcode(Optional<String> postcode) {this.postcode = requireNonNull(postcode,"The argument 'postcode' must not be null.");}public void setPostcode(String postcode) {// again you might want to use 'requireNonNull'// if you prefer a verbose exception message;this.postcode = Optional.of(requireNonNull(postcode,"The argument 'postcode' must not be null."));}public void setEmptyPostcode() {this.postcode = Optional.empty();}}當然,這在許多可選字段中無法很好地擴展。 在這種情況下,構建器模式會有所幫助。
事實是,如果我們的可為空的郵政編碼中有一個setter,則處理其他代碼的開發人員必須再次停止并查看此類,以確定她是否可以傳遞null。 由于她永遠不能確定,因此她也必須檢查其他吸氣劑。 談論煩人的代碼...
使用Optional類型的字段,setter可能如下所示:
重載的二傳手,避免創建可選項
public class Address {// look ma, no comments requiredprivate final String addressLine;private final String city;private Optional<String> postcode;// nobody has to look at these constructors to check which parameters are// allowed to be null because of course none are!public Address(String addressLine, String city, Optional<String> postcode) {this.addressLine = requireNonNull(addressLine,"The argument 'addressLine' must not be null.");this.city = requireNonNull(city,"The argument 'city' must not be null.");this.postcode = requireNonNull(postcode,"The argument 'postcode' must not be null.");}public Address(String addressLine, String city, String postcode) {// use 'requireNonNull' inside Optional factory method// if you prefer a verbose exception message;// otherwise 'Optional.of(postcode)' sufficesthis(addressLine, city, Optional.of(requireNonNull(postcode,"The argument 'postcode' must not be null.")));}public Address(String addressLine, String city) {this(addressLine, city, Optional.empty());}// now if some method needs to use the postcode,// we can not overlook the fact that it is optionalpublic int comparePostcode(Address other) {// without Optionals we might overlook that the postcode// could be missing and do this:// return this.postcode.compareTo(other.postcode);if (this.postcode.isPresent() && other.postcode.isPresent())return this.postcode.get().compareTo(other.postcode.get());else if (this.postcode.isPresent())return 1;else if (other.postcode.isPresent())return -1;elsereturn 0;}// of course methods that might not have a result// return 'Optional' instead of nullpublic static Optional<Address> findAddress(String userInput) {// find the address, returning Optional.empty() if not found}// getters are straight forward and can be generatedpublic String getAddressLine() {return addressLine;}public String getCity() {return city;}// look how the field's type matches the getter's type;// nice for bean-based code/toolspublic Optional<String> getPostcode() {return postcode;}// in case this 'Address' is mutable// (which it probably shouldn't be but let's presume it is)// you can decide whether you prefer a setter that takes an 'Optional',// a pair of methods to set an existing and an empty postcode, or bothpublic void setPostcode(Optional<String> postcode) {this.postcode = requireNonNull(postcode,"The argument 'postcode' must not be null.");}public void setPostcode(String postcode) {// again you might want to use 'requireNonNull'// if you prefer a verbose exception message;this.postcode = Optional.of(requireNonNull(postcode,"The argument 'postcode' must not be null."));}public void setEmptyPostcode() {this.postcode = Optional.empty();}}同樣,所有的空值都會立即得到答復,但有例外。
豆子
不利的一面是,這種方法導致的對象不是bean。
是的 擁有類型為Optional的字段不會因此受到影響。
共性
我們在這里討論細節不容忽視。 我們的目標是相同的,并且我們提出了類似的實現目標的方法。
如果在應用程序中廣泛采用,則null問題趨于消失而無需付出很大的努力。 由于每個域對象都拒絕返回null,因此應用程序往往永遠不會傳遞null。 以我的經驗,采用這種方法往往會導致在類的私有范圍之外從未使用過null的代碼。 重要的是,這自然而然地發生了,而不是一個痛苦的過渡。 隨著時間的流逝,您開始編寫防御性較小的代碼,因為您更有信心沒有任何變量實際包含null。
這是一個偉大的目標! 并遵循斯蒂芬的建議將帶給您大部分幫助。 因此,不要以我的不同為理由而不使用Optional。
我要說的是,我幾乎沒有理由停止更多地禁止null!
反射
每當有可為空的內容時,我就解決一些問題并希望駁斥一些反對使用Optional的論點。 我希望表明我更嚴格的方法在驅散null方面做得更好。 這應該使您有更多的精力去思考更多相關的問題。
付出的代價可能會降低性能。 如果有人證明更多,對于這些特定情況,我們仍然可以返回null。 或將硬件扔在問題上。 或等待值類型 。
你怎么看?
翻譯自: https://www.javacodegeeks.com/2015/08/java-8-se-optional-a-strict-approach.html
java java se
總結
以上是生活随笔為你收集整理的java java se_Java 8 SE可选,严格的方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安卓微信助手插件(安卓微信助手)
- 下一篇: 门市牌子备案(门市备案表)