String, StringBuffer, StringBuilder의 차이점과 장단점은 뭔가요?

2014-04-03 22:38

1) String, StringBuffer, StringBuilder의 차이점과 쓰임새가 궁금해요. 그리고 성능은 어떤게 좋을까요?

2) String 은 immutable (한국말로는 뭔지..) 해서 성능이 좋지 않다라는 말도 있었는데요. 이 말 뜻은 뭔가요? 그리고 지금도 여전히 그런가요?

  • 어디가 질문란인지 몰라서 남겼는데, 적당한 자리로 옮겨 주세요. 죄송합니다.

0개의 의견 from FB

BEST 의견 원본위치로↓
2014-04-04 18:35

1) String, StringBuffer, StringBuilder의 차이점과 쓰임새가 궁금해요. 그리고 성능은 어떤게 좋을까요? 답변은 앞의 @changhwa.oh 님이 설명해 주셨는데요. 저는 좀 더 구체적으로 설명해 볼께요. 일단 String과 StringBuffer, StringBuilder 둘을 비교할 수 있는데요. String은 문자열을 대표하는 것으로 문자열을 조작하는 경우 유용하게 사용할 수 있고요. 문자열, 숫자, char 등을 concat할 때는 StringBuffer, StringBuilder를 사용할 수 있어요. 단, 복잡한 경우 의미가 있고, 단순한 경우에는 굳이 StringBuffer, StringBuilder를 쓰지 않고 "abc" + 1 + 'd'와 같이 +를 활용해 직접 합쳐도 됩니다.

StringBuffer, StringBuilder는 동기화 지원 여부입니다. 두 클래스가 제공하는 메소드는 같아요. 단, 메소드를 보면 StringBuffer는 각 메소드 별로 synchronized keyword가 존재하죠. 즉, 멀티 쓰레드 상태에서 동기화를 지원한다는 것이 다릅니다. 코드를 보면 다음과 같아요.

  public final class StringBuffer
    public synchronized StringBuffer append(String str) {
        super.append(str);
        return this;
    }


    public synchronized StringBuffer append(boolean b) {
        super.append(b);
        return this;
    }  


    [...]
}



public final class StringBuilder {
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }


    public StringBuilder append(boolean b) {
        super.append(b);
        return this;
    }    	


    [...]
}

문자열을 +를 활용해 합치는 경우 정확히 어느 버전까지인지 모르겠는데요. 매번 String 인스턴스를 생성하는 방식이였어요. 그래서 성능상의 이슈가 많았죠. 이런 성능 이슈를 개선하기 위해 JDK 1.5 (@changhwa.oh 설명에 따르면) 버전 이후에는 컴파일 단계에서 StringBuilder로 컴파일 되도록 변경되었어요. 그래서 JDK 1.5 이후부터는 +를 활용해도 성능상에 큰 이슈는 없습니다.

이 내용을 좀 더 구체적으로 파고 들어 보면 다음과 같아요.

    public String concat1(String start, String end) {
        return start + end;
    }

위 소스 코드를 컴파일 된 바이트 코드 결과물을 확인해 보면 다음과 같이 변경됩니다.

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


  public java.lang.String concat1(java.lang.String, java.lang.String);
    Code:
       0: new           #16                 // class java/lang/StringBuilder
       3: dup
       4: aload_1
       5: invokestatic  #18                 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
       8: invokespecial #24                 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
      11: aload_2
      12: invokevirtual #27                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      15: invokevirtual #31                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      18: areturn

결과적으로 StringBuilder로 변환되는 것을 알 수 있어요. 최근 JDK 버전에서는 굳이 StringBuilder를 쓰지 않아도 되는거죠.

2) String 은 immutable (한국말로는 뭔지..) 해서 성능이 좋지 않다라는 말도 있었는데요. 이 말 뜻은 뭔가요? 그리고 지금도 여전히 그런가요? immutable에 대한 설명은 http://fowler.egloos.com/1243657 문서에 잘 정리되어 있네요. 앞의 질문에 대한 답변에서 설명했듯이 String이 immutable인 것은 변함이 없어요. 단, String을 concat할 때 String 인스턴스를 사용하는 것이 아니라 StringBuilder를 활용함으로써 성능 이슈를 해결했다고 보면 됩니다.

