1. 程式人生 > 其它 >Java中列舉型別的妙用

Java中列舉型別的妙用

技術標籤:# Java 資料型別和集合JavaJava列舉型別遍歷所有的列舉型別遍歷Java列舉型別Java列舉型別用法

在我們開發企業級應用中,有時候會有這樣的需求,需要定義一些常量,比如數字1 代表一個含義,數字2代表一個含義。

為了方便講解,我們這裡假設需要定義訂單狀態。

訂單狀態 1.待付款 10.待發貨 20 已發貨 30 待評價 40已完成 -10:已取消

在這種情況下,對於初級程式設計師可能就會這樣定義

// 訂單型別 1 待付款
public static final Integer WAIT_PAY=1;
// 訂單型別 10 待發貨
public static final Integer WAIT_SEND_GOODS=
10; //訂單型別 20 已發貨 public static final Integer HAVE_SEND_GOODS=20; //訂單型別 30 待評價 public static final Integer WAIT_COMMENT=30; //訂單型別 40 已完成 public static final Integer HAVE_FINISH=40; //訂單型別 -10 取消訂單 public static final Integer CANCEL_ORDER=-10;

這裡每一個數字代表一個訂單狀態,這樣設計雖然也能滿足需求,但是會存在一些問題:

  • 如果開發沒有很好的註釋,那麼可能開發一段時間後你自己就忘了訂單狀態的含義
  • 如果今後專案交接後,接收你專案的人找不到充足的註釋那麼很難理解每個狀態的含義。
  • 如果今後增加了新的訂單狀態,但是註釋沒有更新,那麼新人接手很可能會出現問題。

那麼有沒有什麼更好的解決方法呢?

答案是肯定的,那就是使用Java中的列舉型別。

import lombok.Getter;
/**
 * 商城訂單狀態
 * @author qing-feng.zhao
 */
public enum OrderStatusEnum {
    /**
     * 訂單狀態 1.待付款 10.待發貨 20 已發貨 30 待評價 40已完成  -10:已取消
     */
    WAIT_PAY(1,"待付款"
), WAIT_SEND_GOODS(10,"待發貨"), HAVE_SEND_GOODS(20,"已發貨"), WAIT_COMMENT(30,"待評價"), HAVE_FINISH(40,"已完成"), HAVE_CANCEL(-10,"已取消"); @Getter private Integer key; @Getter private String display_name; OrderStatusEnum(Integer key, String display_name) { this.key = key; this.display_name = display_name; } }

配置好後,如果我們想在業務邏輯中使用就可以這樣呼叫:

OrderStatusEnum.WAIT_PAY.name(); // 輸出結果: WAIT_PAY
OrderStatusEnum.WAIT_PAY.getKey();  //輸出結果:1
OrderStatusEnum.WAIT_PAY.getDisplay_name());  //輸出結果:待付款
OrderStatusEnum.WAIT_PAY.ordinal();//輸出結果: 0
OrderStatusEnum.WAIT_SEND_GOODS.ordinal();//輸出結果 1
OrderStatusEnum.HAVE_SEND_GOODS.ordinal();//輸出結果 2
OrderStatusEnum.WAIT_COMMENT.ordinal();//輸出結果 3
OrderStatusEnum.HAVE_FINISH.ordinal();//輸出結果 4
OrderStatusEnum.HAVE_REFUND_PAY.ordinal();//輸出結果 5

或者這樣進行賦值

        String orderStatusDisplayName;
        Integer orderStatus=1;
        switch (orderStatus)
        {
            case 1:
                orderStatusDisplayName=OrderStatusEnum.WAIT_PAY.getDisplay_name();
                break;
            case 10:
                orderStatusDisplayName=OrderStatusEnum.WAIT_SEND_GOODS.getDisplay_name();
                break;
            case 20:
                orderStatusDisplayName=OrderStatusEnum.HAVE_SEND_GOODS.getDisplay_name();
                break;
            case 30:
                orderStatusDisplayName=OrderStatusEnum.WAIT_COMMENT.getDisplay_name();
                break;
            case 40:
                orderStatusDisplayName=OrderStatusEnum.HAVE_FINISH.getDisplay_name();
                break;
            case -10:
                orderStatusDisplayName=OrderStatusEnum.HAVE_CANCEL.getDisplay_name();
                break;
            default:
                orderStatusDisplayName="未知的訂單狀態";
                break;
        }
        log.info("輸出訂單狀態標籤:{}",orderStatusDisplayName);//輸出結果:輸出訂單狀態標籤:待付款

這樣寫的話,有一個好處就是當每個數字代表的含義發生變化,

比如“待評價”要改成“已收貨”或新增訂單狀態型別的時候,就不需要在程式中到處去找,去修改,只需修改列舉類中的配置即可。

但是以上其實還存在一個問題,那就是訂單狀態數字如果還是寫死的,那麼是不完美的。

其實我們完全還可以針對上面的程式在做一個優化。

        String orderStatusDisplayName=null;
        Integer orderStatus=1;
        for (OrderStatusEnum item:OrderStatusEnum.values()) {
            if(item.getKey().equals(orderStatus)){
                orderStatusDisplayName=item.getDisplay_name();
            }
        }
        log.info("輸出訂單狀態標籤:{}",orderStatusDisplayName);// 輸出結果: 輸出訂單狀態標籤 待付款

