Java 优化:String vs Char 数组

11

我正在编写一个程序,需要进行大量的字符串操作。我想提高性能,因此想知道是否使用字符数组会有很好的性能提升。有任何建议吗?

我正在编写的程序中涉及了大量的字符串操作。为了提高性能,我在考虑是否可以使用字符数组来代替字符串。您有什么建议吗?请注意,HTML标签应该被保留。

@ThePinkPoo:你的问题缺乏要求:你的字符串应该包含什么?是整个Unicode范围(在这种情况下,使用char[]将证明是一个主要的痛苦,因为Java的char是*完全不足以表示Unicode 3.1及以上引入的新Unicode代码点)?还是只有(子集)ASCII?在后一种情况下,您可以重新实现整个String类,仅由字节支持,并且可以进行大量非常*巧妙的优化。我已经做过了,在Java中处理数百兆字节的ASCII文本文件... - SyntaxT3rr0r
5个回答

7
你正在进行什么样的操作?能否发布一份代码示例?
你可能需要查看StringBuilder,它实现了CharSequence以提高性能。我不确定你是否想自己编写。顺便说一下,StringBuilder不是线程安全的...如果你需要线程安全,请查看StringBuffer

如果您需要线程安全,那么您可能不仅仅需要插入一个StringBuffer。您可能会避免死锁和竞争条件,但结果可能与您预期的不符。 - Hank Gay
谢谢,我会重新实现并发布我的结果。 - ThePinkPoo
@Hank:对于一个非平凡的更新,你需要在其周围包装自己的synchronized(thebuffer){...},但这种情况并不经常发生。实际上,这就是为什么引入了StringBuilder的原因;当不需要时(即几乎所有时间),可以消除持有锁的成本。 - Donal Fellows

2
这是来自 JDK 6.0 中 String 类的完整源代码的摘录:
 public final class String implements  java.io.Serializable,
       Comparable<String>, CharSequence {
       /** The value is used for character storage. */
        private final char value[];

       /** The offset is the first index of the storage that is used. */
       private final int offset;

        /** The count is the number of characters in the String. */
       private final int count;

如您所见,内部值已经存储为字符数组。对于大多数字符串操作,字符数组作为数据结构具有String类的所有限制:Java数组不会增长,即每次(好吧,也许不是每一次)您的字符串需要增长时,您都需要分配一个新数组并复制内容。
如先前建议的那样,对于大多数字符串操作,使用StringBuilder或StringBuffer是有意义的。
实际上,以下代码:
   String a = "a";
   a=a+"b";
   a=a+"c";

编译时将自动转换为使用StringBuilder,可以借助javap轻松检查。

通常情况下,除非您是该领域的世界级专家,否则很少建议花时间尝试改进Java核心类的性能,因为这些代码最初是由世界级专家编写的。


2

字符串已经被实现为字符数组。你计划有什么不同的做法吗?无论如何,由于短暂对象的GC非常快速,我会很惊讶如果你能找到一种通过替换字符数组来提高性能的方法。

Michael Borgwardt关于使用小字符数组以及使用StringBuilder和StringBuffer的建议非常好。但对我而言,最重要的是尽量不要猜测哪些操作是慢的:进行测量、使用分析器,获取一些确凿的事实。因为通常我们对性能的猜测都是错误的。


2
你的应用程序进行了性能分析吗?你知道瓶颈在哪里吗?如果性能不佳,这是第一步。那么,定义可接受的性能指标也是很重要的。
一旦你对某些任务进行了性能分析,你就可以得到所花费时间的百分比。如果你花费大量时间来操作字符串,也许你可以开始缓存其中的一些操作?当只需要执行一次时,你是否重复执行某些操作(然后在需要时再次使用该结果)?当你不需要时,你是否复制了字符串?请记住,java.lang.String是不可变的,因此不能直接更改它。
我发现,在优化/性能调整我工作的系统时,有几次我本能地不知道慢的原因。我曾经看到其他人(包括我自己)花费了数天的时间来优化一些根本没有提高的东西-因为它并不是最初的瓶颈,实际上它的时间花费不到1%。
希望这可以帮助你找到正确的方向。

我已经进行了分析,但结果并不太有用,因为我的代码复杂度相当低。但是我从分析结果中知道字符串方法和代码中的循环是效率问题的主要原因。因此,我打算展开一些循环并使用 StringBuilder。 - ThePinkPoo
@ThePinkPoo:如果字符串操作让程序变得很慢,那么最好的方法就是尝试减少你所做的字符串操作次数。这可以通过缓存或类似的行为来实现。抱歉我之前假设你没有进行性能分析 - 我经常在各种论坛风格的页面上看到这种情况(包括这里),所以想确保你已经这样做了。祝你好运。 - aperkins

1

当你有大量短字符串时,使用char[]可以节省相当多的内存,这也意味着由于较少的缓存未命中而获得更快的速度。

但是对于大型字符串,主要要注意避免由于String的不可变性导致的不必要复制。如果你经常进行连接或替换操作,使用StringBuilder可以产生很大的差异。


Michael,你能详细说明一下用char[]替换字符串的方法吗?相比于String实例,char[]占用的空间略小,但是char[]不会被内部化。对于许多短字符串来说,它们中有些字符串相同且将被内部化(即JVM将保留单个副本)的概率要比少量长字符串高得多。 - Vlad Gudim
@Totophil:这实际上取决于你使用的字符串类型以及你对它们进行的操作;如果你使用可变表示,那么字符串驻留就不再相关了。 - Michael Borgwardt
迈克尔,同意,这确实取决于具体的情况。我能想到的唯一情况是当软件需要进行大量字符串操作时。但是这种方法对于解决由连接、搜索和比较带来的字符串开销是没有帮助的。 - Vlad Gudim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接