热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

串接字符('x')与单个字符字符串文字("x")-Concatenatecharliteral('x')vssinglecharstringliteral(“x”)

WhenIhaveaStringthatIneedtoconcatenateasinglechartoitsend,shouldIprefers.+

When I have a String that I need to concatenate a single char to its end, should I prefer s = .... + ']' over s = .... + "]" for any performance reason?

当我有一个字符串,我需要将一个字符结束,我应该喜欢s = ....+ ']' / s = ....“为了任何性能原因?”

I know array string joining and of String builders, and I am NOT asking for suggestions on how to concatenate strings in general.

我知道数组字符串连接和字符串构建器,我并没有要求关于如何连接字符串的建议。

I also know some of would have the urge to explain to me about premature optimizations and that in general I should not bother with such minor stuff, please don't...

我也知道有些人会有向我解释过早优化的冲动,一般来说,我不应该为这些小事烦心,请不要……

I am asking because from a coding style preference I would prefer to use the later, but it feels to me that the first one should perform marginally better because knowing that what is being appended is just a single char there is no need for any internal looping going over this single char as there might be when copying a single character string.

我问,因为我宁愿从编码风格偏好使用之后,但在我的感觉,第一个应该执行略微更好,因为只知道什么是被附加一个字符不需要任何内部循环复习这一个char时可能会有复制一个字符的字符串。

Update

更新

As @Scheintod wrote this is indeed a theoretical Q and has to do more with my desire to better understand how java works and less with any real life "lets save another microsecond" scenario... maybe I should have said that more clearly.

正如@Scheintod所写的,这确实是一个理论问题,我需要做更多的事情,我希望更好地理解java的工作原理,更少地使用任何真实的生命“让我们保存另一微秒”的场景……也许我应该说得更清楚些。

I like understanding the way things work "behind the scenes" And I find that it can sometime help me create better code...

我喜欢理解事物在幕后工作的方式,我发现它有时可以帮助我创建更好的代码……

The truth - I was not thinking about compiler optimizations at all...

事实上,我根本没有考虑编译器的优化……

I would not have expected the JIT to use StringBuilders instead of Strings for me... Because I (possibly wrongly) think of String builders as being "heavier" then Strings on one hand but faster at building and modifying the strings on the other hand. So I would assume that in some cases using StringBuilders would be even less efficient then using stings... (if that was not the case then the entire String class should have had its implementation changed to be such as that of a StringBuilder and use some internal representation for actual immutable strings... - or is that what the JIT is sort of doing? - assuming that for the general case it would probably be better not to let the developer choose... )

