<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          你一定需要知道的高階JAVA枚舉特性!

          共 4467字,需瀏覽 9分鐘

           ·

          2021-01-14 16:33

          JAVA枚舉,比你想象中功能還要強大!

          我經(jīng)常發(fā)現(xiàn)自己在Java中使用枚舉來表示某個對象的一組值。

          在編譯時確定類型可以具有什么值的能力是一種強大的能力,它為代碼提供了結構和意義。

          當我第一次了解枚舉時,當時我認為它們只是一個為常量命名的工具,可以很容易地被靜態(tài)常量字符串ENUM_VAL_NAME所取代。

          后來我發(fā)現(xiàn)我錯了。事實證明,Java枚舉具有相當高級的特性,可以使代碼干凈、不易出錯,功能強大。

          讓我們一起來看看Java中的一些高級枚舉特性,以及如何利用這些特性使代碼更簡單、更可讀。

          枚舉是類!

          在Java中,枚舉是Object的一個子類。讓我們看看所有枚舉的基類,Enum(為簡潔起見進行了修改)。


          public?abstract?class?Enum<E?extends?Enum<E>>
          ????implements?Constable,?Comparable<E>,?Serializable?
          {
          ??private?final?String?name;
          ??
          ??public?final?String?name()?{
          ??????return?name;
          ??}
          ??
          ??private?final?int?ordinal;
          ??
          ??public?final?int?ordinal()?{
          ??????return?ordinal;
          ??}
          ??
          ??protected?Enum(String?name,?int?ordinal)?{
          ??????this.name?=?name;
          ??????this.ordinal?=?ordinal;
          ??}
          ??
          ??public?String?toString()?{
          ??????return?name;
          ??}
          ??
          ??public?final?boolean?equals(Object?other)?{
          ??????return?this==other;
          ??}
          ??
          ??public?final?int?hashCode()?{
          ??????return?super.hashCode();
          ??}
          ??
          ??public?final?int?compareTo(E?o)?{
          ??????Enum?other?=?(Enum)o;
          ??????Enum?self?=?this;
          ??????if?(self.getClass()?!=?other.getClass()?&&?//?optimization
          ??????????self.getDeclaringClass()?!=?other.getDeclaringClass())
          ??????????throw?new?ClassCastException();
          ??????return?self.ordinal?-?other.ordinal;
          ??}
          }
          ??

          我們可以看到,這基本上只是一個常規(guī)的抽象類,有兩個字段,name和ordinal。

          所以說枚舉都是類,它們具有常規(guī)類的許多特性。

          我們能夠為枚舉提供實例方法、構造函數(shù)和字段。我們可以重寫toString(),但不能重寫hashCode()或equals(Object other)。

          接下來我們看下我們的枚舉示例,Operation

          ??enum?Operation?{
          ????ADD,
          ????SUBTRACT,
          ????MULTIPLY
          ??}

          這個枚舉表示一個Operation可以對兩個值執(zhí)行,并將生成一個結果。關于如何實現(xiàn)此功能,您最初的想法可能是使用switch語句,如下所示:

          ??public?int?apply(Operation?operation,?int?arg1,?int?arg2)?{
          ????switch(operation)?{
          ??????case?ADD:
          ????????return?arg1?+?arg2;
          ??????case?SUBTRACT:
          ????????return?arg1?-?arg2;
          ??????case?MULTIPLY:
          ????????return?arg1?*?arg2;
          ??????default:
          ????????throw?new?UnsupportedOperationException();
          ??}
          }
          ??

          當然,這樣子會有一些問題。

          第一個問題是,如果我們將一個新operation添加到我們的Operation中,編譯器不會通知我們這個開關不能正確處理新操作。

          更糟糕的是,如果一個懶惰的開發(fā)人員在另一個類中復制或重新編寫這些代碼,我們可能無法更新它。

          第二個問題是默認情況default,每段程序里面都是必需的,盡管我們知道在正確的代碼里它永遠不會發(fā)生。

          這是因為Java編譯器知道上面的第一個問題,并且希望確保我們能夠處理在不知情的情況下向Operation中添加了新枚舉。

          還好,Java8用函數(shù)式編程為我們提供了一個干凈的解決方案。

          函數(shù)枚舉實現(xiàn)

          因為枚舉是類,所以我們可以創(chuàng)建一個枚舉字段來保存執(zhí)行操作的函數(shù)。

          但是在我們找到解決方案之前,讓我們先來看看一些重構。

          首先,讓我們把開關放在enum類中。

          ??
          enum?Operation?{
          ??ADD,
          ??SUBTRACT,
          ??MULTIPLY;
          ??
          ??public?static?int?apply(Operation?operation,?int?arg1,?int?arg2)?{
          ????switch(operation)?{
          ??????case?ADD:
          ????????return?arg1?+?arg2;
          ??????case?SUBTRACT:
          ????????return?arg1?-?arg2;
          ??????case?MULTIPLY:
          ????????return?arg1?*?arg2;
          ??????default:
          ????????throw?new?UnsupportedOperationException();
          ????}
          ??}
          }
          ??

          我們可以這樣做:Operation.apply(Operation.ADD, 2, 3);

          因為我們現(xiàn)在從Operation中調用方法,所以我們可以將其更改為實例方法并使用this,而不是用Operation.apply()來實現(xiàn),如下所示:

          public?int?apply(int?arg1,?int?arg2)?{
          ??switch(this)?{
          ????case?ADD:
          ??????return?arg1?+?arg2;
          ????case?SUBTRACT:
          ??????return?arg1?-?arg2;
          ????case?MULTIPLY:
          ??????return?arg1?*?arg2;
          ????default:
          ??????throw?new?UnsupportedOperationException();
          ??}
          }
          ??

          像這樣使用:Operation.ADD.apply(2, 3);

          看起來變好了。現(xiàn)在讓我們更進一步,通過使用函數(shù)式編程完全消除switch語句。

          enum?Operation?{
          ??????????????ADD((x,?y)?->?x?+?y),
          ??????????????SUBTRACT((x,?y)?->?x?-?y),
          ??????????????MULTIPLY((x,?y)?->?x?*?y);
          ??
          ??????????????Operation(BiFunction?operation)?{
          ??????????????????????this.operation?=?operation;
          ??????????????}
          ??
          ??????????????private?final?BiFunction?operation;
          ??
          ??????????????public?int?apply(int?x,?int?y)?{
          ??????????????????????return?operation.apply(x,?y);
          ??????????????}
          ??
          ??}
          ??
          ??

          這里我做的是:

          • 添加了一個字段 BiFunction operation
          • 用BiFunction創(chuàng)建了用于Operation的構造函數(shù)。
          • 調用枚舉定義中的構造函數(shù),并用lambda指定BiFunction。

          這個java.util.function.BiFunction operation字段是對采用兩個參數(shù)的函數(shù)(方法)的引用。

          在我們的例子中,兩個參數(shù)都是int,返回值也是int。不幸的是,Java參數(shù)化類型不支持原語,所以我們必須使用Integer。

          因為BiFunction是用@functioninterface注釋的,所以我們可以使用Lambda表示法定義一個。

          因為我們的函數(shù)接受兩個參數(shù),所以我們可以使用(x,y)來指定它們。

          然后我們定義了一個單行方法,它使用 ->x+y 返回一個值。這相當于下面的方法,只是更簡潔而已。

          ??class?Adder?implements?BiFunction<Integer,?Integer,?Integer>?{
          ??????????@Override
          ??????????public?Integer?apply(Integer?x,?Integer?y)?{
          ??????????????????return?x?+?y;
          ????}
          ??}

          我們的新Operation實現(xiàn)采用相同的方式:Operation.ADD.apply(2, 3);.

          但是,這種實現(xiàn)更好,因為編譯器會告訴我們何時添加了新Operation,這要求我們更新函數(shù)。如果沒有這一點,如果我們在添加新Operation時還不記得更新switch語句,就有可能得到UnsupportedOperationException()。

          關鍵要點

          • Enum枚舉是Enum的擴展類。

          • Enum枚舉可以有字段、構造函數(shù)和實例方法。

          • Enum枚舉字段可以存儲函數(shù)。與lambda配合使用,可以創(chuàng)建干凈、安全的特定于枚舉的函數(shù)實現(xiàn),并在編譯時強制執(zhí)行它們(而不是使用switch)。

          下面是這個示例的GitHub地址。(https://github.com/alex-power/java-enum-example)

          本文參考:https://medium.com/javarevisited/advanced-java-enum-features-you-need-to-know-b516a191c7e2

          往期推薦

          盤點 IDEA2020.3 那些炫酷的插件,超級好用的那種

          不到 20 人的 IT 公司該去嗎?

          文件上傳的單元測試怎么寫?

          Github上看到的4個好玩的開源項目

          一個承載無數(shù)悲痛的網(wǎng)站

          鏈家前DBA判刑7年!你還敢不敢刪庫?



          瀏覽 52
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲色天| 欧美黄片亚洲 | 午夜精品在线观看 | 在线观看黄色小电影 | 一区二区三区入口 |