成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

簡談Java Enum

BicycleWarrior / 3064人閱讀

摘要:常量接口是對接口的一種不良使用。如果這些常量最好被看作是枚舉類型成員,那就應(yīng)該用枚舉類型來導(dǎo)出。因為客戶端既不能創(chuàng)建枚舉類型的實例,也不能對它進(jìn)行擴(kuò)展,因此很可能沒有實例,而只有聲明過的枚舉常量。換句話說,枚舉類型是實例受控的。

問題

我們偶爾能在項目中看到如下風(fēng)格的代碼:

public class ResponseCode {
    public static final int SUCCESS = 0;
    public static final int FAILURE = 10000;
    public static final int ILLEGAL_ARGUMENT = 10001;
    //........
}

這樣的代碼一般被叫做int枚舉模式。其包含著大量缺點:

int枚舉是編譯時常量,被編譯到客戶端中,如果枚舉常量關(guān)聯(lián)的int發(fā)生變化,客戶端必須重新編譯,如果沒有重新編譯,程序仍可以運行,但行為就不確定了。

將int枚舉常量翻譯成可打印的字符串很麻煩。

在本例中,我要向客戶端返回一個錯誤碼和錯誤信息,錯誤碼可以通過ResponseCode.FAILURE獲得,但是錯誤信息恐怕只能以"FAILURE"這樣的hard code返回了。

遍歷一個組中所有的int枚舉常量,獲得int枚舉組的大小,沒有可靠的方法。

在這種int枚舉模式的基礎(chǔ)上,還有一種變體,我們稱之為String枚舉模式。雖然它提供了可打印的字符串,但這種方式存在性能問題,因為依賴于字符串的比較操作。

還有一種代碼類似:

public interface CascadeConstant {
    String DELETION_CHECK_CODE = "deletion.check";
    String DELETION_DELETE_CODE = "deletion.delete";
    String DELETION_FORCE_DELETE_CODE = "deletion.forceDelete";
    String DELETION_CLEANUP_CODE = "deletion.cleanup";

    List DELETION_CODES = Arrays.asList(DELETION_CHECK_CODE, DELETION_DELETE_CODE, DELETION_FORCE_DELETE_CODE);
}

這樣的代碼我們一般稱之為常量接口(constant interface)——這種接口不包含任何方法,它只包含靜態(tài)的final域,每個域都導(dǎo)出一個常量。

類實現(xiàn)接口時,接口就充當(dāng)可以引用這個類的實例類型。因此,類實現(xiàn)了接口,就表明客戶端對這個類的實例可以實施某些動作。為了任何其他目的而定義的接口是不恰當(dāng)?shù)摹?/p>

?常量接口是對接口的一種不良使用。類在內(nèi)部使用某些常量,純粹是實現(xiàn)細(xì)節(jié),實現(xiàn)常量接口,會導(dǎo)致把這樣的實現(xiàn)細(xì)節(jié)泄露到該類的導(dǎo)出API中,因為接口中所有的域都是及方法public的。類實現(xiàn)常量接口,這對于這個類的用戶來講并沒有實際的價值。實際上,這樣做返回會讓他們感到更糊涂,這還代表了一種承諾:如果在將來的發(fā)行版本中,這個類被修改了,它不再需要使用這些常量了,依然必須實現(xiàn)這個接口,以確保二進(jìn)制兼容性。如果非final類實現(xiàn)了常量接口,它的所有子類的命名空間都受到了污染。Java平臺類庫中存在幾個常量接口,如java.io.ObjectStreamConstants,這些接口都是反面典型,不值得效仿。

那既然不適合存在全部都是導(dǎo)出常量的常量接口,那么如果需要導(dǎo)出常量,它們應(yīng)該放在哪里呢?如果這些常量與某些現(xiàn)有的類或者接口緊密相關(guān),就應(yīng)該把這些常量添加到這個類或者接口中,注意,這里說添加到接口中并不是指的常量接口。在Java平臺類庫中所有的數(shù)值包裝類都導(dǎo)出MIN_VALUE和MAX_VALUE常量。如果這些常量最好被看作是枚舉類型成員,那就應(yīng)該用枚舉類型來導(dǎo)出。否則,應(yīng)該使用不可實例化的工具類來導(dǎo)出這些常量。

實踐

我們先看改良版的ResponseCode :

public enum ResponseCode {
    SUCCESS(0),
    ERROR(10000),
    ILLEGAL_ARGUMENT(10001);

    private final int code;

    ResponseCode(int code) {
        this.code = code;
    }

    public int getCode() {
        return code;
    }

    public static ResponseCode getEnum(int value) {
        for (ResponseCode responseCode : ResponseCode.values()) {
            if (responseCode.getCode()==value) {
                return responseCode;
            }
        }
        return null;
    }
}

這樣就克服了我們之前提到的缺點:類型確定。
在int枚舉模式中或者String枚舉模式中,我們會寫出這樣的方法簽名:

//int 枚舉模式
SendResponse(String description,int value)
//String枚舉模式
//SendResponse(String description,int value)