我不希望JIT使用stringbuilder而不是字符串给我…因为我(可能是错误的)认为字符串构建器是“较重”的字符串,但是在构建和修改字符串时速度更快。所以我认为在某些情况下,使用StringBuilders会更低效,然后使用stings…(如果不是这样的话,那么整个String类就应该让它的实现变成像StringBuilder那样的实现,并对实际的不可变字符串使用一些内部表示……-或者说,JIT就是这样做的吗?-假设在一般情况下,最好不要让开发人员选择……

If it Does change my code to such a degree then maybe My Q should have been at that level asking if its is appropriate for the JIT to do something like this and would it be better if it used.

如果它确实改变了我的代码到这样的程度,那么我的Q应该在这个层次上问它是否适合JIT做这样的事情,如果它使用它会更好。

maybe I should start looking at compiled byte code... [I will need to learn how to do that in java ...]

也许我应该开始查看编译后的字节码…我需要学习如何在java中做到这一点……

As a side note and example of why I would even consider looking at bytecode - have a look at a quite old blog post of mine about Optimizing Actionscript 2.0 - a bytecode perspective - Part I it shows that knowing what your code compiles into indeed can help you write better code.

边注,甚至为什么我会考虑到字节码的例子,看一看我的一个很旧的博客优化Actionscript 2.0 -字节码的角度来说,我确实表明,知道你的代码编译成可以帮助你写出更好的代码。

3 个解决方案

#1


18  

Besides profiling this we have another possibility to get some insights. I want to focus on the possible speed differences and not on the things which remove them again.

除了剖析这一点,我们还有另一种可能获得一些见解。我想把注意力集中在可能的速度差异上,而不是把它们移走。

So lets start with this Test class:

那么让我们从这个测试类开始:

public class Test {

    // Do not optimize this
    public static volatile String A = "A String";

    public static void main( String [] args ) throws Exception {

        String a1 = A + "B";

        String a2 = A + 'B';

        a1.equals( a2 );

    }

}

I compiled this with javac Test.java (using javac -v: javac 1.7.0_55)

我用javac测试编译了这个。java(使用javac -v: javac 1.7.0_55)

Using javap -c Test.class we get:

使用javap - c测试。类我们得到:

Compiled from "Test.java"
public class Test {
  public static volatile java.lang.String A;

  public Test();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."":()V
       4: return

  public static void main(java.lang.String[]) throws java.lang.Exception;
    Code:
       0: new           #2                  // class java/lang/StringBuilder
       3: dup
       4: invokespecial #3                  // Method java/lang/StringBuilder."":()V
       7: getstatic     #4                  // Field A:Ljava/lang/String;
      10: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      13: ldc           #6                  // String B
      15: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      18: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      21: astore_1
      22: new           #2                  // class java/lang/StringBuilder
      25: dup
      26: invokespecial #3                  // Method java/lang/StringBuilder."":()V
      29: getstatic     #4                  // Field A:Ljava/lang/String;
      32: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      35: bipush        66
      37: invokevirtual #8                  // Method java/lang/StringBuilder.append:(C)Ljava/lang/StringBuilder;
      40: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      43: astore_2
      44: aload_1
      45: aload_2
      46: invokevirtual #9                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      49: pop
      50: return

  static {};
    Code:
       0: ldc           #10                 // String A String
       2: putstatic     #4                  // Field A:Ljava/lang/String;
       5: return
}

We can see, that there are two StringBuilders involved (Lines 4, 22 ). So the first thing we discover is, that using + to concat Strings is effectively the same as using StringBuilder.

我们可以看到,有两个stringbuilder(第4行,第22行)。我们发现的第一件事是,使用+ to concat字符串实际上和使用StringBuilder是一样的。

The second thing we can see here is that the StringBuilders both are called twice. First for appending the volatile variable (Lines 10, 32) and the second time for appending the constant part (Lines 15, 37)

我们可以看到的第二件事是,StringBuilders都被调用了两次。第一个用于附加volatile变量(第10行、第32行)和第二次附加常量部分(第15、37行)

In case of A + "B" append is called with a Ljava/lang/String (a String) argument while in case of A + 'B' it is called with an C (a char) argument.

如果使用Ljava/lang/String (String)参数来调用A +“B”,则使用C (char)参数来调用。

So the compile does not convert String to char but leaves it as it is*.

因此,编译器不会将字符串转换为char,而是将其保留为*。

Now looking in AbstractStringBuilder which contains the methods used we have:

现在看看AbstractStringBuilder,它包含了我们使用的方法:

public AbstractStringBuilder append(char c) {
    ensureCapacityInternal(count + 1);
    value[count++] = c;
    return this;
}

and

public AbstractStringBuilder append(String str) {
    if (str == null) str = "null";
    int len = str.length();
    ensureCapacityInternal(count + len);
    str.getChars(0, len, value, count);
    count += len;
    return this;
}

as the methods actually called.

实际上是调用方法。

The most expensive operations here is certainly ensureCapacity but only in case the limit is reached (it does an array copy of the old StringBuffers char[] into a new one). So this is true for both and makes no real difference.

这里最昂贵的操作当然是ensurecacity,但只有在达到极限时(它会将旧的stringbuffer char[]的数组复制到一个新的)中。所以这两种情况都是成立的,没有什么区别。

As one can see there are numerous other operations which are done but the real distinction is between value[count++] = c; and str.getChars(0, len, value, count);

我们可以看到还有许多其他的操作,但真正的区别在于价值[count++] = c;和str.getChars(0, len, value, count);

If we look in to getChars we see, that it all boils down to one System.arrayCopy which is used here to copy the String to the Buffer's array plus some checks and additional method calls vs. one single array access.

如果我们看一下getChars,我们会看到,所有这些都归结为一个系统。这里使用的arrayCopy将字符串复制到缓冲区的数组中,加上一些检查和额外的方法调用vs.一个数组访问。

So I would say in theory using A + "B" is much slower than using A + 'B'.

所以在理论上,A + B比A + B要慢得多。

I think in real execution it is slower, too. But to determine this we need to benchmark.

我认为在实际执行过程中,它也比较慢。但要确定这一点,我们需要进行基准测试。

EDIT: Of cause this is all before the JIT does it's magic. See Stephen C's answer for that.

编辑:因为这都是在JIT之前的魔法。参见Stephen C的答案。

EDIT2: I've been looking at the bytecode which eclipse's compiler generated and it's nearly identical. So at least these two compilers don't differ in the outcome.

EDIT2:我一直在关注eclipse编译器生成的字节码,它几乎是相同的。所以至少这两个编译器在结果上没有区别。

EDIT2: AND NOW THE FUN PART

现在是有趣的部分。

The Benchmarks. This result is generated by running Loops 0..100M for a+'B' and a+"B" few times after a warmup:

基准。此结果由运行循环0生成。a+'B'和a+"B"在热身后几次:

a+"B": 5096 ms
a+'B': 4569 ms
a+'B': 4384 ms
a+"B": 5502 ms
a+"B": 5395 ms
a+'B': 4833 ms
a+'B': 4601 ms
a+"B": 5090 ms
a+"B": 4766 ms
a+'B': 4362 ms
a+'B': 4249 ms
a+"B": 5142 ms
a+"B": 5022 ms
a+'B': 4643 ms
a+'B': 5222 ms
a+"B": 5322 ms

averageing to:

平均:

a+'B': 4608ms
a+"B": 5167ms

So even in the real benchmark world of syntetic knowlege (hehe) a+'B' is about 10% faster than a+"B"...

因此,即使是在真正的标准知识世界中,a+ B的速度也比a+ B快10%……

... at least (disclaimer) on my system with my compiler and my cpu and it's really no difference / not noticeable in real world programms. Except of cause you have a piece of code you run realy often and all your application perfomance depends on that. But then you would probably do things different in the first place.

…至少(免责声明)在我的系统上有我的编译器和我的cpu,在现实世界的程序中没有明显的区别。除了因为你有一段代码你经常运行,你的所有应用程序性能都取决于这个。但首先你可能会做一些不同的事情。

EDIT4:

标:

Thinking about it. This is the loop used to benchmark:

思考这个问题。这是用于基准测试的循环:

    start = System.currentTimeMillis();
    for( int i=0; i

so we're really not only benchmarking the one thing we care about but although java loop performance, object creation perfomance and assignment to variables performance. So the real speed difference may be even a little bigger.

因此,我们不仅要对我们关心的一件事进行基准测试,而且还要考虑java循环性能、对象创建性能和变量性能的分配。所以真正的速度差异可能会更大。

#2


3  

When I have a String that I need to concatenate a single char to its end, should I prefer s = .... + ']' over s = .... + "]" for any performance reason?

当我有一个字符串,我需要将一个字符连接到它的结尾时,我是否应该选择s =+ ']' / s = ....“为了任何性能原因?”

There are actually two questions here:

这里有两个问题

Q1: Is there a performance difference?

Q1:有性能差异吗?

Answer: It depends ...

答:这取决于……

  • In some cases, possibly yes, depending on the JVM and/or the bytecode compiler. If the bytecode compiler generates a call to StringBuilder.append(char) rather than StringBuilder.append(String) then you would expect the former to be faster. But the JIT compiler could treat these methods as "intrinics" and optimize calls to append(String) with a one character (literal) string.

    在某些情况下,可能是的,取决于JVM和/或字节码编译器。如果字节码编译器生成一个对StringBuilder.append(char)的调用,而不是StringBuilder.append(String),那么您会期望前者更快。但是JIT编译器可以将这些方法视为“内在”,并优化调用以一个字符(文字)字符串附加(字符串)。

    In short, you would need to benchmark this on your platform to be sure.

    简而言之,您需要在您的平台上确定这一点。

  • In other cases, there is definitely no difference. For example, these two calls will be compiled identical bytecode sequences because the concatenation is a Constant Expression.

    在其他情况下,肯定没有区别。例如,这两个调用将被编译成相同的字节码序列,因为连接是一个常量表达式。

        System.out.println("234" + "]");
    
        System.out.println("234" + ']');
    

    This is guaranteed by the JLS.

    这是由JLS保证的。

Q2: Should you prefer one version over the other.

你是否应该选择一个版本而不是另一个版本。

Answer:

答:

  • In the general sense, this is likely to be a premature optimization. You should only prefer one form over the other for performance reasons if you have profiled your code at the application level and determined that the code snippet has a measurable impact on performance.

    在一般意义上,这可能是一个不成熟的优化。如果您在应用程序级别上对代码进行了分析,并确定代码片段对性能有可测量的影响,那么您应该只喜欢一种形式而不是另一种形式。

  • If you have profiled the code, then use the answer to Q1 as a guide.

    如果您已经对代码进行了分析,那么请使用Q1作为指南。

    And if it was worth trying to optimize the snippet, then is essential that you rerun your benchmarking / profiling after optimizing, to see if it made any difference. Your intuition about what is fastest... and what you have read in some old article on the internet ... could be very wrong.

    如果值得尝试优化代码片段,那么在优化后重新运行基准测试/概要分析,看看它是否有什么不同,这是非常重要的。你对什么是最快的直觉……你在网上看到的一些旧文章……可能是非常错误的。

#3


0  

No! That is premature optimization, and a complete waste of your time. Prefer whichever you prefer, and use whichever works. Sometimes ']' won't promote to "]" automatically. I expect the JIT will optimize away any performance difference you think you measure. And in the cases where it works, it works because ']' was converted to "]" (in your example). Now, using a StringBuilder directly and append(char) might be slightly faster... but again, this difference won't be meaningful in any real application.

不!这是不成熟的优化,完全浪费你的时间。你喜欢哪个就选哪个,用哪个都行。“有时”“不会”“自动”。我希望JIT能够优化你认为你衡量的任何性能差异。在它工作的情况下,它起作用是因为“]”被转换为“”)(在你的例子中)。现在,直接使用StringBuilder和append(char)可能会稍微快一些……但是,这种差异在任何实际应用中都不会有意义。

