devnoong.log
728x90

String vs StringBuilder vs StringBuffer 

 

위의 세 클래스는 모두 문자열을 관리하고 저장하는 클래스입니다.
다만, 약간의 차이와 성능적인 면에서 다른 점을 보입니다.

 

String

String 클래스는 불변(immutable)객체라는 큰 특징이 존재합니다.

String 클래스는 문자열을 저장하기 위해서 내부적으로 'char' 배열을 사용하여 저장하는데, 

저장하는 char [] 를 보면 final 로 선언되어 있는 점을 확인 할 수 있습니다.

 

즉, String 객체는 불변객체이므로 문자열 연산이 수행될때마다 새로운 'String' 객체가 생성되며 객체의 해시코드 값이 계산됩니다. 

이러한 해시코드 값은 최초 한번만 계산되어 캐싱 되어 메모리에 저장하고 있습니다.

 

단, 새로운 String 객체가 생성되었다고해서 해시코드 값이 새로 계산되는 것은 아니고

 같은 문자열이 존재하는 String 객체가 생성되었을 경우에는 이전에 저장해둔 해시코드값을 기존 그대로 사용합니다. 

 

따라서 동일한 문자열을 포함하는 String 객체는 동일한 해시코드 값을 가지게 됩니다.

 

그러나 문자열 연산 (+=) 자를 이용해서 변경했을 경우에는 새로운 해시코드값이 계산됩니다.

 

         String st = new String("TEST");

        System.out.println("hashCode 값 ="+st.hashCode()); //2571410
        System.out.println("hashCode 값 ="+ st.concat("new Test").hashCode()); //-792425020
        System.out.println("hashCode 값 ="+(st+= "new Test").hashCode()); //-792425020

 

반복적으로 문자열을 이어 붙이면 Heap 영역에 참조를 잃은 문자열 객체가 계속해서 쌓이게 됩니다.

이는 메모리 관리 측면에서 결코 좋다고 할 수 없고, 연산 속도적인 측면에서도 문제가 발생합니다.

 

이러한 문제점으로 인해 JDK 1.5 이상에서는 컴파일 단계에서 내부적으로 StringBuilder로 변경되어 동작하고 있습니다.

 

 

StringBuilder

반대로 StringBuilder 클래스는 가변(mutable)객체입니다.

가변객체이므로 문자열을 더하거나, 수정하거나,삭제하는 등의 작업을 보다 쉽게 수행 할 수 있습니다.

 

StringBuilder는 내부적으로 문자열을 저장할 버퍼를 가지고 있으며, 이 버퍼의 크기는 필요에 따라 동적으로 늘어 날 수 있습니다.

버퍼의  초기 용량을 지정하지 않으면, 기본값인 16으로 버퍼 크기가 설정됩니다.

 

문자열을 append 메서드를 이용해 추가할때는 내부 퍼버에 문자열을 추가하므로, 새로운 객체를 생성하지 않고 동일한 해시코드 값을 유지합니다.

        StringBuilder sb = new StringBuilder();
        System.out.println(sb.hashCode()); //1435804085
        sb.append("test");
        System.out.println(sb.hashCode()); //1435804085

 

String VS StringBuilder

 

위에서 언급했듯이 String의 문제점을 개선하기 위해 JDK 1.5이상에서는 컴파일 단계에 StringBuilder로 변환하여 동작됩니다.

 

따라서 JDK1.5 이상이라면 String 클래스를 쓰나 StringBuilder를 쓰나 큰 차이점은 존재하지 않습니다.

JDK 1.5 밑이라면 StringBuilder 사용을 권장하고 있습니다.

 

 

StringBuffer

StringBuilder와 동일하게 가변(mutable) 객체로 가변적으로 문자열을 다룰 수가 있습니다.

차이점은 StringBuffer는 Thread-safe로 동시에 여러 스레드에서 사용해도 내부적으로 스레드 동기화를 수행하기때문에 안전하게 동작합니다.

       StringBuffer sb = new StringBuffer(); // 빈 문자열 버퍼 생성
        System.out.println("hashCode 값 ="+sb.hashCode()); //1784662007
        sb.append("Hello"); // 문자열 추가
        System.out.println("hashCode 값 ="+sb.hashCode()); //1784662007
        sb.append(" ");
        System.out.println("hashCode 값 ="+sb.hashCode()); //1784662007
        sb.append("world");
        System.out.println("hashCode 값 ="+sb.hashCode()); //1784662007
        sb.append("!");
        System.out.println("hashCode 값 ="+sb.hashCode()); //1784662007

 

StringBuilder VS StringBuffer

 

StringBuilder와 StringBuffer 클래스는 모두 가변적인 문자열을 처리하는 클래스입니다.

StringBuffer 는 스레드 안정성을 보장하지만, StringBuilder는 스레드 안정성을 보장하지 않습니다.

대신   단일 스레드 환경이라면 속도차이면에서는 StringBuilder가 더 빠르게 동작합니다.

 

그러나 최근 자바 버전에서는 StringBuilder 클래스도 내부적으로 스레드를 안전하게 구현하는 방식을 사용하기때문에 성능 차이가 크게 존재하지는 않습니다.

 

따라서 스레드 안정성이 필요한 경우에 StringBuffer를 사용하고, 그렇지 않은 경우에 StringBuilder를 사용하면 됩니다.

최근 자바 버전에서는 StringBuffer의 사용 빈도가 감소하고 있으며, 대부분의 경우 StringBuilder를 사용하는 것이 일반적입니다.

 

String VS StringBuilder VS StringBuffer

모두 문자열을 다루는 클래스지만 각각 상황에 맞게 적절한 클래스를 사용해야됩니다.

 

String
- 문자열이 변경되지 않을 때
- 문자열 연산이 많지 않은 경우

 

StringBuilder
- 단일 스레드 환경에서 문자열을 동적으로 변경해야 할때
- 문자열 연산이 빈번한 경우
- 스레드 안정성이 필요하지 않은 경우

 

StringBuffer
- 멀티 스레드 환경에서 문자열을 동적으로 변경해야 할때
- 문자열 연산이 빈번한 경우
- 스레드 안정성이 필요한 경우

 

즉, 정리를 해보자면 문자열이 변경되지 않거나 문자열이 많지 않은경우에는 String을 사용하면됩니다.

문자열을 동적으로 변경해야하고, 스레드 안정성이 필요하지 않다면 StringBuilder를 사용합니다.

스레드 안정성이 필요한 경우에 StringBuffer를 사용합니다.

 

 

728x90