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.