본문 바로가기

JAVA/Coding Habit

[Story 04] 왜 자꾸 String 을 쓰지 말라는 거야?


음 이번 Story 는 내가 가장 궁금해 했던 사항이 었던 String 에 대한 부분이다.
개발할때 쿼리문이 여러 줄 나오곤 하는데, 그 때 마다 각 개발자 들은 String 이 속도가 더 잘나온다.
StringBuffer 가 속도가 더 잘나온다 . 하며 개발자들마다 의견이 분분했는데....

결과 부터 말하자면, String 대신에 StringBuffer 나 StringBuilder 를 써야 한다는 것이다.!



String 으로 작성하는 Query 예

String strSql = "";

strSql += "select * ";
strSql += "from ( ";
strSql += " select a_column, ";
strSql += " b_column, ";
//중간생략 ( 약 400 라인 ).....
.....

이런식으로 작성되기 마련인데, 개발시에는 좀 편할지 몰라도 메모리를 많이 사용하게 된다.

문자열을 더하는 4개 라인과 같은 패턴을 100회 수행한다는 가정(총 400라인 수행) 하에 이 메소드를 한번 수행하면,
약 10회 평균 5MB 의 메모리 사용량이 나오며 응답시간은 약 10회 평균 약 5ms 가 나온다.

이 문을 StringBuilder 로 변경해 보자.

StringBuilder strSql = new StringBuilder();

strSql.append ( "select * ");
strSql.append ( " from ( ");
strSql.append ( "  select a_column,  ");
strSql.append ( " b_column , ");
//중간생략 (약 400라인).........
.............


동일하게 변경 한후 메모리 사용량은 약 10회평균 371KB , 응답시간은 10회평균 평균 약 0.3ms 가 나왔다.

* StringBuffer 클래스와 StringBuilder 클래스

StringBuilder 클래스는 JDK 5.0 에서 새로 추가된 클래스이다.
StringBuffer 클래스나 StringBuilder 클래스에서 제공하는 메소드는 동일하다.

StringBuffer 클래스
: 스레드에 안전하게 설계 (ThreadSafe)
여러개의 스레드에서 하나의  StringBuffer 객체를 처리해도 전혀 문제가 되지 않는다.

StringBuilder 클래스
: 단일 스레드에서의 안전성망을 보장
여러개의 스레드에서 하나의 StringBuilder 객체를 처리하면 문제가 발생한다.

####### 사용 ########

StringBuffer sb = new StringBuffer();

// 이렇게 사용해도 되고
sb.append(" ABCDEF ");
sb.append(" GFEFEF ");
sb.append(" WEFWEFWE ");

// 이렇게 사용해도 된다.
sb.append(" ABCDEF ")
    .append( "  GFEFEF ")
    .append( "  WEFWEFWE ");

// 이렇게 만은 제발 사용하지 말자
 sb.append( "ABCDE" + " = " + "FEFEF ");
sb.insert( 3, "1234");

// insert() 메소드는 지정된 위치 이후에 넘어온 값을 덧붙이는 작업을 수행한다.
//insert() 메소드를 수행할 때 지정한 위치까지 값이 할당되어 있지 않으면 StringIndexOutOfBoundsException 이 발생



** append() 메소드를 사용할 때 append() 메소드 내에서 + 를 이용해 문자열을 더하면  StringBuffer 를 사용하는 효과가 전혀 없게 된다.

String 과 StringBuffer 의 원리

쉽게 그림으로 String 과 StringBuffer 의 원리를 보자면,

** String 클래스의 원리

String a 값에 계속 값을 더해가는 경우 새로운 String 클래스가 만들어 진다.




** StringBuffer 나 StringBuilder 의 원리

새로운 객체를 생성시키지 않고, 기존에 있는 객체의 크기를 증가시키면서 값을 더한다.



1.  String 은 짧은 문자열을 더할 경우 사용한다.
2.  StringBuffer 는 스레드에 안전한 프로그램이 필요할 때나,
     개발중인 시스템의 부분이 스레드에 안전한지 모를 경우 사용하면 좋다.
3.  StringBuilder  는 스레드에 안전한지 여부가 전혀 관계 없는 프로그램을 개발할 때 사용하면 좋다. 



JDK 버전에 따른 차이

JDK 5.0  이상의 WAS 를 사용한다면 결과가 약간 달라진다. 

다음과 같은 소스를  JDK 1.4 일 경우에는 아래와 동일하게 컴파일 되지만,

String s = "Here " + "is " + "samples";

JDK 1.5 일 경우 컴파일인 경우에는 다음과 같이 컴파일 된다.

String s = (new StringBuilder ("Here is")).append("samples").toString();

 결론적으로...

 String, StringBuffer, StringBuilder  이 세가지 클래스 중에서 가장 메모리를 많이 차지하고
응답시간에 많은 영향을 주는 것은 String  클래스 이다.
만약 여러분의 WAS  나 시스템이  JDK 5.0 이상을 사용한다면,
컴파일러에서 자동으로 StringBuilder  로 변환하여 준다.
하지만 반복 루프를 사용해서 문자열을 더할때에는 객체를 계속 추가해야 한다는 사실에는 변함이 없다.
그러므로  String 클래스를 쓰는대신, 스레드와 관련이 있으면  StringBuffer  를,
스레드 안전여부와 상관이 없으면  StringBuilder  를 사용하는 것을 권장한다.