`

如何选择使用字符串还是数字呢?

    博客分类:
  • java
阅读更多

 

在我多年的开发经验中,经常发现的一个情况就是,很多项目的对象字段或者是数据库字段本来是数字类型的,却被定义成字符串类型,这无关痛痒吗?

对于小项目来说,可能没什么影响,反正只要业务逻辑正确即可,性能没什么问题,因为数据也不多,用户也不多。

然而,对于大数据处理来说,这个可不是小事,从字符串替换为数字类型,可以极大地节省内存、磁盘存储以及网络带宽,减少IO的代价,而且很多数据结构和算法使用数字类型比字符串要更快。

我们来看一个例子,假设你有很多的日志需要处理,而每条日志都有一个唯一的标识,标识类似这样的格式:

F5051582611729507844
3832154813577306424
F1624235934976711017
3810376634214027595
F6884923813121317381
7278044081826528150

 

看到这些标识,你怎么想?我的第一反应应该是数字,可是怎么有个F呢?我想可以把它当做16进制。后来发现可以把F当做负号,这就是一个64位的长整型。

那么如果你把这些标识当成字符串,会有什么不同呢?

当然有,如果你每秒要处理这样的日志百万或者千万条,每条处理结果可能会包含百万或者千万个这样的标识元素构成的集合,这个不同就会体现的非常明显。

下面,我们来分析一下标识3832154813577306424的存储占用情况:

1、内存占用

当做字符串:我们知道,JAVA中字符串是由字符构成的,一个字符是由2个字节构成的(这是JAVA的悲剧了),上述标识有19个字符,所以,占用的内存大小为:19*2+4=42(字节),+4是因为字符串使用一个整型保存字符串的哈希值。

当做数字:如当做长整型,则占用的内存大小为8字节。

这里有5倍以上的差距了吧。

2、序列化字节大小

当我们需要通过网络传输这些标识或者需要把这些标识存储到磁盘中的时候,我们就需要把这些标识转换为字节数组,如何转换为字节数组呢?我们可以使用多种编码方式。

当做字符串:我们知道,JAVA中字符串转换为字节数组可以使用多种编码方式,我们看看常见的编码方式对如上字符串编码之后的字节数:

String abc = "3832154813577306424";

System.out.println("3832154813577306424 length:"+abc.length());
System.out.println(Charset.defaultCharset().name()+":"+abc.getBytes().length);
System.out.println("unicode:"+abc.getBytes("unicode").length);
System.out.println("gbk:"+abc.getBytes("gbk").length);
System.out.println("gb2312:"+abc.getBytes("gb2312").length);
System.out.println("ISO-8859-1:"+abc.getBytes("ISO-8859-1").length);

 

输出如下:

3832154813577306424 length:19
UTF-8:19
unicode:40
gbk:19
gb2312:19
ISO-8859-1:19

 

当做数字:如当做长整型,则占用的内存大小为8字节。

这里有2倍以上的差距了吧。

那么我们如何在长整型和字节数组之间转换呢?

String abc = "3832154813577306424";

System.out.println("3832154813577306424 length:"+abc.length());
System.out.println("long:"+ByteUtils.longToBytes(Long.parseLong(abc)).length);
byte[] bytes = ByteUtils.longToBytes(Long.parseLong(abc));
System.out.println("string:"+ByteUtils.bytesToLong(bytes));

 

输出如下:

3832154813577306424 length:19
long:8
string:3832154813577306424

 

public static byte[] longToBytes(long x) {
    ByteBuffer longBuffer = ByteBuffer.allocate(Long.BYTES);
    longBuffer.putLong(0, x);
    return longBuffer.array();
}
public static long bytesToLong(byte[] bytes) {
    return bytesToLong(bytes, 0, bytes.length);
}
public static long bytesToLong(byte[] bytes, int offset, int length) {
    ByteBuffer longBuffer = ByteBuffer.allocate(Long.BYTES);
    longBuffer.put(bytes, offset, length);
    longBuffer.flip();//need flip
    return longBuffer.getLong();
}

 

 

 

 

 

 

 

5
2
分享到:
评论
6 楼 yangshangchuan 2015-10-01  
liujun422134235 写道
楼主,请问 ByteBuffer longBuffer = ByteBuffer.allocate(Long.BYTES);  这句中的Long.BYTES这个你是从哪来的?是原生java.lang.Long中的吗?那个这长度你固定了吗?如果在再长这个长度该如何确定?

liujun422134235 写道
楼主,请问 ByteBuffer longBuffer = ByteBuffer.allocate(Long.BYTES);  这句中的Long.BYTES这个你是从哪来的?是原生java.lang.Long中的吗?那个这长度你固定了吗?如果在再长这个长度该如何确定?



java.lang.Long中:

public static final int BYTES = SIZE / Byte.SIZE;
public static final int SIZE = 64;

java.lang.Byte中:

public static final int SIZE = 8;
5 楼 liujun422134235 2015-09-30  
楼主,请问 ByteBuffer longBuffer = ByteBuffer.allocate(Long.BYTES);  这句中的Long.BYTES这个你是从哪来的?是原生java.lang.Long中的吗?那个这长度你固定了吗?如果在再长这个长度该如何确定?
4 楼 white_crucifix 2015-09-01  
其实我相信绝大多数的系统还达不到因这个原因而引起性能瓶颈的地步,但是什么样的数据用什么样的类型当然是极好的,只是实践当中,确实从项目到人,很多地方都崇尚全部用字符串,甚至是时间类型的字段也用string。
3 楼 yixiandave 2015-09-01  
hanjiangit 写道
qqt31 写道
用String表达数字的原因是高精度计算时用BigDecimal

不是有double嘛

高精度计算不能用double,虽然double精度比float高但是依然会出错。之前碰到过用double计算结果后面多出来个莫名其妙的尾巴
2 楼 hanjiangit 2015-09-01  
qqt31 写道
用String表达数字的原因是高精度计算时用BigDecimal

不是有double嘛
1 楼 qqt31 2015-09-01  
用String表达数字的原因是高精度计算时用BigDecimal
0 楼 eggliwen 2015-08-31  
  

相关推荐

Global site tag (gtag.js) - Google Analytics