在Java中,以字符形式“构建”和使用字符串的最快方法是什么?

时间:2009-10-14 10:38:20

标签: java string variables byte

我有一个间歇性接收数据的Java套接字连接。每次突发接收的数据字节数会有所不同。数据可以或可以不由众所周知的字符(例如CR或LF)终止。每个数据突发的长度是可变的。

我正在尝试从每个数据突发中构建一个字符串。构建一个稍后需要解析的字符串的最快方法(速度,而不是内存)是什么?

我首先使用一个字节数组来存储传入的字节,然后将它们转换为每个突发的字符串,如下所示:

byte[] message = new byte[1024];
...
message[i] = //byte from socket
i++;
...
String messageStr = new String(message);
...
//parse the string here

这个明显的缺点是有些突发可能超过1024.我不想随意创建一个更大的字节数组(如果我的突发更大会怎么样?)。

这样做的最佳方式是什么?我应该创建一个StringBuilder对象并追加它()吗?这样我就不必将StringBuilder转换为String(因为前者有我需要的大部分方法)。

同样,执行速度是我最关心的问题。

TIA。

8 个答案:

答案 0 :(得分:12)

我可能会使用InputStreamReader缠绕BufferedInputStream,而BufferedInputStream/InputStreamReader又包裹套接字。并编写一次处理消息的代码,可能会阻止输入。如果输入是突发性的,我可能会在后台线程上运行并使用并发队列来保存消息。

一次读取缓冲区并尝试将其转换为字符正是{{1}}所做的。并且它在关注编码时这样做,(正如其他人所指出的那样)你的解决方案没有。

我不知道为什么你专注于速度,但你会发现处理来自套接字的数据的时间远远少于通过该套接字传输数据的时间。

答案 1 :(得分:8)

请注意,当您跨网络层传输时,转换速度可能不是瓶颈。如果您认为这很重要,那将值得衡量。

注意(另外)您没有在从字节到字符串(通过字符)的转换中指定字符编码。我会以某种方式强制执行,否则如果/当您的客户端/服务器在不同的环境中运行时,您的客户端/服务器通信可能会损坏。您可以通过JVM运行时args强制执行该操作,但这不是一个特别安全的选项。

鉴于上述情况,您可能需要考虑StringBuilder(int capacity)以适当的大小提前配置它,这样就不必动态重新分配。

答案 2 :(得分:4)

首先,您对从客户端收到的charachter编码做了很多假设。是US-ASCII,ISO-8859-1,UTF-8?

因为在Java字符串中不是字节序列,所以在构建可移植的字符串序列化代码时,您应该明确决定字符编码。出于这个原因,你应该从不使用StringBuilder将字节转换为String。如果你看一下StringBuilder接口,你会发现它甚至没有append( byte )方法,而这并不是因为设计师只是忽略了它。

在你的情况下,你应该绝对使用ByteArrayOutputStream。使用ByteArrayOutputStream的直接实现的唯一缺点是它的toByteArray()方法返回该对象持有的数组的副本。因此,您可以创建自己的ByteArrayOutputStream子类,并提供对受保护buf成员的直接访问。

请注意,如果不使用默认实现,请记住在String构造函数中指定字节数组边界。您的代码应如下所示:

MyByteArrayOutputStream message = new MyByteArrayOutputStream( 1024 );
...
message.write( //byte from socket );
...
String messageStr = new String(message.buf, 0, message.size(), "ISO-8859-1");

ISO-8859-1替换为适合您需要的字符集。

答案 3 :(得分:2)

StringBuilder 是你的朋友。根据需要添加任意数量的字符,然后调用toString()以获取String。

答案 4 :(得分:2)

我会创建一个“小”字符数组并为其添加字符。 当数组已满(或传输结束)时,使用StringBuilder.append(char [] str)方法将数组的内容追加到字符串中。

现在对于阵列的“小”尺寸 - 您需要尝试各种尺寸,并查看哪一个最适合您的生产环境(性能“可能”取决于JVM,操作系统,处理器类型和速度等等) )

编辑:其他人提到ByteArrayOutputStream,我同意这也是另一种选择。

答案 5 :(得分:2)

您可能希望查看ByteArrayOutputStream,具体取决于您是在处理字节而不是字符。

我通常会使用ByteArrayOutputStream来组合消息,然后在消息完成时使用toString / toByteArray来检索它。

编辑:ByteArrayOutputStream可以通过toString调用处理各种字符集编码。

答案 6 :(得分:0)

就个人而言,独立于语言,我会将所有字符发送到内存数据流,一旦我需要字符串,我会将此流中的所有字符读入字符串。 作为替代方案,您可以使用动态数组,在需要添加更多字符时使其更大。更好的是,跟踪实际长度并使用额外的块而不是单个字符来增加阵列。因此,您将从1000个字符数组中的1个字符开始。一旦达到1001,阵列需要调整为2000,然后是3000,4000等......

幸运的是,包括Java在内的多种语言都有一个特殊的内置类,专门用于此。这些是stringbuilder类。他们使用的技术并不重要,但它们的创建是为了提高性能,因此它们应该是您最快的选择。

答案 7 :(得分:0)

查看Text课程。它比StringBuilder更快(对于你执行的操作)并且更具确定性。

注意:包含该类的项目针对RTSJ个虚拟机。它完全可用于标准的SE / EE环境。