Java如何使用“+”进行字符串连接?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2721998/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 12:06:25  来源:igfitidea点击:

How Java do the string concatenation using "+"?

javastring

提问by Tom Brito

I read about the way Java works with +=operator, using StringBuilder.
Is it the same with a ("a" + "b")operation?

我阅读了 Java 与+=运算符一起工作的方式,使用StringBuilder.
("a" + "b")手术一样吗?

采纳答案by Pablo Santa Cruz

No. It's not the same using StringBuilderthan doing "a" + "b".

不,这与使用StringBuilder和做不同"a" + "b"

In Java, String instances are immutable.

在 Java 中,String 实例是不可变的。

So, if you do:

所以,如果你这样做:

String c = "a" + "b";

You are creating new Strings every time you concatenate.

每次连接时都会创建新的字符串。

On the other hand, StringBuilder is like a buffer that can grow as it needs when appending new Strings.

另一方面,StringBuilder 就像一个缓冲区,可以在追加新字符串时根据需要增长。

StringBuilder c = new StringBuilder();
c.append("a");
c.append("b"); // c is only created once and appended "a" and "b".

Rule of the thumb is (changed thanks to the comments I got):

经验法则是(由于我得到的评论而改变):

If you are going to concatenate a lot (i.e., concatenate inside a loop, or generating a big XML formed by several string concatenated variables), do use StringBuilder. Otherwise, simple concatenation (using + operator) will be just fine.

如果您要连接很多(即在循环内连接,或生成由多个字符串连接变量形成的大 XML),请使用 StringBuilder。否则,简单的连接(使用 + 运算符)就可以了。

Compiler optimizations also play a huge role when compiling this kind of code.

编译器优化在编译此类代码时也发挥着重要作用。

Here'sfurther explanation on the topic.

这是有关该主题进一步解释。

And more StackOVerflow questions on the issue:

以及更多关于这个问题的 StackOverflow 问题:

Is it better to reuse a StringBuilder in a loop?

在循环中重用 StringBuilder 会更好吗?

What's the best way to build a string of delimited items in Java?

在 Java 中构建一串分隔项的最佳方法是什么?

StringBuilder vs String concatenation in toString() in Java

Java 中 toString() 中的 StringBuilder 与字符串连接

回答by Donal Fellows

Yes, it's the same, but the compiler can additionally optimize concatenations of literalsbefore issuing the code, so "a"+"b"can be just issued as "ab"directly.

是的,它是一样的,但是编译器可以在发布代码之前额外优化文字的连接,所以"a"+"b"可以"ab"直接发布。

回答by inkedmn

Strings are more commonly concatenated with the + operator, as in "Hello," + " world" + "!"

字符串更常与 + 运算符连接,如 "Hello," + " world" + "!"

Source

来源

回答by T.J. Crowder

If you combine literalstrings (literally "foo" + "bar"), the compiler does it at compile-time, not at runtime.

如果您组合文字字符串(字面意思"foo" + "bar"),编译器会在编译时执行,而不是在运行时执行。