9개의 의견 from SLiPP

2014-04-04 09:14
  1. 사용법에 따라 다른데 JDK1.5 이상부터는 String도 내부적으로는 StringBuilder 인가.. 로 변환하는걸로 알고 있어요 (제 기억이 정확한지는 잘-..-;)

StringBuffer와 StringBuilder는 동기화 지원 여부 입니다.

단순히 성능만으로 놓고 보면 예전에 책을보면 연산이 많은 경우(?) String < StringBuffer < StringBuilder라고 봤습니다.

  1. 불변 이라는 의미입니다. 설명이 잘나와있어서 예전에 스크랩해둔 사이트 입니다. http://fowler.egloos.com/1243657 쉽게 말하면 변하지 않는다. 연산시 새롭게 생성한다 정도로 이해되는것 같네요.
2014-04-04 18:35

1) String, StringBuffer, StringBuilder의 차이점과 쓰임새가 궁금해요. 그리고 성능은 어떤게 좋을까요? 답변은 앞의 @changhwa.oh 님이 설명해 주셨는데요. 저는 좀 더 구체적으로 설명해 볼께요. 일단 String과 StringBuffer, StringBuilder 둘을 비교할 수 있는데요. String은 문자열을 대표하는 것으로 문자열을 조작하는 경우 유용하게 사용할 수 있고요. 문자열, 숫자, char 등을 concat할 때는 StringBuffer, StringBuilder를 사용할 수 있어요. 단, 복잡한 경우 의미가 있고, 단순한 경우에는 굳이 StringBuffer, StringBuilder를 쓰지 않고 "abc" + 1 + 'd'와 같이 +를 활용해 직접 합쳐도 됩니다.

StringBuffer, StringBuilder는 동기화 지원 여부입니다. 두 클래스가 제공하는 메소드는 같아요. 단, 메소드를 보면 StringBuffer는 각 메소드 별로 synchronized keyword가 존재하죠. 즉, 멀티 쓰레드 상태에서 동기화를 지원한다는 것이 다릅니다. 코드를 보면 다음과 같아요.

  public final class StringBuffer
    public synchronized StringBuffer append(String str) {
        super.append(str);
        return this;
    }


    public synchronized StringBuffer append(boolean b) {
        super.append(b);
        return this;
    }  


    [...]
}



public final class StringBuilder {
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }


    public StringBuilder append(boolean b) {
        super.append(b);
        return this;
    }    	


    [...]
}

문자열을 +를 활용해 합치는 경우 정확히 어느 버전까지인지 모르겠는데요. 매번 String 인스턴스를 생성하는 방식이였어요. 그래서 성능상의 이슈가 많았죠. 이런 성능 이슈를 개선하기 위해 JDK 1.5 (@changhwa.oh 설명에 따르면) 버전 이후에는 컴파일 단계에서 StringBuilder로 컴파일 되도록 변경되었어요. 그래서 JDK 1.5 이후부터는 +를 활용해도 성능상에 큰 이슈는 없습니다.

이 내용을 좀 더 구체적으로 파고 들어 보면 다음과 같아요.

    public String concat1(String start, String end) {
        return start + end;
    }

위 소스 코드를 컴파일 된 바이트 코드 결과물을 확인해 보면 다음과 같이 변경됩니다.

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


  public java.lang.String concat1(java.lang.String, java.lang.String);
    Code:
       0: new           #16                 // class java/lang/StringBuilder
       3: dup
       4: aload_1
       5: invokestatic  #18                 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
       8: invokespecial #24                 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
      11: aload_2
      12: invokevirtual #27                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      15: invokevirtual #31                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      18: areturn

결과적으로 StringBuilder로 변환되는 것을 알 수 있어요. 최근 JDK 버전에서는 굳이 StringBuilder를 쓰지 않아도 되는거죠.

