網頁

2019/9/24

Java 列舉 Enum valueOf()正確用法

最近發現蠻多人會在業務邏輯程式中直接使用Enum.valueOf(String arg0)將傳入的字串轉為對應的Enum型別,而這樣是好的寫法嗎?

先說結論,不應該在業務邏輯中(例如Service層)使用Enum.valueOf(String arg0),此方法應該只在Enum內部使用,原因如下。

例如現在有個簡單的Enum型別CardType,有兩個列舉CREDITDEBIT分別表示信用卡與簽帳卡。

public enum CardType {
    
    CREDIT, DEBIT;
    
}    

由於傳來的字串參數會是各種樣式,若在業務邏輯中直接用valueOf(),若傳入的參數不同於列舉本身的文字,就會造成java.lang.IllegalArgumentException錯誤。

例如下面的方法會根據傳入的cardType判斷為信用卡還是簽帳卡去不同的資料表撈取客戶資料。

public Customer getCustomer(String cardNumber, String cardType) {
    
    CardType type = CardType.valueOf(cardType); // IllegalArgumentException if cardType is not "CREDIT" or "DEBIT"
    
    switch(type) {
        case CREDIT:
            // query Credit Card Table
            break;
        case DEBIT:
            // query Debit Card Table
            break;
    }
    //...
}

在上面的方法中,如果cardType字串不是"CREDIT""DEBIT"就會丟出IllegalArgumentException導致程式停止。

傳入的字串不但文字要相同,大小寫也要相同。

CardType.valueOf("CREDIT");
CardType.valueOf("credit"); // 發生IllegalArgumentException錯誤

也就是說使用Enum.valueOf(String arg0)前都必須檢查傳入的字串是否符合列舉的名稱,以文字大小寫不同為例,有的人可能會這樣寫。

public Customer getCustomer(String cardNumber, String cardType) {
    
    CardType type = CardType.valueOf(cardType.toUpperCase()); // 轉成大寫
    
    switch(type) {
        case CREDIT:
            // query Credit Card Table
            break;
        case DEBIT:
            // query Debit Card Table
            break;
    }
    //...
}

但這樣的問題是所有業務邏輯中有用到valueOf()的地方都要用toUpperCase()轉成大寫。此外如果傳入的字串是null每個地方還要加上null的檢查。當用到的地方一多很容易疏漏要做的檢查,而且若有改動全部的地方都要修改非常麻煩。

所以在業務邏輯中要轉字串為對應的Enum,應該集中在Enum中寫一個統一的轉換方法如下。當業務邏輯中要轉字串為Enum時就呼叫此方法。

public enum CardType {
    
    CREDIT, DEBIT;
    
    public static CardType getEnum(String value) {
        if (value == null || value.length() < 1) {
            return null;
        }
        
        for (CardType t : values()) {
            if (t.name().equalsIgnoreCase(value)) {
                return t;
            }
        }
        
        return null;
    }
}  

業務邏輯中改為如下。

public Customer getCustomer(String cardNumber, String cardType) {
    
    CardType type = CardType.getEnum(cardType); // <--
    
    switch(type) {
        case CREDIT:
            // query Credit Card Table
            break;
        case DEBIT:
            // query Debit Card Table
            break;
    }
    //...
}

參考:

沒有留言:

張貼留言