it-swarm-ko.tech

문자열 연결 연산자 대신 Java에 StringBuffer를 사용하는 이유)

누군가가 StringBuffer을 사용하여 Strings에 대해 + 연산자를 사용하는 것보다 Java에 문자열을 연결하는 것이 StringBuffer을 사용하는 것이 더 효율적이라고 말했습니다. 다르게?

54
harry

요즘, 거의 모든 경우에 StringBuilder (동기화되지 않은 버전입니다; 언제 병렬로 문자열을 작성합니까?)를 사용하는 것이 좋습니다. 그러나 다음과 같은 상황이 발생합니다.

두 개의 문자열과 함께 +를 사용하면 다음과 같은 코드가 컴파일됩니다.

String third = first + second;

이런 식으로 :

StringBuilder builder = new StringBuilder( first );
builder.append( second );
third = builder.toString();

따라서 작은 예제의 경우 일반적으로 차이가 없습니다. 그러나 복잡한 문자열을 만들 때 종종 이보다 더 많은 것을 처리해야합니다. 예를 들어, 다양한 추가 명령문을 사용하거나 다음과 같은 루프를 사용할 수 있습니다.

for( String str : strings ) {
  out += str;
}

이 경우, 각 반복마다 새로운 StringBuilder 인스턴스와 새로운 String (새로운 값 out-Strings는 변경 불가능)가 필요합니다. 이것은 매우 낭비입니다. 이것을 단일 StringBuilder로 바꾸면 단일 String 만 생성 할 수 있으며 상관하지 않은 Strings로 힙을 채울 수 없습니다.

62
Calum

다음과 같은 간단한 연결의 경우 :

String s = "a" + "b" + "c";

StringBuffer- jodonnell 을 사용하는 것이 의미가 없습니다.

String s = new StringBuffer().append("a").append("b").append("c").toString();

BUT 다음과 같이 루프에서 문자열을 연결하는 것은 매우 성능이 떨어집니다.

String s = "";
for (int i = 0; i < 10; i++) {
    s = s + Integer.toString(i);
}

이 루프에서 문자열을 사용하면 메모리에 "0", "01", "012"등 10 개의 중간 문자열 객체가 생성됩니다. StringBuffer를 사용하여 동일하게 작성하는 동안 StringBuffer의 일부 내부 버퍼를 업데이트하기 만하면 필요하지 않은 중간 문자열 객체를 만들지 않습니다.

StringBuffer sb = new StringBuffer();
for (int i = 0; i < 10; i++) {
    sb.append(i);
}

실제로 위의 예에서는 StringBuilder 대신 StringBuffer (Java 1.5)에 도입)를 사용해야합니다.-StringBuffer 메소드가 동기화됩니다.

42
tkokoszka

하나는 다른 것보다 빠르지 않아야합니다. Java 1.4.2 이전에는 사실이 아니 었습니다. "+"연산자를 사용하여 두 개 이상의 문자열을 연결하면 빌드 과정에서 중간 String 객체가 생성되기 때문에 마지막 문자열.

그러나 JavaDoc for StringBuffer 상태이므로 적어도 "="연산자를 사용하여 Java 1.4.2 _ StringBuffer 및 많은 문자열을 append() ing하기 때문에 분명히 차이는 없습니다.

그러나 루프 내에서 다른 문자열에 문자열을 추가 할 때주의하십시오! 예를 들면 다음과 같습니다.

String myString = "";

for (String s : listOfStrings) {
  // Be careful! You're creating one intermediate String object
  // for every iteration on the list (this is costly!)
  myString += s;
}

그러나 일반적으로 "+"로 몇 개의 문자열을 연결하면 append() ing보다 더 깔끔합니다.

20
André Chalella

후드 아래에서 실제로 결과에 대해 toString ()을 호출하여 StringBuffer를 만들고 추가합니다. 따라서 실제로 더 이상 사용하는 것은 중요하지 않습니다.

그래서

String s = "a" + "b" + "c";

된다

String s = new StringBuffer().append("a").append("b").append("c").toString();

단일 명령문 내에서 여러 인라인 추가가 적용됩니다. 여러 명령문을 통해 문자열을 작성하면 메모리가 낭비되고 StringBuffer 또는 StringBuilder가 더 나은 선택입니다.

9
jodonnell

