日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java Comparable接口的陷阱

發布時間:2023/12/3 java 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java Comparable接口的陷阱 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Java Comparable接口提供了一種對實現該接口的類進行自然排序的方法。 自然順序對標量和其他非常簡單的對象有意義,但是當我們使用面向業務的領域對象時,自然順序就變得更加復雜。 從業務經理的角度來看,交易對象的自然順序可以是交易的價值,但是從系統管理員的角度來看,自然順序可以是交易的速度。 在大多數情況下,業務域對象沒有明確的自然順序。

假設我們已經為諸如Company這樣的類找到了良好的自然排序。 我們將使用公司的正式名稱作為主要訂單字段,并使用公司ID作為次要字段。 公司類的實現可以如下。

public class Company implements Comparable<Company> {private final String id;private final String officialName;public Company(final String id, final String officialName) {this.id = id;this.officialName = officialName;}public String getId() {return id;}public String getOfficialName() {return officialName;}@Overridepublic int hashCode() {HashCodeBuilder builder = new HashCodeBuilder(17, 29);builder.append(this.getId());builder.append(this.getOfficialName());return builder.toHashCode();}@Overridepublic boolean equals(final Object obj) {if (obj == this) {return true;}if (!(obj instanceof Company)) {return false;}Company other = (Company) obj;EqualsBuilder builder = new EqualsBuilder();builder.append(this.getId(), other.getId());builder.append(this.getOfficialName(), other.getOfficialName());return builder.isEquals();}@Overridepublic int compareTo(final Company obj) {CompareToBuilder builder = new CompareToBuilder();builder.append(this.getOfficialName(), obj.getOfficialName());builder.append(this.getId(), obj.getId());return builder.toComparison();} }

該實現看起來不錯并且可以正常工作。 對于某些用例,Company類是不夠的,因此我們將其擴展到CompanyDetails類,該類提供有關公司的更多信息。 例如,可以在顯示公司詳細信息的數據表中使用這些類的實例。

public class CompanyDetails extends Company {private final String marketingName;private final Double marketValue;public CompanyDetails(final String id, final String officialName, final String marketingName, final Double marketValue) {super(id, officialName);this.marketingName = marketingName;this.marketValue = marketValue;}public String getMarketingName() {return marketingName;}public Double getMarketValue() {return marketValue;}@Overridepublic int hashCode() {HashCodeBuilder builder = new HashCodeBuilder(19, 31);builder.appendSuper(super.hashCode());builder.append(this.getMarketingName());return builder.toHashCode();}@Overridepublic boolean equals(final Object obj) {if (obj == this) {return true;}if (!(obj instanceof CompanyDetails)) {return false;}CompanyDetails other = (CompanyDetails) obj;EqualsBuilder builder = new EqualsBuilder();builder.appendSuper(super.equals(obj));builder.append(this.getMarketingName(), other.getMarketingName());builder.append(this.getMarketValue(), other.getMarketValue());return builder.isEquals();} }

乍一看,該實現看起來還不錯,但實際上并非如此。 我們可以創建一個小的測試用例來指示實現問題。 當我們不知道類的實際接口在做什么,并且我們對擴展的超類的所有細節沒有給予足夠的關注時,就會出現問題。

CompanyDetails c1 = new CompanyDetails("231412", "McDonalds Ltd", "McDonalds food factory", 120000.00); CompanyDetails c2 = new CompanyDetails("231412", "McDonalds Ltd", "McDonalds restaurants", 60000.00);Set<CompanyDetails> set1 = CompaniesFactory.createCompanies1(); set1.add(c1); set1.add(c2);Set<CompanyDetails> set2 = CompaniesFactory.createCompanies2(); set2.add(c1); set2.add(c2);Assert.assertEquals(set1.size(), set2.size());

我們使用兩個集合,但要意識到它們的行為有所不同。 這是為什么? 另一個集是HashSet,它依賴于對象的hashCode()和equals()方法,而另一個是TreeSet,并且僅依賴于Comparable接口,而我們并未為子類實現該接口。 擴展域對象時,這是一個很常見的錯誤,但更重要的是,這與錯誤的編碼約定有關。 我們使用Apache Commons的構建器來實現hashCode() , equals()和compareTo()方法。 建設者提供了appendSuper()方法,該方法指示應將其用于該方法的超類的實現。 如果您讀過Joshua Bloch撰寫的精彩著作《 Effective Java》 ,您將意識到這是不對的。 如果在子類中添加字段,則在不違反對稱規則的情況下,我們無法正確實現equals()或compareTo()方法。 我們應該使用組合而不是繼承。 如果我們使用組合來創建CompanyDetails,那么Comparable接口就不會有問題,因為我們不會自動實現它,并且默認情況下允許行為異常。 而且我們也可以適當地滿足equals()和hashCode()的要求。

這篇文章中提到的問題很普遍,但通常被忽略。 可比接口的問題實際上是由不正確的約定引起的,并且不了解所用接口的要求。 作為Java開發人員或架構師,您應該注意諸如此類的事情,并遵守良好的編碼約定和實踐。 項目越大,避免人為因素造成的錯誤就越重要。 我試圖為可比接口總結一個良好的最佳實踐列表,以便可以避免錯誤。

Java可比接口設計和用法的最佳實踐:

  • 了解您正在創建的域對象,如果該對象沒有明確的自然順序,則不要實現Comparable接口。
  • 比Comparable更喜歡Comparator實現。 比較器可以根據用例以更面向業務的方式使用。
  • 如果您需要創建依賴于比較對象的接口或庫,請盡可能提供自己的Comparator實現,否則創建良好的文檔,說明如何為您的接口實現Comparator。
  • 遵守良好的編碼約定和慣例。 有效的Java是入門的好書。

參考:來自RAINBOW WORLDS博客的JCG合作伙伴 Tapio Rautonen 的Java Comparable接口的陷阱 。

翻譯自: https://www.javacodegeeks.com/2013/08/pitfalls-of-java-comparable-interface.html

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的Java Comparable接口的陷阱的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。