這樣的代碼其實并不可靠,我們可以考慮:

SendResponse(String description,int code)

那么在調(diào)用的時候?qū)嵸|(zhì)上是:

SendResponse(ResponseCode.ERROR.toString(),ResponseCode.ERROR.getCode())

為了更加方便,我們可以在此之上簡單的封裝一層:

AutoBuildAndSendResponse(ResponseCode responseCode){
  SendResponse(responseCode.toString(),responseCode.getCode();
}

這就很美滋滋。

在這個情況下,我們甚至還可以考慮在SendResponse方法中再加一個名為errorDetail的參數(shù)。利用方法重載,使Reponse的返回信息更為靈活。

不僅如此,Java的枚舉類是很強大的。其本質(zhì)是int值,并且背后基本原理也非常簡單:它們就是通過共有的靜態(tài)final域為每個枚舉常量導(dǎo)出實例的類。因為沒有可以訪問的構(gòu)造器,枚舉類是真正的final。因為客戶端既不能創(chuàng)建枚舉類型的實例,也不能對它進(jìn)行擴(kuò)展,因此很可能沒有實例,而只有聲明過的枚舉常量。換句話說,枚舉類型是實例受控的。而且,Java的枚舉類還可以添加任意的方法和域,并實現(xiàn)任意接口,而且也提供了所有的Object方法的高級實現(xiàn)。

關(guān)于StringValue的較佳實踐
public enum SourceDiskType {

    SYSTEM("system"),
    DATA("data"),;

    private String stringValue;

    SourceDiskType(String stringValue) {
        setStringValue(stringValue);
    }

    public String getStringValue() {
        return stringValue;
    }

    public void setStringValue(String stringValue) {
        this.stringValue = stringValue;
    }

    public static SourceDiskType getEnum(String stringValue) {
        if (null == stringValue) {
            return null;
        }

        for (SourceDiskType sourceDiskType : SourceDiskType.values()) {
            if (sourceDiskType.getStringValue().equals(stringValue)) {
                return sourceDiskType;
            }
        }
        return null;
    }
}

這是阿里云早期版本SDK中的一段代碼。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/70211.html

相關(guān)文章

  • 簡談Java String

    摘要:而用關(guān)鍵字調(diào)用構(gòu)造器,總是會創(chuàng)建一個新的對象,無論內(nèi)容是否相同。中對象的哈希碼被頻繁地使用比如在等容器中。字符串不變性保證了碼的唯一性因此可以放心地進(jìn)行緩存。對于所有包含方式新建對象包括的連接表達(dá)式,它所產(chǎn)生的新對象都不會被加入字符串池中。 前言 前陣子和同事在吃飯時聊起Java的String,覺得自己之前的筆記寫的略顯零散。故此又重新整理了一下。 String在Java中算是一個有意...

    ssshooter 評論0 收藏0
  • 簡談文件下載的三種方式

    摘要:一前言本文章將以報表下載為例,給大家介紹三種文件下載的方式。通過二進(jìn)制數(shù)據(jù)流的方式下載這種方式是我目前采用的方式,用于處理報表下載。缺點對于數(shù)據(jù)量不大的文件,這種方式是可行的。 一、前言 本文章將以excel報表下載為例,給大家介紹三種文件下載的方式。 原文地址:簡談文件下載的三種方式 | Rychou 二、正文 1. 通過服務(wù)器文件地址下載 這是最常見的文件下載方式,大多數(shù)網(wǎng)站的音頻...

    lsxiao 評論0 收藏0
  • 簡談文件下載的三種方式

    摘要:一前言本文章將以報表下載為例,給大家介紹三種文件下載的方式。通過二進(jìn)制數(shù)據(jù)流的方式下載這種方式是我目前采用的方式,用于處理報表下載。缺點對于數(shù)據(jù)量不大的文件,這種方式是可行的。 一、前言 本文章將以excel報表下載為例,給大家介紹三種文件下載的方式。 原文地址:簡談文件下載的三種方式 | Rychou 二、正文 1. 通過服務(wù)器文件地址下載 這是最常見的文件下載方式,大多數(shù)網(wǎng)站的音頻...

    2i18ns 評論0 收藏0
  • 簡談JavaScript閉包

    摘要:所以經(jīng)??吹降恼f閉包就是綁定了上下文環(huán)境的函數(shù)。我更偏向于閉包是一個函數(shù)和聲明該函數(shù)的詞法環(huán)境的組合。里面的閉包先上一個閉包該例子的解釋上面的代碼,在函數(shù)里面定義的函數(shù)和這個函數(shù)聲明的詞法環(huán)境就形成了一個閉包。 閉包是什么 第一種說法:閉包創(chuàng)建一個詞法作用域,這個作用域里面的變量被引用之后可以在這個詞法作用域外面被自由訪問,是一個函數(shù)和聲明該函數(shù)的詞法環(huán)境的組合 第二種說法:閉包就是...

    Zachary 評論0 收藏0

發(fā)表評論

0條評論

BicycleWarrior

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<