2015-03-25 74 views
4

我看到了四种替代方法,用于将char转换为Java中的StirngJava中最快的字符串转换

v = Something.lookup(new String((char)binaryData[idx])); // SORRY! Wrong. 
v = Something.lookup("" + (char)binaryData[idx]); 
v = Something.lookup(String.valueOf((char)binaryData[idx])); 
v = Something.lookup(Character.toString((char)binaryData[idx]))); 

我认为第一个是最慢的。第二个非常方便。我推测第三个可能会返回以前创建的String实例,但我不确定,API文档没有这样说。选项四也是如此。实例的重用将非常幸运,因为然后基于散列的查找可以利用String中的hashCode()高速缓存。 (哪些功能在API文档中也没有描述,但很多人告诉我)。

我来自C++,我觉得缺乏复杂性信息令人不安。 :-)我的猜测是否正确?我们是否有任何形式的官方文档,在其中声明了性能保证和缓存机制?

+5

“第二个非常方便” - 不是如果你想读代码,国际海事组织。该代码使用字符串连接和一个空字符串,这两者都不是你真正想实现的一部分。 'String.valueOf'一路,海事组织 - 并且你*测量了*这些中的任何一个?你知道吗,这实际上是代码中的瓶颈?你有没有尝试确定'String.valueof' *是否缓存这些值? (很容易分辨......)假设'binaryData'是一个'byte []',你可以很容易地用256个字符串构建你自己的'String []',以绝对保证缓存...... – 2015-03-25 10:28:40

+0

3和4同样的..暗含地调用3 :)。我们还没有一个String构造函数,它只接受一个字符(case-1?) – TheLostMind 2015-03-25 10:30:58

+0

版本2将由编译器翻译为:创建一个StringBuilder对象,然后将char添加到该对象,最后toString()将被调用。所以这相当昂贵。对于v3或v4的成本...你可以看看源代码,看看会发生什么。 – GhostCat 2015-03-25 10:32:12

回答

6

首先,Java规范不说有关性能什么关于这四种方法,因此结果可能会有所不同,具体取决于您使用的JRE版本和供应商。

如果您使用Oracle的JRE,您可以轻松地自行检查源代码!在Java 8中,如下所示:

鉴于一些价值char c

  • new String(c)不能编译。没有这样的构造函数。
  • "" + c看起来丑陋,麻烦和棘手。它在内部创建一个新的空字段StringBuilder并将字符附加到它。然后它会从StringBuilder中创建一个新的String实例。
  • Character.toString(c)代表String.valueOf(c)
  • String.valueOf(c)创建一个新的String实例。

那么,哪一个使用?

最易读!

这就是我的观点String.valueOf(c)Character.toString(c)

+0

你是对的! ;)谢谢,我已经解决了我的答案。 – isnot2bad 2015-03-25 11:06:07

+1

你很想讨论字符串实习生,以便让答案更完整。我敢打赌,所有低于256的acii字符都是在启动时被实施(缓存)的。 – 2015-03-25 11:36:14

+1

由于在HotSpot JVM中进行了特殊的优化,''“+ c'会稍微快一点,但为了便于阅读,我也更喜欢'Character.toString'或'String.valueOf'。 – apangin 2015-03-25 11:40:09

2

第二个肯定是(在理论上)慢,因为它被翻译成

v = Something.lookup(new StringBuilder().append("").append((char)binaryData[idx]).toString()); 

StringBuilder S使用初始化的char[]持有16个值被实现。因此,StringBuilder选项会初始化一个大小为16的char[],仅用于将设置的单元格(此例中仅为第一个)复制到结果字符串中。

String.valueOf(其等同于Character.toString)使用尺寸1的char[],然后直接设置String的背衬char[],从而避免了复制的需要。

第一种方法不会编译(至少是没有的Java 7),因为没有String构造函数接受单个字符作为输入:http://docs.oracle.com/javase/7/docs/api/java/lang/String.html

+2

“*第二个肯定比较慢*”==>你会感到惊讶...... – assylias 2015-03-25 10:50:56

+0

我的意思是说第二个选项可以做更多的工作,理论上应该更慢。 – EvenLisle 2015-03-25 10:54:00

+0

*理论上理论和实践之间没有区别,实际上存在。*“:-)它发生在三个选项与Hotspot JVM 8之间没有明显的区别。 – assylias 2015-03-25 11:15:30

1

第一个解决方案不能编译。 第二种解决方案在内部创建一个字符串,调用类似于Character.valueOf(char)的代码。 解决方案三比第四更好,因为内部实现Character.toString(char ch)String.valueOf

public static String toString(char c) { 
    return String.valueOf(c); 
} 

内部执行第三String.valueOf(char ch)的呼叫

public static String valueOf(char c) { 
    char data[] = {c}; 
    return new String(0, 1, data); 
} 
1

我是从C++来了,我觉得这缺乏复杂的信息令人不安。 :-)我的猜测是否正确?我们是否有任何形式的官方文档,在其中声明了性能保证和缓存机制?

回答这个问题的部分:一般来说没有。您会发现内置集合的渐近性能以及其他几个方面的信息,但总的来说,这些问题留给VM实施者自行决定。您当然可以始终查看源代码,但请记住,有些事情会影响您无法直接控制的性能:JIT编译和垃圾回收是两个最大的问题。

你应该为此感到不安吗?我不这么认为,Java运行的前提是低级性能很少是应用程序开发人员需要关注的问题。这是一种折衷,你可以争论这是否是一个好的折衷,但它就是这样。

但是到了开发真正高性能系统的时候,您将一路领略所有必要的信息。

+0

如果可以的话,我会添加更多的提示,因为这是处理问题第二部分的唯一答案。 – Notinlist 2015-03-25 12:44:35

+1

@Notinlist只是一个小小的附录:你的问题(或者说,你得到的答案)表明了这种在实践中很少实施保证的政策。 ''“”+ c“开始是一种”坏习惯“,这是非常令人不悦的,而且确实很慢。但是从Java 8开始,这种模式显然被JIT编译器所认可,它可以像所有其他解决方案一样快速地生成代码。如果对实施细节有更多保证,也许这是不可能的。 – biziclop 2015-03-25 13:10:26