누군가가 StringBuffer
을 사용하여 String
s에 대해 +
연산자를 사용하는 것보다 Java에 문자열을 연결하는 것이 StringBuffer
을 사용하는 것이 더 효율적이라고 말했습니다. 다르게?
요즘, 거의 모든 경우에 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
-String
s는 변경 불가능)가 필요합니다. 이것은 매우 낭비입니다. 이것을 단일 StringBuilder
로 바꾸면 단일 String
만 생성 할 수 있으며 상관하지 않은 String
s로 힙을 채울 수 없습니다.
다음과 같은 간단한 연결의 경우 :
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
메소드가 동기화됩니다.
하나는 다른 것보다 빠르지 않아야합니다. 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보다 더 깔끔합니다.
후드 아래에서 실제로 결과에 대해 toString ()을 호출하여 StringBuffer를 만들고 추가합니다. 따라서 실제로 더 이상 사용하는 것은 중요하지 않습니다.
그래서
String s = "a" + "b" + "c";
된다
String s = new StringBuffer().append("a").append("b").append("c").toString();
단일 명령문 내에서 여러 인라인 추가가 적용됩니다. 여러 명령문을 통해 문자열을 작성하면 메모리가 낭비되고 StringBuffer 또는 StringBuilder가 더 나은 선택입니다.
Jdk1.5 (또는 그 이상)가 주어지고 연결이 스레드로부터 안전하다고 생각하면 StringBuffer 대신 StringBuilder를 사용해야합니다 http://Java4ever.blogspot.com/2007/03/string-vs-stringbuffer-vs -stringbuilder.html 속도 향상과 관련하여 : http://www.about280.com/stringtest.html
개인적으로 나는 가독성을 위해 코드를 작성 했으므로 문자열 연결로 인해 코드 속도가 상당히 느려지지 않는 한 코드를 더 읽기 쉽게 만드는 방법을 유지하십시오.
경우에 따라 컴파일러에서 수행하는 최적화로 인해이 기능이 더 이상 사용되지 않지만 일반적인 문제는 다음과 같은 코드입니다.
string myString="";
for(int i=0;i<x;i++)
{
myString += "x";
}
다음과 같이 작동합니다 (각 단계는 다음 루프 반복 임).
보시다시피, 각 반복은 하나 이상의 문자를 복사해야하므로 각 루프마다 1 + 2 + 3 + 4 + 5 + ... + N 연산을 수행합니다. 이것은 O (n ^ 2) 연산입니다. 그러나 우리가 N 문자 만 필요하다는 것을 미리 알고 있다면 사용중인 문자열에서 N 문자 만 복사하여 단일 할당으로 수행 할 수 있습니다. 단순한 O(n) 조작.
StringBuffer/StringBuilder는 변경 가능하므로이를 피하므로 내부 버퍼에 복사 할 공간이있는 한 동일한 데이터를 계속 반복해서 복사 할 필요가 없습니다. 그들은 버퍼 크기를 현재 크기의 비율로 초과 할당하여 수행되는 추가 수에 비례하여 할당 및 복사를 수행하지 않고 상각 O(1) 추가)를 제공합니다.
그러나 종종 컴파일러가 StringBuilder 스타일로 코드를 최적화 할 수 있다는 점은 주목할 가치가 있습니다 (또는 상수 접기 등을 수행 할 수 있기 때문에 더 좋습니다).
AFAIK는 "+"또는 "+ ="를 사용하는 1.5 이전 버전의 JVM 버전에 따라 매번 전체 문자열을 실제로 복사했습니다.
+ =를 사용하면 실제로 새 문자열 복사본이 할당됩니다.
루프에서 +를 사용하여 지적했듯이 복사가 포함됩니다.
연결된 문자열이 컴파일 시간 상수 인 경우 컴파일시 연결된 문자열이므로
String foo = "a" + "b" + "c";
Has는 다음과 같이 컴파일됩니다.
String foo = "abc";
Java는 string1 + string2를 StringBuffer 구문, append () 및 toString ()으로 변환합니다. 이것은 말이됩니다.
그러나 Java 1.4 및 이전 버전에서는 별도 문에서 each + 연산자에 대해이 작업을 수행합니다. b + c는 two toString () 호출을 사용하여 two StringBuffer 구문을 생성합니다 .concats가 긴 문자열은 실제로 혼란스러워집니다. 당신이 이것을 제어하고 올바르게 할 수 있음을 의미했습니다.
Java 5.0 이상은 더 현명하게 수행하는 것처럼 보이므로 문제가 적고 덜 장황합니다.
추가 정보 :
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 ..
}
StringBuffer는 변경 가능합니다. 다른 객체를 인스턴스화하지 않고 문자열 값을 same 객체에 추가합니다. 같은 일을 :
myString = myString + "XYZ"
new String 객체를 만듭니다.
'+'를 사용하여 두 문자열을 연결하려면 두 문자열에 공백이있는 새 문자열을 할당 한 다음 두 문자열에서 데이터를 복사해야합니다. StringBuffer는 연결에 최적화되어 있으며 처음에 필요한 것보다 많은 공간을 할당합니다. 새 문자열을 연결할 때 대부분의 경우 문자를 기존 문자열 버퍼의 끝으로 간단하게 복사 할 수 있습니다.
두 개의 문자열을 연결하는 경우 '+'연산자는 오버 헤드가 적을 수 있지만 더 많은 문자열을 연결하면 더 적은 메모리 할당 및 데이터 복사를 사용하여 StringBuffer가 나옵니다.
StringBuffer 클래스는 연결하는 문자열의 내용을 유지하기 위해 문자 배열을 유지하지만 + 메서드는 호출 할 때마다 새 문자열을 만들고 두 매개 변수 (param1 + param2)를 추가합니다.
StringBuffer는 1. 더 빠르기 때문에 이미 존재하는 배열을 사용하여 모든 문자열을 연결/저장할 수 있습니다. 2. 배열에 맞지 않더라도 더 큰 배킹 배열을 할당하는 것보다 빠르며 각 호출에 대해 새로운 String 객체를 생성합니다.
문자열은 변경할 수 없으므로 + 연산자를 호출 할 때마다 새 문자열 객체가 만들어지고 문자열 데이터가 새 문자열로 복사됩니다. 문자열을 복사하면 문자열 길이에서 시간이 선형으로 걸리기 때문에 + 연산자에 대한 N 호출 시퀀스는 O (N2) 실행 시간 (이차).
반대로 StringBuffer는 변경 가능하므로 Append ()를 수행 할 때마다 String을 복사 할 필요가 없으므로 N Append () 호출 순서는 O(N) time ( 많은 수의 문자열을 함께 추가하는 경우 런타임에 큰 차이가 있습니다.
앞에서 언급했듯이 String 객체는 변경 가능하며 일단 생성되면 (아래 참조) 변경할 수 없습니다.
문자열 x = 새 문자열 ( "something"); // 또는
문자열 x = "무언가";
따라서 String 객체를 연결하려고 시도하면 해당 객체의 값을 가져 와서 새로운 String 객체에 넣습니다.
IS 변경 가능) 인 StringBuffer를 사용하는 경우 필요한 값에 맞게 확장되거나 잘릴 수있는 char (기본)의 내부 목록에 값을 계속 추가합니다. 값을 보유해야 할 때 새 문자 만 작성/제거됩니다.
두 개의 문자열을 연결하면 실제로 Java로 세 번째 문자열 객체를 만듭니다. StringBuffer (또는 Java 5/6)의 StringBuilder를 사용하면 문자열을 저장하기 위해 내부 문자 배열을 사용하고 add (...) 메소드 중 하나를 사용할 때 더 빠릅니다. 새 String 객체를 만들지 않고 대신 StringBuffer/Buider가 내부 배열을 추가합니다.
간단한 연결에서는 StringBuffer/Builder 또는 '+'연산자를 사용하여 문자열을 연결하는지 여부는 실제로 문제가되지 않지만 많은 문자열 연결을 수행 할 때는 StringBuffer/Builder를 사용하는 것이 더 빠르다는 것을 알 수 있습니다.
Java에서는 문자열을 변경할 수 없으므로 문자열을 연결할 때마다 메모리에 새 객체가 생성됩니다. StringBuffer는 메모리에서 동일한 객체를 사용합니다.
가장 간단한 대답은 더 빠르다고 생각합니다.
실제로 모든 것을 알고 싶다면 항상 소스를 직접 볼 수 있습니다.
Java 언어 사양의 문자열 연결 연산자 + 섹션에는 + 연산자가 왜 그렇게 느릴 수 있는지에 대한 배경 정보가 더 있습니다.