본문 바로가기
Programing General/Java

[java] String, Stringbuffer, Stringbuilder 차이점 및 성능비교

by Gnaseel 2019. 12. 1.
728x90
반응형

1. String의 메소드 concat과 +연산자의 동작방식

String의 concat과 +연산자가 어떻게 동작하는지 살펴보자.

    String strNull=null;
    String str = "aaaa";
    String str2 = "bbbb";

    System.out.println(str.concat(str2));
    System.out.println(str+str2);

    //System.out.println(strNull.concat(str2));
    System.out.println(strNull+str2);

결과

aaaabbbb
aaaabbbb
nullbbbb

첫 번째 예시에서는 String의 concat과 +연산자의 결과값이 같다.
하지만 두 번째 예시는 concat메소드에서만 NullPointerException가 발생한다.
게다가 null이 문자처럼 변환되었다.
concat과 +연산자 사이에 어떤 차이점이 존재해서 후자만 정상적으로 작동하는 것일까.

concat의 작동방식

concat은 새로운 메모리를 할당받아서 두 문자열을 결합한 새로운 문자열을 저장한다.
str의 위치에 str2의 값을 추가하는게 아니라, 새로운 위치에 메모리를 할당하고, str과 str2를 더한 값을 추가하는 것이다.

+연산자의 작동방식

+연산자는 Stringbuilder처럼 작동한다.
즉 String을 +로 더하면 Stringbuilder처럼 컴파일 되는 것이다.
이 때 +연산자가 Stringbuilder의 append메소드처럼 치환되는 과정에서 재미있는 일이 발생한다.

        String strNull=null;
        int i = 50;

        System.out.println(strNull+i);
        //System.out.println(str.concat(i)); 에러 발생

결과

null50

null 문자열에 int형 데이터를 더했는데 null50이 출력되었다.
append메소드는 int형 파라미터에 대해 오버로딩이 되어있기 때문에 concat에서는 불가능하던 형태의 연산까지 수행할 수 있다.
그리고 append메소드의 정의를 찬찬히 살펴보면 아까부터 궁금했던 null이라는 문자열이 출력되는 이유도 설명된다.

public java.lang.AbstractStringBuilder append (String str)
Appends the specified string to this character sequence.
The characters of the String argument are appended, in order, increasing the length of this sequence by the length of the argument. If str is null, then the four characters "null" are appended.

마지막 문장을 해석해보면 더해지는 문자열이 null일 경우 4개의 charters "null"을 더한다고 정의되어있다.
그렇기 때문에 null값에 대해서도 연산이 가능한 것이다.

concat과 +연산자에서 찾은 String과 Stringbuilder의 결론

concat은 사용시마다 새로 메모리를 할당하고, 이전 메모리가 JVM의 가비지컬렉터에 의해 처리되어야한다.
즉 성능면에서 매우 불리하다.

그렇다면 Stringbuilder만 쓰면 되는데 왜 굳이 String을 쓸까?
그것은 String의 immutable속성 때문이다. Stringbuilder와 다르게 String은 immutable속성 덕분에 절대 값이 바뀌지 않는다.
concat을 보면 이해가 쉬운데, 값이 바뀔 일이 있으면 메모리를 새로 할당받아서 바뀐 값을 주입하고 취하는 것이다.
즉 동일 메모리에서 불변함을 유지하는 특성을 갖는 것이다.
이 특징 때문에 String은 멀티 스레드 매우 안전하다. 아무리 많은 스레드에서 String의 값을 다뤄도 동기화가 보장되는 것이다.(값이 바뀔일이 없으니...)

아니 그러면 Stringbuffer는 뭐야?

Stringbuffer은 Stringbuilder가 갖는 멀티 스레드에서의 취약점을 보완하기 위해 만들어진 클래스이다.
Stringbuffer은 멀티 스레드에서 매우 안전하며 String보다 빠른 연산속도를 자랑한다.
즉 Stringbuilder는 단일 스레드에서 제일 빠른 성능을 자랑하고,
Stringbuffer는 멀티 스레드에서 성능이 빛을 발하는 것이다.

그러면 String은 왜 존재하지?

Stringbuilder나 Stringbuffer를 사용한다고 하더라도 toString을 사용해 String으로 변환하는 과정을 거쳐야 하고,
단순 조회 성능은 String이 앞서기 때문에 조회 작업이 많은경우 String을 사용하는게 현명하다.

반응형