經過上面的學習,聰明的你會發現,我們使用了OrderStatusEnum.values()的方法,遍歷了所有的列舉型別。

然後在迴圈中做了判斷,大大簡化並優化了程式碼的編寫和維護。

到這裡,基本上列舉型別的基礎用法就講完了。

不過,博主打算再分享一個系統設計方法。

我們前面提到

訂單狀態 1.待付款 10.待發貨 20 已發貨 30 待評價 40已完成 -10:已取消

如果我們想直接返回訂單狀態列表(包括訂單狀態數字和顯示標籤),不需要做判斷,那麼應該怎麼做呢?

這時候其實我們可以這樣,先封裝一個所有列舉型別通用的VO類——EnumDicVO。

import lombok.Data;

import java.io.Serializable;

/**
 * @author qing-feng.zhao
 */
@Data
public class EnumDicVO implements Serializable {
    private Integer key;
    private String display_name;
}

然後遍歷所有的列舉型別,並封裝一個獲取所有列舉型別code和標籤的靜態方法即可。

     public static List<EnumDicVO> findAllEnumList() {
        if(null==OrderStatusEnum.values()||OrderStatusEnum.values().length<=0){
            return Collections.EMPTY_LIST;
        }
        List<EnumDicVO> orderStatusList=new ArrayList<>(OrderStatusEnum.values().length);
        EnumDicVO enumDicVO;
        for (OrderStatusEnum item:OrderStatusEnum.values()
        ) {
            enumDicVO =new EnumDicVO();
            enumDicVO.setKey(item.getKey());
            enumDicVO.setDisplay_name(item.getDisplay_name());
            orderStatusList.add(enumDicVO);
        }
        return orderStatusList;
    }

最後由於這個方法可能會在很多地方都會呼叫,因此我們直接封裝到列舉類中。

最終優化版本如下:

import lombok.Getter;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 商城訂單狀態
 * @author qing-feng.zhao
 */
public enum OrderStatusEnum {
    /**
     * 這裡是靜態成員變數而不是例項化成員屬性
     * 訂單狀態 1.待付款 10.待發貨 20 已發貨 30 待評價 40已完成  -10:已取消
     */
    WAIT_PAY(1,"待付款"),
    WAIT_SEND_GOODS(10,"待發貨"),
    HAVE_SEND_GOODS(20,"已發貨"),
    WAIT_COMMENT(30,"待評價"),
    HAVE_FINISH(40,"已完成"),
    HAVE_CANCEL(-10,"已取消");
    
    //靜態方法
    public static List<EnumDicVO> findAllEnumList() {
        if(null==OrderStatusEnum.values()||OrderStatusEnum.values().length<=0){
            return Collections.EMPTY_LIST;
        }
        List<EnumDicVO> orderStatusList=new ArrayList<>(OrderStatusEnum.values().length);
        EnumDicVO enumDicVO;
        for (OrderStatusEnum item:OrderStatusEnum.values()
        ) {
            enumDicVO =new EnumDicVO();
            enumDicVO.setKey(item.getKey());
            enumDicVO.setDisplay_name(item.getDisplay_name());
            orderStatusList.add(enumDicVO);
        }
        return orderStatusList;
    }

    //例項化成員屬性
    @Getter
    private Integer key;
    @Getter
    private String display_name;

    //例項化構造方法
    OrderStatusEnum(Integer key, String display_name) {
        this.key = key;
        this.display_name = display_name;
    }
}

值得注意的是,

  • WAIT_PAY 是靜態值物件,並不是例項化成員屬性值
  • 如果不是很理解的話可以看下這篇反編譯詳解:重新認識java(十) ---- Enum(列舉類)
  • 我們這裡findAllEnumList()方法中其實是靜態方法中呼叫了例項化構造方法。
  • 上面如果不好理解的話,我們可以換個例子
import java.util.ArrayList; import java.util.List; 
/**  
* @author qing-feng.zhao  
*/ 
public class CommonEnum {
    private static MyPageParam MyPageA=new MyPageParam(1,10);
    private static MyPageParam MyPageB=new MyPageParam(2,20);

    public static List<MyPageParam> findAllEnumList() {
        List<MyPageParam> myList=new ArrayList<>();
        myList.add(MyPageA);
        myList.add(MyPageB);
        return myList;
    }
} 

這樣我們無論在哪裡想要獲取這個列舉型別列表都可以這樣呼叫就行了:

List<EnumDicVO> orderStatusList=TimerTaskTypeEnum.findAllEnumList();
log.info("{}",orderStatusList);

輸出結果:

[EnumDicVO(key=1, display_name=待付款), EnumDicVO(key=10, display_name=待發貨), EnumDicVO(key=20, display_name=已發貨), EnumDicVO(key=30, display_name=待評價), EnumDicVO(key=40, display_name=已完成), EnumDicVO(key=-10, display_name=已取消)]

UI最終 效果
在這裡插入圖片描述
本篇完~

感謝您的閱讀,喜歡我的文章,歡迎點贊關注或分享。