2) String 은 immutable (한국말로는 뭔지..) 해서 성능이 좋지 않다라는 말도 있었는데요. 이 말 뜻은 뭔가요? 그리고 지금도 여전히 그런가요? immutable에 대한 설명은 http://fowler.egloos.com/1243657 문서에 잘 정리되어 있네요. 앞의 질문에 대한 답변에서 설명했듯이 String이 immutable인 것은 변함이 없어요. 단, String을 concat할 때 String 인스턴스를 사용하는 것이 아니라 StringBuilder를 활용함으로써 성능 이슈를 해결했다고 보면 됩니다.

2014-04-04 20:50

String 클래스는 jdk 1.5 버전이전에서도 (StringBuilder이 나오기 전) StringBuffer를 사용하도록 내부구조가 되어있었음.

String 클래스는 immutable => im + mutable 부정을 뜻하는 접두어에 mutate + able (변화 가능한)의 뜻이므로 변할 수 없는 => 불변이라는 말이 됨.

String 클래스의 객체는 Heap 상에 생성될 경우 한번 생성된 객체의 내부 내용을 변화시킬 수 없다는 뜻.

StringBuffer나 StringBuilder는 초기에 생성할 때 Buffer Size를 주도록 구성되며 이에 의한 생성, 확장 오버로드가 걸리기 때문에 의외로 Buffer Size를 잘못 지정할 경우 성능이 떨어질 가능성도 있음.

String 클래스의 경우 new 에 의한 생성이 아닐 때 초기 컴파일러 분석단계에서 literal 처리에 의해 최적화가 될 수 있기 때문에 오히려 빠른 결과를 보여줄 때가 있음.

그냥 생각나는 대로 주절 주절 해본건데... 박재성 교수도 익히 잘 알고 있는 사항일것으로 판단해보네 ㅋ

2014-04-29 09:39

[Java 5에서 String Concatenation과 StringBuffer의 속도 비교]

http://www.mimul.com/pebble/default/2008/09/28/1222607880000.html

[Java Tips - String, StringBuffer, StringBuilder 선택 기준]

http://www.mimul.com/pebble/default/2007/11/26/1196088660000.html

조금이라도 도움이 될까해서 링크 걸어봅니다. 2007년 기준이니깐 지금도 유효한지 모르겠네요. JDK1.6 이상이 어떻게 바뀌었을지에 따라서 성능이나 이런 부분에 차이가 있을 것 같습니다.

2014-05-21 01:36

위 글들을 읽고 직접 실험을 해 봤습니다. (1) String에 += 'a'; 를 반복 (2) StringBuffer로 같은 실험

제 시스템(우분투 14.04 - JDK7 기준) 에서는 여전히 StringBuffer가 String보다 매우 빨랐습니다. 예상한 결과와는 다르게 나왔네요.

2014-11-20 18:24

문자열 최적화라는 것 때문에 다른 결과라고 착각을 하게 만든 것입니다. 컴파일되었을 때

String query = "SELECT " + "a.userName, " + "a.registerDate, " + "sum(a.duration), " + "a.id " + "FROM " + Test.class.getName() + " as a " + "ORDER BY " + "a.registerDate desc";

구문은

String query = "SELECT a.userName, a.registerDate, sum(a.duration), a.id FROM " + Test.class.getName() + " as a " + "ORDER BY " + "a.registerDate desc";

과 같게 됩니다.

2016-09-28 22:55

@자바지기 한참 지난 글이지만... 해당 포스트를 보고 의문점이 생겨 테스트를 해보았습니다.

실무에서 런타임에 문자열이 조합되는 경우도 자주 발생하는 케이스같은데...

런타임의 경우에는 + 연산자의 연산속도가 현저하게 느려짐을 확인하였습니다.

http://blog.naver.com/freeofspace/220823372682

확인을 안했으면.. 앞으로 + 연산자만 사용하다가 사고를 칠수도 있었을 것 같습니다.

혹시 저의 테스트 코드에 문제가 있으시면 알려주십시오.

의견 추가하기

연관태그

← 목록으로