Hello,這裡是愛 Coding,愛 Hiphop,愛喝點小酒的 AKA 柏炎。
位運算是java中比較基礎的知識,位運算的計算速度很快,jdk中不少源碼都是使用位運算
(例如ArrayList,HashMap)
。
但是在日常開發的過程中,我們很少會使用位運算。相比較它的計算速度的優點,它可讀性不高的”缺點“似乎對于普通的業務開發來說更加突出。
我們更加樂意直接使用
+,-,*,/
這些直接的運算符。
本文将給大家介紹一種位運算在業務中的應用場景,希望能給大家帶來幫助,如有不對之處,歡迎指正。
本位不對位運算的基礎做展開介紹,如果不熟悉位運算的基礎概念的,請先自行google了解。

一、正常業務打标思路
日常業務開發的過程中,經常會有對業務模型打标 (true/false) 的需求。
例如:
true表示男生,false表示女生
true表示參與活動優惠,false表示無法參與活動優惠
true表示超級管理者,false表示普通使用者
.....
一般情況下針對這種需求,我們通常會使用一個獨立的字段去表示Domain的狀态。随着業務的發展,需要打标的邏輯越來越多。對應到Domain/表結構中辨別的字段也會不斷的上升。
@Data
public class User {
private Long userId;
private String userName;
private boolean canLogin;
private boolean isMale;
private boolean isAdmin;
....
}
二、位運算優化邏輯
為了解決這種非A即B的字段辨別的膨脹問題,我們可以使用位運算去整合這些字段。
例如上文展示的User Domain,我們整合canLogin,isMale,isAdmin為一個字段,認為是一個feature辨別(設定字段為
featureTag
)。
@Data
public class User {
private Long userId;
private String userName;
private int featureTag;
}
我們可以定義一個feature的枚舉定義每一位辨別什麼
public enum UserFeatureEnum{
CAN_LOGIN(0),
IS_MALE(1);
IS_ADMIN(2);
private int bit;
UserFeatureEnum(int bit) {
this.bit = bit;
}
public int getValue() {
return this.bit;
}
}
然後我們可以通過一下的BitUtil來check目前使用者某個特性的狀态
public class BitUtil {
public static int setBit(int options, int bitIndex) {
int val = 1 << bitIndex;
return options | val;
}
public static int unsetBit(int options, int bitIndex) {
int val = 1 << bitIndex;
return options & (~ val);
}
public static boolean isBitSetted(int options, int bitIndex) {
int val = 1 << bitIndex;
return (options & val) == val;
}
public static boolean isBitUnSetted(int options, int bitIndex) {
int val = 1 << bitIndex;
return (options & val) == 0;
}
}
這樣我們如果去校驗user是否為男性就可以這麼操作
boolean isMale = BitUtil.isBitSetted(user.getfeatureTag(),UserFeatureEnum.IS_MALE.getValue());
設定目前使用者為女性
user.setfeatureTag(BitUtil.unsetBit(user.getfeatureTag(),UserFeatureEnum.IS_MALE.getValue()))
設定目前使用者為男性
user.setfeatureTag(BitUtil.setBit(user.getfeatureTag(),UserFeatureEnum.IS_MALE.getValue()))
這樣我們将日益膨脹的标志字段給合并了,資料庫也能夠隻用一個字段就能夠辨別Domain的多個feature。
後續如果需要增加一個feature時,就不需要修改表結構了,隻需要增加一個枚舉值及設定、判斷邏輯就行。
像線上項目,改個表結構還要走一道道的DBA審批流程
三、優劣勢對比
- 相比較正常的業務設計,位運算在空間節省與擴充性上更加突出,但是可讀性就比較差。
- 在DB檢索上,正常設計可以直接将字段作為條件進行過濾,位運算需要在條件上進行一下位運算。
- 在ES檢索上,正常設計可以直接将字段作為條件進行過濾,位運算就不支援了,需要備援出一個字段,如果Domain的存儲結構是ES,并且feature字段有檢索需求,那還是按照正常設計比較好。
- 如果涉及到與用戶端互動的功能,版本A的client支援的功能,在版本B就不能支援了。由于用戶端是安裝在使用者本地的,不可能一直強制使用者做更新。是以這種時候可以在使用一個feature字段,辨別目前用戶端支援的一些特性,服務端去解析傳回結果。請求參數清晰簡單,動态性比較高。
四、最後
文中如有不正确之處,歡迎指正,寫文不易,點個贊吧,麼麼哒~
微信:baiyan_lou
公衆号:柏炎大叔