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

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

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

然而,对于大数据处理来说,这个可不是小事,从字符串替换为数字类型,可以极大地节省内存、磁盘存储以及网络带宽,减少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();
}

文章转载自 开源中国社区[https://www.oschina.net]

时间: 2024-07-31 23:36:13

如何选择使用字符串还是数字呢?的相关文章

Javascript中如何将字符串转为数字

本文介绍Javascript中数字转字符串及字符串转数字的方法 Javascript中最简洁的数字转字符串方法是: var num = 123; var string = num + ""; 也就是在数字后面加上一个空字符.那么最简洁字符串转数字方法呢? 字符串只能进行加法(拼接) 字符串进行加法(拼接)是很常见的,但是字符串进行减法.乘法.除法呢? 这似乎很难定义,实际上字符串没有减法.乘法.除法操作. 但Javascript是动态语言,如果你拿两个字符串进行这三种操作的时候,他会尝

Symbian中把字符串变成数字的方法

我们知道C语言中又很方便的函数,很多种方法可以把字符串变成数字, 比如 char * p = "100" ; int a; a = atoi(p) ; // 此时a的值就是100了. 或者用这种办法也可以,就是慢点: sscanf(p, "%d", &a) ; 这样也可以达到同样的效果. 但是symbian开发环境中遇到这种情况,我们该怎么做呢? 我们可以考虑采用TLex类,来实现同样的功能. TBufC buffer = _L("124"

C#获得字符串中数字或字母的长度

在程序中获得字符串中数字或字母的长度时,可以先使用CharEnumerator对象的MoveNext方法循环访问字符串中的每个字符,并将字符用System.Text.Encoding类中ASCII编码方式的GetBytes方法进行编码,然后判断经过编码之后的字符的ASCII码值是否介于指定的值之间,如果是,则将其添加到一个数组中,最后获得该数组的项数即可.获得字符串中数字或字母长度的关键代码如下: ArrayList itemList = new ArrayList();CharEnumerat

Groovy Tip 37 字符串和数字之间的转化

字符串和数字之间的转化是我们在项目中必然要碰到的问题,因为我们从用户界面取得的变量的值肯 定是字符串. 所以,我们在项目中经常要做的事情就是:第一,需要对用户的输入进行校验,以判断用户的输入是 否是一个数字:第二,如果是的话,我们则需要进一步把它转化为数字,以方便我们进行计算. 在Java语言中,我们要判断一个字符串是否是数字,基本上有两种方法,第一是直接进行转化,如果 有Exception抛出,则该字符串非我们所需要的数字.如下面就是一段判定一个字符串是否为整型数字的 代码: public s

php结合正则获取字符串中数字

  这篇文章主要给大家汇总介绍了php结合正则获取字符串中数字的几种方法,十分的简单实用,有需要的小伙伴可以参考下. php结合正则获取字符串中数字 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <?php $patterns = "/d+/"; //第一种 //$patterns = "/d/"; //第二种 $st

c#中判断字符串是不是数字或字母的方法

这篇文章介绍了C#判断字符串是否数字或字母的实例,有需要的朋友可以参考一下   一.判断字母 复制代码 代码如下: string str = Console.ReadLine(); if (char.isLetter(str)) { } else if (char.IsDigit(str)) { } if(ch>='a'&&ch<='z') 小写字母 if(ch>='A'&&ch<='Z') 大写字母 数字也一样. 判断汉字一般是输入 >255

C语言中字符串和数字的相互转换实现代码

以下是对C语言中字符串和数字的相互转换实现代码进行了分析介绍,需要的朋友可以参考下   1.数字转换为字符串sprintf 跟printf 在用法上几乎一样,只是打印的目的地不同而已,前者打印到字符串中,后者则直接在命令行上输出. sprintf 是个变参函数,定义如下: int sprintf( char *buffer, const char *format [, argument] ... ); 除了前两个参数类型固定外,后面可以接任意多个参数. printf 和sprintf 都使用格式

将字符串或数字倒序输出

将字符串或数字倒序输出,以使这些呈散列分布,用于作为hbase rowkey的一部分,避免region的读写热点 public class StringUtil { public static void main(String[] args) { long start = System.currentTimeMillis(); for (int i = 0; i < 10; i++) { System.out.println(reverseLong(78945612399l)); } Syste

c++-C++字符串和数字混合输入问题

问题描述 C++字符串和数字混合输入问题 #include <iostream> using namespace std; int main() { struct Car { char maked[20]; int year; }; unsigned int i; cout << "How many cars do you wish to catalog ? "; cin >> i; Car *car = new Car[i]; for (int k