If you have two non-literal strings and join them with +, the compiler (Sun's, anyway) will use a StringBuilderunder the covers, but not necessarily in the most efficient way. So for instance, if you have this:

如果您有两个非文字字符串并用 将它们连接起来+,编译器(无论如何都是 Sun 的)将StringBuilder在幕后使用 a ,但不一定以最有效的方式使用。例如,如果你有这个:

String repeat(String a, int count) {
    String rv;

    if (count <= 0) {
        return "";
    }

    rv = a;
    while (--count > 0) {
        rv += a;
    }
    return rv;
}

...what the Sun compiler will actually produce as bytecode looks somethinglike this:

......什么Sun编译器将实际产生的字节码看起来事情是这样的:

String repeat(String a, int count) {
    String rv;

    if (count <= 0) {
        return "";
    }

    rv = a;
    while (--count > 0) {
        rv = new StringBuilder().append(rv).append(a).toString();
    }
    return rv;
}

(Yes, really — see the disassembly at the end of this answer.) Note that it created a new StringBuilderon every iteration, and then converted the result to String. This is inefficient (but it doesn't matter unless you're doing it a lot) because of all of the temporary memory allocations: It allocates a StringBuilderand its buffer, quite possibly reallocates the buffer on the first append[if rvis more than 16 characters long, which is the default buffer size] and if not on the first then almost certainly on the second append, then allocates a Stringat the end — and then does it all againon the next iteration.

(是的,真的 - 请参阅本答案末尾的反汇编。)请注意,它StringBuilder在每次迭代时都创建了一个新的,然后将结果转换为String. 这是低效的(但是不要紧,除非你正在做一个很大),因为所有的临时内存分配的:它分配一个StringBuilder和它的缓冲,很可能重新分配缓冲区第一append[如果rv是超过16个字符long,这是默认的缓冲区大小],如果不在第一个上,那么几乎可以肯定在第二个上append,然后String在最后分配 a - 然后在下一次迭代中再次执行所有操作

You could gain efficiency, if necessary, by rewriting it to explicitly use a StringBuilder:

如有必要,您可以通过重写它以显式使用 a 来提高效率StringBuilder

String repeat(String a, int count) {
    StringBuilder rv;

    if (count <= 0) {
        return "";
    }

    rv = new StringBuilder(a.length() * count);
    while (count-- > 0) {
        rv.append(a);
    }
    return rv.toString();
}

There we've used an explicit StringBuilderand also set its initial buffer capacity to be large enough to hold the result. That's more memory-efficient, but of course, marginally less clear to inexperienced code maintainers and marginally more of a pain to write. So ifyou find a performance issue with a tight string concat loop, this might be a way to address it.

在那里我们使用了一个显式StringBuilder并将其初始缓冲区容量设置为足够大以保存结果。这更节省内存,但当然,对于没有经验的代码维护者来说不太清楚,而且编写起来也有点痛苦。因此,如果您发现紧密的字符串 concat 循环存在性能问题,这可能是一种解决方法。

You can see this under-the-covers StringBuilderin action with the following test class:

您可以StringBuilder使用以下测试类查看幕后操作:

public class SBTest
{
    public static final void main(String[] params)
    {
        System.out.println(new SBTest().repeat("testing ", 4));
        System.exit(0);
    }

    String repeat(String a, int count) {
        String rv;

        if (count <= 0) {
            return "";
        }

        rv = a;
        while (--count > 0) {
            rv += a;
        }
        return rv;
    }
}

...which disassembles (using javap -c SBTest) like this:

...它javap -c SBTest像这样反汇编(使用):

Compiled from "SBTest.java"
public class SBTest extends java.lang.Object{
public SBTest();
Code:
   0: aload_0
   1: invokespecial  #1; //Method java/lang/Object."<init>":()V
   4: return

public static final void main(java.lang.String[]);
Code:
   0: getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   3: new   #3; //class SBTest
   6: dup
   7: invokespecial  #4; //Method "<init>":()V
   10: ldc   #5; //String testing
   12: iconst_4
   13: invokevirtual  #6; //Method repeat:(Ljava/lang/String;I)Ljava/lang/String;
   16: invokevirtual  #7; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   19: iconst_0
   20: invokestatic   #8; //Method java/lang/System.exit:(I)V
   23: return

java.lang.String repeat(java.lang.String, int);
Code:
   0: iload_2
   1: ifgt  7
   4: ldc   #9; //String
   6: areturn
   7: aload_1
   8: astore_3
   9: iinc  2, -1
   12: iload_2
   13: ifle  38
   16: new   #10; //class java/lang/StringBuilder
   19: dup
   20: invokespecial  #11; //Method java/lang/StringBuilder."<init>":()V
   23: aload_3
   24: invokevirtual  #12; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   27: aload_1
   28: invokevirtual  #12; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   31: invokevirtual  #13; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   34: astore_3
   35: goto  9
   38: aload_3
   39: areturn

}

Note how a new StringBuilderis created on eachiteration of the loop and created using the default buffer capacity.

请注意如何在循环的每次迭代中StringBuilder创建新的并使用默认缓冲区容量创建。

All of this temporary allocation stuff sounds ugly, but again, only if you're dealing with substantial loops and/or substantial strings. Also, when the resulting bytecode is run, the JVM may well optimize it further. Sun's HotSpot JVM, for instance, is a very mature JIT optimizing compiler. Once it's identified the loop as a hot spot, it may well find a way to refactor it. Or not, of course. :-)

所有这些临时分配的东西听起来都很丑陋,但同样,只有当您处理大量循环和/或大量字符串时。此外,当生成的字节码运行时,JVM 可能会进一步优化它。例如,Sun 的 HotSpot JVM 是一个非常成熟的 JIT 优化编译器。一旦将循环识别为热点,它很可能会找到重构它的方法。或者不,当然。:-)