Jdk1.5 (또는 그 이상)가 주어지고 연결이 스레드로부터 안전하다고 생각하면 StringBuffer 대신 StringBuilder를 사용해야합니다 http://Java4ever.blogspot.com/2007/03/string-vs-stringbuffer-vs -stringbuilder.html 속도 향상과 관련하여 : http://www.about280.com/stringtest.html

개인적으로 나는 가독성을 위해 코드를 작성 했으므로 문자열 연결로 인해 코드 속도가 상당히 느려지지 않는 한 코드를 더 읽기 쉽게 만드는 방법을 유지하십시오.

7
slipset

경우에 따라 컴파일러에서 수행하는 최적화로 인해이 기능이 더 이상 사용되지 않지만 일반적인 문제는 다음과 같은 코드입니다.

string myString="";
for(int i=0;i<x;i++)
{
    myString += "x";
}

다음과 같이 작동합니다 (각 단계는 다음 루프 반복 임).

  1. 길이가 1 인 문자열 객체를 만들고 값 "x"
  2. 크기가 2 인 새 문자열 객체를 만들고 이전 문자열 "x"를 복사 한 다음 위치 2에 "x"를 추가합니다.
  3. 크기가 3 인 새 문자열 객체를 만들고 이전 문자열 "xx"를 복사 한 다음 위치 3에 "x"를 추가합니다.
  4. ... 등등

보시다시피, 각 반복은 하나 이상의 문자를 복사해야하므로 각 루프마다 1 + 2 + 3 + 4 + 5 + ... + N 연산을 수행합니다. 이것은 O (n ^ 2) 연산입니다. 그러나 우리가 N 문자 만 필요하다는 것을 미리 알고 있다면 사용중인 문자열에서 N 문자 만 복사하여 단일 할당으로 수행 할 수 있습니다. 단순한 O(n) 조작.

StringBuffer/StringBuilder는 변경 가능하므로이를 피하므로 내부 버퍼에 복사 할 공간이있는 한 동일한 데이터를 계속 반복해서 복사 할 필요가 없습니다. 그들은 버퍼 크기를 현재 크기의 비율로 초과 할당하여 수행되는 추가 수에 비례하여 할당 및 복사를 수행하지 않고 상각 O(1) 추가)를 제공합니다.

그러나 종종 컴파일러가 StringBuilder 스타일로 코드를 최적화 할 수 있다는 점은 주목할 가치가 있습니다 (또는 상수 접기 등을 수행 할 수 있기 때문에 더 좋습니다).

5
Brian

AFAIK는 "+"또는 "+ ="를 사용하는 1.5 이전 버전의 JVM 버전에 따라 매번 전체 문자열을 실제로 복사했습니다.

+ =를 사용하면 실제로 새 문자열 복사본이 할당됩니다.

루프에서 +를 사용하여 지적했듯이 복사가 포함됩니다.

연결된 문자열이 컴파일 시간 상수 인 경우 컴파일시 연결된 문자열이므로

String foo = "a" + "b" + "c";

Has는 다음과 같이 컴파일됩니다.

String foo = "abc"; 
3
jb.

Java는 string1 + string2를 StringBuffer 구문, append () 및 toString ()으로 변환합니다. 이것은 말이됩니다.

그러나 Java 1.4 및 이전 버전에서는 별도 문에서 each + 연산자에 대해이 작업을 수행합니다. b + c는 two toString () 호출을 사용하여 two StringBuffer 구문을 생성합니다 .concats가 긴 문자열은 실제로 혼란스러워집니다. 당신이 이것을 제어하고 올바르게 할 수 있음을 의미했습니다.

Java 5.0 이상은 더 현명하게 수행하는 것처럼 보이므로 문제가 적고 덜 장황합니다.

3
Alan Krueger

추가 정보 :

StringBuffer는 스레드 안전 클래스입니다


public final class StringBuffer extends AbstractStringBuilder
    implements Serializable, CharSequence
{
// .. skip ..
     public synchronized StringBuffer append(StringBuffer stringbuffer)
    {
        super.append(stringbuffer);
        return this;
    }
// .. skip ..
}

그러나 StringBuilder는 스레드로부터 안전하지 않으므로 가능한 경우 StringBuilder를 사용하는 것이 더 빠릅니다.


public final class StringBuilder extends AbstractStringBuilder
    implements Serializable, CharSequence
{
// .. skip ..
    public StringBuilder append(String s)
    {
        super.append(s);
        return this;
    }
// .. skip ..
}

1
Eric Yung

