閱讀909 返回首頁    go 阿裏雲 go 技術社區[雲棲]


如何使用EnumSet實現基於bit field的enum set?

如果我們在使用有一個枚舉類型時,每次會用到其一項或多項(也就是enum set)時,會怎麼做呢?

在Java沒有引入EnumSet之前,有一種叫int enum pattern(assigning a different power of 2 to each constant)的做法,例如一個字體的style的枚舉會寫成

public static final int STYLE_BOLD = 1 << 0; // 1
public static final int STYLE_ITALIC = 1 << 1; // 2
public static final int STYLE_UNDERLINE = 1 << 2; // 4
public static final int STYLE_STRIKETHROUGH = 1 << 3; // 8

在使用的時候,我們用按位與(|),就可以combine several constants into a set

text.applyStyles(STYLE_BOLD | STYLE_ITALIC);

不過這種做法已經是obsolete了,可以用EnumSet來替代,and it is more concise and flexible,至於效率方麵,完全沒有下降,因為EnumSet內部實現也是用bitwise的。

那麼上麵的例子就可以寫成這樣

// EnumSet - a modern replacement for bit fields
public class Text {
public enum Style { BOLD, ITALIC, UNDERLINE, STRIKETHROUGH }
// Any Set could be passed in, but EnumSet is clearly best
text.applyStyles(EnumSet.of(Style.BOLD, Style.ITALIC));
}


如果我們要把這個EnumSet存儲到數據庫怎麼辦呢?其實這樣的case還是挺多的,我們經常會有flag這樣的column,來表示(is or is not),如果這個flag隻存儲一個(1 或 0 ) 雖然看起來很簡單,但是很浪費而且沒有擴展性,overtime,新需求也許需要個flagB,  那麼你又要加一個新column,flagC,flagD.... frustrated

如果我們把EnumSet直接存到數據庫,上麵的問題就可以解決了,怎麼存呢?看看EnumSet的源碼,就知道其實它是用一個long elements來represent 這個set的, 那麼我們需要寫個工具類能在long和EnumSet之間做轉化, 這樣就可以存取數據庫了。

long轉EnumSet

	/**
	 * Create an enum set by parsing the specified value based on the specified enum type
	 * 
	 * @param originalEnumType the class object of the enum type
	 * @param elements The 2^k bit indicates the presence of the element in this set
	 * @return
	 */
	public static <T extends Enum<T>> EnumSet<T> parseEnumSet(Class<T> originalEnumType, long elements){
		EnumSet<T> resultEnumSet = EnumSet.allOf(originalEnumType);
		for (T element : resultEnumSet){
			if ((elements & (1L << element.ordinal())) == 0)//Check if it is 1 at bit 2^K
				resultEnumSet.remove(element);
		}
		return resultEnumSet;		
	}

EnumSet轉long

	/**
	 * Calculate the elements' long value from a given enum set
	 * 
	 * @param originalEnumSet the given enum set
	 * @return long value of elements in this set
	 */
	public static <T extends Enum<T>> long getElementsValue(EnumSet<T> originalEnumSet){		
		if (originalEnumSet == null)
			return 0;
		
		long elements = 0;
		for (T element : originalEnumSet){
			elements |= (1L << element.ordinal());
		}
		return elements;
	}

使用

		//Calculate the long value before storing in DB
		System.out.println(EnumSetUtil.getElementsValue(EnumSet.of(Style.BOLD, Style.TEST, Style.UNDERLINE)));
		
		//Parse the enum set from long value after fetching from DB
		System.out.println(EnumSetUtil.parseEnumSet(Style.class, 10));



最後更新:2017-04-02 06:52:05

  上一篇:go adb操作命令詳解及大全
  下一篇:go 馬士兵J2SE-第二章-J2SE基礎語法-運算符