Edit

编辑

The best advice I can give you about performance is:

关于业绩,我能给你的最好建议是:

  1. Benchmark before you start making code changes (and try to limit yourself to areas where you are likely to have an impact through real critical-path identification) and
  2. 在开始进行代码更改之前(并尝试将自己限制在可能通过真正的关键路径标识进行影响的领域)和。
  3. If you can, stream a result instead of building a temporary String where possible (this will sometimes pay huge dividends with regards to memory usage and performance).
  4. 如果可以的话,不要在可能的情况下构建一个临时字符串(这会在内存使用和性能方面带来巨大的回报)。

推荐阅读
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • 2018年人工智能大数据的爆发,学Java还是Python?
    本文介绍了2018年人工智能大数据的爆发以及学习Java和Python的相关知识。在人工智能和大数据时代,Java和Python这两门编程语言都很优秀且火爆。选择学习哪门语言要根据个人兴趣爱好来决定。Python是一门拥有简洁语法的高级编程语言,容易上手。其特色之一是强制使用空白符作为语句缩进,使得新手可以快速上手。目前,Python在人工智能领域有着广泛的应用。如果对Java、Python或大数据感兴趣,欢迎加入qq群458345782。 ... [详细]
  • 原文地址:https:www.cnblogs.combaoyipSpringBoot_YML.html1.在springboot中,有两种配置文件,一种 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • 本文讨论了如何使用IF函数从基于有限输入列表的有限输出列表中获取输出,并提出了是否有更快/更有效的执行代码的方法。作者希望了解是否有办法缩短代码,并从自我开发的角度来看是否有更好的方法。提供的代码可以按原样工作,但作者想知道是否有更好的方法来执行这样的任务。 ... [详细]
  • 本文讨论了一个数列求和问题,该数列按照一定规律生成。通过观察数列的规律,我们可以得出求解该问题的算法。具体算法为计算前n项i*f[i]的和,其中f[i]表示数列中有i个数字。根据参考的思路,我们可以将算法的时间复杂度控制在O(n),即计算到5e5即可满足1e9的要求。 ... [详细]
author-avatar
mobiledu2502883317
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有