My rule of thumb is I worry about it when I see a performance problem, or if I know I'm doing a lotof concatenation and it's very likelyto be a performance problem and the code won't be significantly impacted from a maintainability standpoint if I use a StringBuilderinstead. The rabid anti-premature-optimization league would probably disagree with me on the second of those. :-)

我的经验法则是当我看到性能问题时我会担心,或者如果我知道我正在做很多连接并且它很可能是一个性能问题并且代码不会从可维护性的角度受到显着影响如果我使用 aStringBuilder代替。狂热的反过早优化联盟可能会不同意我的第二个观点。:-)

回答by Christian Semrau

For concatenating a fixed number of strings in one expressionwith +, the compiler will produce code using a single StringBuilder.

为了将一个表达式中的固定数量的字符串与连接起来+,编译器将使用单个StringBuilder.

E.g. the line

例如线

String d = a + b + c;

results in the same bytecode as the line

产生与行相同的字节码

String d = new StringBuilder().append(a).append(b).append(c).toString();

when compiled using the javac compiler. (The Eclipse compiler produces somewhat more optimized code by invoking new StringBuilder(a), thus saving one method call.)

使用 javac 编译器编译时。(Eclipse 编译器通过调用 生成更优化的代码new StringBuilder(a),从而节省了一次方法调用。)

As mentioned in other answers, the compiler will concatenate string literals like "a" + "b"into one string itself, producing bytecode that contains "ab"instead.

正如其他答案中提到的,编译器会将字符串文字像连接"a" + "b"到一个字符串本身一样,生成包含的字节码"ab"

As mentioned everywhere on the net, you should not use +to build up one string within a loop, because you are copying the beginning of the string over and over to new strings. In this situation you should use one StringBuilderwhich you declare outside the loop.

正如网络上到处提到的那样,您不应该使用在循环中+构建一个字符串,因为您正在一遍又一遍地将字符串的开头复制到新的字符串中。在这种情况下,您应该使用在循环外声明的一个。StringBuilder

回答by ring bearer

"a" + "b"operation

"a" + "b"手术

Though readable, easy to format and straight forward, concatenating strings with "+" is considered to be bad in Java.

尽管可读、易于格式化且简单明了,但在 Java 中用“+”连接字符串被认为是不好的。

Each time you append something via '+' (String.concat()) a new String is created, the old String content is copied, the new content is appended, and the old String is discarded. The bigger the String gets the longer it takes - there is more to copy and more garbage is produced. Note:if you are just concatenating a few (say 3,4) strings and not building a string via a loop or just writing some test application, you could still stick with "+"

每次通过 '+' (String.concat()) 附加内容时,都会创建一个新字符串,复制旧字符串内容,附加新内容,并丢弃旧字符串。字符串越大,需要的时间越长——需要复制的内容越多,产生的垃圾也越多。 注意:如果您只是连接几个(比如 3,4)字符串而不是通过循环构建字符串或只是编写一些测试应用程序,您仍然可以坚持使用“+”

Using StringBuilder

使用 StringBuilder

When performing extensive String manipulation (or appending through a loop), replacing "+" with StringBuilder.append is likely recommended. The intermediate objects mentioned in case of "+" are not created during append()method call.

在执行大量字符串操作(或通过循环附加)时,StringBuilder可能建议将“+”替换为.append。在“+”的情况下提到的中间对象不是在append()方法调用期间创建的。

Also to be noted that optimizations in the Sun Java compiler, which automatically creates StringBuilders(StringBuffers< 5.0) when it sees String concatenations. But that is just Sun Java compiler.

还需要注意的是 Sun Java 编译器中的优化,当它看到字符串连接时会自动创建StringBuilders( StringBuffers<5.0)。但这只是 Sun Java 编译器。