Loading

Java生成64bit、32bit的ID

主要就是数字的位运算,这里以32位为例。

完整代码

package net.add1s.slf4jlogback.bits;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author add1s.net
 */
public class BitsEncode {

    private static final Logger LOG = LoggerFactory.getLogger(BitsEncode.class);

    /**
     * 三个值依次占位10bit、10bit、12bit,总计32bit
     */
    private static final int A_BITS = 10;
    private static final int B_BITS = 10;
    private static final int C_BITS = 12;

    /**
     * A左移10+12
     * B左移12
     * C无需位移
     */
    private static final long A_SHIFT = B_BITS + C_BITS;
    private static final long B_SHIFT = C_BITS;

    /**
     * 三个值的最大值
     */
    private static final long A_MAX = ~(-1 << A_BITS);
    private static final long B_MAX = ~(-1 << B_BITS);
    private static final long C_MAX = ~(-1 << C_BITS);

    /**
     * 最小值
     */
    private static final int MIN = 0;

    /**
     * 验证参数合法性
     * 
     * @param a 值a
     * @param b 值b
     * @param c 值c
     * @return boolean
     */
    private static boolean check(long a, long b, long c) {
        boolean flag = Boolean.TRUE;
        if (a < MIN || a > A_MAX) {
            LOG.error("\"a\" cannot less than 0 or greater than {}", A_MAX);
            flag = Boolean.FALSE;
        }
        if (b < MIN || b > B_MAX) {
            LOG.error("\"b\" cannot less than 0 or greater than {}", B_MAX);
            flag = Boolean.FALSE;
        }
        if (c < MIN || c > C_MAX) {
            LOG.error("\"c\" cannot less than 0 or greater than {}", C_MAX);
            flag = Boolean.FALSE;
        }
        return flag;
    }

    /**
     * 编码
     * 
     * @param a 值a
     * @param b 值b
     * @param c 值c
     * @return (long) 编码后的值
     */
    public static long encode(long a, long b, long c) {
        if (!check(a, b, c)) {
            LOG.error("编码失败");
            return -1;
        }
        return (a << A_SHIFT) |
                (b << B_SHIFT) |
                c;
    }

    /**
     * 解码
     * 
     * @param code 已编码值
     * @return (long[]) 解码后的long型数组,只是个返回对象,也可使用其他容器对象或自定义对象代替,如List或Map
     */
    public static long[] decode(long code) {
        return new long[] {
            (code >> A_SHIFT) & A_MAX,
            (code >> B_SHIFT) & B_MAX,
            code & C_MAX
        };
    }
}

测试

package net.add1s.slf4jlogback.bits;

import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class BitsEncodeTest {

    private final Logger LOG = LoggerFactory.getLogger(BitsEncodeTest.class);

    @Test
    void encode() {
        // 10bit最大值是1023,所以应该打印error日志提示“b”转换错误
        LOG.info("BitsEncode.encode(1023, 1024, 4095) 编码结果: {}", BitsEncode.encode(1023, 1024, 4095));
    }

    @Test
    void decode() {
        LOG.info("解码:{}", BitsEncode.decode(BitsEncode.encode(111, 222, 333)));
    }
}

上述测试encode()日志打印

2020-05-30 19:28:23.352 ERROR 7532 --- [           main] net.add1s.slf4jlogback.bits.BitsEncode   : "b" cannot less than 0 or greater than 1023
2020-05-30 19:28:23.352 ERROR 7532 --- [           main] net.add1s.slf4jlogback.bits.BitsEncode   : 编码失败
2020-05-30 19:28:23.352  INFO 7532 --- [           main] n.a.slf4jlogback.bits.BitsEncodeTest     : BitsEncode.encode(1023, 1024, 4095) 编码结果: -1

更改值为1023后再次运行

2020-05-30 19:30:10.934  INFO 924 --- [           main] n.a.slf4jlogback.bits.BitsEncodeTest     : BitsEncode.encode(1023, 1023, 4095) 编码结果: 4294967295

运行测试decode()

2020-05-30 19:31:55.298  INFO 15448 --- [           main] n.a.slf4jlogback.bits.BitsEncodeTest     : 解码:[111, 222, 333]

若在编码方法encode(long a, long b, long c)里不进行check(long a, long b, long c)验证,那么解码的时候将会得到错误结果

注释掉验证代码

// if (!check(a, b, c)) {
//     LOG.error("编码失败");
//     return -1;
// }

再次DEBUG测试

@Test
void encode() {
    // 本次将b的值设置为6666,已经超出10bit最大值
    LOG.info("BitsEncode.encode(1023, 6666, 4095) 编码结果: {}", BitsEncode.encode(1023, 6666, 4095));
}

日志打印

2020-05-30 19:37:59.754  INFO 12132 --- [           main] n.a.slf4jlogback.bits.BitsEncodeTest     : BitsEncode.encode(1023, 6666, 4095) 编码结果: 4292915199

结果为4292915199,以该结果运行解码测试

@Test
void decode() {
    LOG.info("解码:{}", BitsEncode.decode(4292915199L));
}

打印日志

2020-05-30 19:40:01.761  INFO 3948 --- [           main] n.a.slf4jlogback.bits.BitsEncodeTest     : 解码:[1023, 522, 4095]

可以发现“b”的值并不是最初编码的值

DONE.

posted @ 2020-05-30 19:42  mahoshojo  阅读(573)  评论(0编辑  收藏  举报