StringBuffer는 변경 가능합니다. 다른 객체를 인스턴스화하지 않고 문자열 값을 same 객체에 추가합니다. 같은 일을 :

myString = myString + "XYZ"

new String 객체를 만듭니다.

1
Loren Segal

'+'를 사용하여 두 문자열을 연결하려면 두 문자열에 공백이있는 새 문자열을 할당 한 다음 두 문자열에서 데이터를 복사해야합니다. StringBuffer는 연결에 최적화되어 있으며 처음에 필요한 것보다 많은 공간을 할당합니다. 새 문자열을 연결할 때 대부분의 경우 문자를 기존 문자열 버퍼의 끝으로 간단하게 복사 할 수 있습니다.
두 개의 문자열을 연결하는 경우 '+'연산자는 오버 헤드가 적을 수 있지만 더 많은 문자열을 연결하면 더 적은 메모리 할당 및 데이터 복사를 사용하여 StringBuffer가 나옵니다.

1
Eclipse

StringBuffer 클래스는 연결하는 문자열의 내용을 유지하기 위해 문자 배열을 유지하지만 + 메서드는 호출 할 때마다 새 문자열을 만들고 두 매개 변수 (param1 + param2)를 추가합니다.

StringBuffer는 1. 더 빠르기 때문에 이미 존재하는 배열을 사용하여 모든 문자열을 연결/저장할 수 있습니다. 2. 배열에 맞지 않더라도 더 큰 배킹 배열을 할당하는 것보다 빠르며 각 호출에 대해 새로운 String 객체를 생성합니다.

1
Matt Novinger

문자열은 변경할 수 없으므로 + 연산자를 호출 할 때마다 새 문자열 객체가 만들어지고 문자열 데이터가 새 문자열로 복사됩니다. 문자열을 복사하면 문자열 길이에서 시간이 선형으로 걸리기 때문에 + 연산자에 대한 N 호출 시퀀스는 O (N2) 실행 시간 (이차).

반대로 StringBuffer는 변경 가능하므로 Append ()를 수행 할 때마다 String을 복사 할 필요가 없으므로 N Append () 호출 순서는 O(N) time ( 많은 수의 문자열을 함께 추가하는 경우 런타임에 큰 차이가 있습니다.

1
Adam Rosenfield

앞에서 언급했듯이 String 객체는 변경 가능하며 일단 생성되면 (아래 참조) 변경할 수 없습니다.

문자열 x = 새 문자열 ( "something"); // 또는

문자열 x = "무언가";

따라서 String 객체를 연결하려고 시도하면 해당 객체의 값을 가져 와서 새로운 String 객체에 넣습니다.

IS 변경 가능) 인 StringBuffer를 사용하는 경우 필요한 값에 맞게 확장되거나 잘릴 수있는 char (기본)의 내부 목록에 값을 계속 추가합니다. 값을 보유해야 할 때 새 문자 만 작성/제거됩니다.

1
Christian P.

두 개의 문자열을 연결하면 실제로 Java로 세 번째 문자열 객체를 만듭니다. StringBuffer (또는 Java 5/6)의 StringBuilder를 사용하면 문자열을 저장하기 위해 내부 문자 배열을 사용하고 add (...) 메소드 중 하나를 사용할 때 더 빠릅니다. 새 String 객체를 만들지 않고 대신 StringBuffer/Buider가 내부 배열을 추가합니다.

간단한 연결에서는 StringBuffer/Builder 또는 '+'연산자를 사용하여 문자열을 연결하는지 여부는 실제로 문제가되지 않지만 많은 문자열 연결을 수행 할 때는 StringBuffer/Builder를 사용하는 것이 더 빠르다는 것을 알 수 있습니다.

1
Alexandre Brasil

Java에서는 문자열을 변경할 수 없으므로 문자열을 연결할 때마다 메모리에 새 객체가 생성됩니다. StringBuffer는 메모리에서 동일한 객체를 사용합니다.

0
Ivan Bosnic

가장 간단한 대답은 더 빠르다고 생각합니다.

실제로 모든 것을 알고 싶다면 항상 소스를 직접 볼 수 있습니다.

http://www.Sun.com/software/opensource/Java/getinvolved.jsp

http://download.Java.net/jdk6/latest/archive/

0
rgcb

Java 언어 사양의 문자열 연결 연산자 + 섹션에는 + 연산자가 왜 그렇게 느릴 수 있는지에 대한 배경 정보가 더 있습니다.

0
Benedikt Waldvogel