前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >不谈源码,聊聊位运算的实际应用

不谈源码,聊聊位运算的实际应用

作者头像
柏炎
发布2022-08-23 14:50:10
2740
发布2022-08-23 14:50:10
举报

Hello,这里是爱 Coding,爱 Hiphop,爱喝点小酒的 AKA 柏炎。

位运算是java中比较基础的知识,位运算的计算速度很快,jdk中不少源码都是使用位运算(例如ArrayList,HashMap)

但是在日常开发的过程中,我们很少会使用位运算。相比较它的计算速度的优点,它可读性不高的”缺点“似乎对于普通的业务开发来说更加突出。

我们更加乐意直接使用 +,-,*,/这些直接的运算符。

本文将给大家介绍一种位运算在业务中的应用场景,希望能给大家带来帮助,如有不对之处,欢迎指正。

本位不对位运算的基础做展开介绍,如果不熟悉位运算的基础概念的,请先自行google了解。

一、常规业务打标思路

日常业务开发的过程中,经常会有对业务模型打标 (true/false) 的需求。

例如: true表示男生,false表示女生 true表示参与活动优惠,false表示无法参与活动优惠 true表示超级管理员,false表示普通用户 .....

一般情况下针对这种需求,我们通常会使用一个独立的字段去表示Domain的状态。随着业务的发展,需要打标的逻辑越来越多。对应到Domain/表结构中标识的字段也会不断的上升。

代码语言:javascript
复制
@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)。

代码语言:javascript
复制
@Data
public class User {
    private Long userId;
    private String userName;
    private int featureTag;
}

我们可以定义一个feature的枚举定义每一位标识什么

代码语言:javascript
复制
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当前用户某个特性的状态

代码语言:javascript
复制
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 &amp; (~ val);
    }
​
    public static boolean isBitSetted(int options, int bitIndex) {
        int val = 1 << bitIndex;
        return (options &amp; val) == val;
    }
​
    public static boolean isBitUnSetted(int options, int bitIndex) {
        int val = 1 << bitIndex;
        return (options &amp; val) == 0;
    }
}

这样我们如果去校验user是否为男性就可以这么操作

代码语言:javascript
复制
boolean isMale = BitUtil.isBitSetted(user.getfeatureTag(),UserFeatureEnum.IS_MALE.getValue());

设置当前用户为女性

代码语言:javascript
复制
user.setfeatureTag(BitUtil.unsetBit(user.getfeatureTag(),UserFeatureEnum.IS_MALE.getValue()))

设置当前用户为男性

代码语言:javascript
复制
user.setfeatureTag(BitUtil.setBit(user.getfeatureTag(),UserFeatureEnum.IS_MALE.getValue()))

这样我们将日益膨胀的标志字段给合并了,数据库也能够只用一个字段就能够标识Domain的多个feature。

后续如果需要增加一个feature时,就不需要修改表结构了,只需要增加一个枚举值及设置、判断逻辑就行。

像线上项目,改个表结构还要走一道道的DBA审批流程

三、优劣势对比

  • 相比较常规的业务设计,位运算在空间节省与扩展性上更加突出,但是可读性就比较差。
  • 在DB检索上,常规设计可以直接将字段作为条件进行过滤,位运算需要在条件上进行一下位运算。
  • 在ES检索上,常规设计可以直接将字段作为条件进行过滤,位运算就不支持了,需要冗余出一个字段,如果Domain的存储结构是ES,并且feature字段有检索需求,那还是按照常规设计比较好。
  • 如果涉及到与客户端交互的功能,版本A的client支持的功能,在版本B就不能支持了。由于客户端是安装在用户本地的,不可能一直强制用户做升级。因此这种时候可以在使用一个feature字段,标识当前客户端支持的一些特性,服务端去解析返回结果。请求参数清晰简单,动态性比较高。
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-07-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、常规业务打标思路
    • 二、位运算优化逻辑
    • 三、优劣势对比
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档