[딴짓글] String의 + 와 StringBuffer에 대해…
많은 곳에서 String의 + 보다 StringBuffer를 사용하는것이 성능에 더 좋다고 얘기한다.
(String의 + 연산은 내부적으로 StringBuffer로 처리한 후 toString()한다.)
그리고 이를 본 일부 개발자는 무조건 StringBuffer로만 코딩을 하려고 한다.
StringBuffer의 사용은 성능에는 좋을지 모르나 소스의 가독률은 낮아진다.
내가 지금까지 코딩을 하면서 긴문장의 String을 많이 사용했던 곳이 쿼리를 작성할때였다.
아래와 같은 코드일 것이다.
—————————————————-
String a = “AAA”;
String query = “select A, B, C, D, E, F \n”
+ “from TABLE \n”
+ “where A=’” + a + “‘ \n”;
—————————————————-
공백을 넣어 줄을 맞춘 이유는 소스에서 쿼리를 복사하기가 편하고 보기에도 좋다.
\n을 넣은 이유는 로그를 보기 편하게 하기 위해서다.
(프로젝트를 하면서 소스나 로그에서 쿼리를 따서 직접 던져보는 작업을 많이 한다.
이때 에디터의 컬럼모드 기능을 사용하면 편리하다.)
이를 javap로 확인하면 결과는 다음과 같다.
(javap는 class가 실행될때 VM이 실제로 어떻게 동작하는지를 보여준다.
사용 : javap -c 클래스명)
—————————————————-
0: ldc #2; //String AAA
2: astore_1
3: new #3; //class StringBuffer
6: dup
7: invokespecial #4; //Method java/lang/StringBuffer.”<init>”:()V
10: ldc #5; //String select A, B, C, D, E, F \nfrom TABLE \nwhere A=’
12: invokevirtual #6; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
15: aload_1
16: invokevirtual #6; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
19: ldc #7; //String ‘ \n
21: invokevirtual #6; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
24: invokevirtual #8; //Method java/lang/StringBuffer.toString:()Ljava/lang/String;
27: astore_2
28: return
—————————————————-
10: 를 보면
”select A, B, C, D, E, F \n”
+ “from TABLE \n”
+ “where A=’”
가
“select A, B, C, D, E, F \nfrom TABLE \nwhere A=’”
로 1개의 String으로 만들어지는걸 볼수 있다.
(class를 jad로 역컴파일한 java소스에는 하나로 합쳐져 있다.
아마 컴파일단계에서 합치는걸로 보여진다.)
위 코드의 javap의 결과가 비슷한 StringBuffer형태는 다음과 같다.
—————————————————-
String a = “AAA”;
StringBuffer buf = new StringBuffer();
buf.append(”select A, B, C, D, E, F \nfrom TABLE \nwhere A=’”)
.append(a).append(”‘ \n”);
String query = buf.toString();
—————————————————-
StringBuffer형태의 코드를 보기 좋게 만들어보면
—————————————————-
StringBuffer buf = new StringBuffer();
buf.append(”select A, B, C, D, E, F \n”);
buf.append(”from TABLE \n”);
buf.append(”where A=’”).append(a).append(”‘ \n”);
String query = buf.toString();
—————————————————-
이를 javap로 확인하면
“select A, B, C, D, E, F \n”
“from TABLE \n”
“where A=’”
가 3개의 String으로 처리된다.
——————————————————
String query = “select A, B, C, D, E, F \n”
+ “from TABLE \n”
+ “where A=’” + a + “‘ \n”;
——————————————————
StringBuffer buf = new StringBuffer();
buf.append(”select A, B, C, D, E, F \n”);
buf.append(”from TABLE \n”);
buf.append(”where A=’”).append(a).append(”‘ \n”);
String query = buf.toString();
——————————————————
이 두 코드는 첫번째 코드가(String +)가 여러모로 더 좋은 결과를 가져온다.
하지만,
String query = “”;
query += “select A, B, C, D, E, F \n”;
query += “from TABLE \n”;
query += “where A=’” + a + “‘ \n”;
이러한 코딩을 한다면 얘기는 달라진다.
StringBuffer는 +가 있는 한문장(;)마다 새로 만들어질것이다.
위는 총 3개가 만들어진다.
String query = “”;
for (int i=0; i<size; i++) {
query += “”;
}
이런 코드는 size가 크면 클수록 많은 성능 차이를 보일것이다.
(많다고 해봐야 몇십초가 더 걸리는것도 아니다. 하드웨어가 좋아져서…)
결론
여러곳의 String의 + 와 StringBuffer의 비교 글에서 “A” + “B” 가 “AB”로 되는것에 대한 언급이 없고
javap도 한번 사용해보라고 이 글을 썻습니다.
자기만의 코딩스타일이 있고 이것이 프로그램에 더 효율적인 방식이라 하더라도
코딩하기 편하고 가독률이 좋은 코드라면 약간의 성능저하는 무시할 수도 있지 않나 생각합니다.