[JAVA] String / StringBuilder / StringBuffer 차이점

String 클래스

String 클래스는 불변(immutable)한 문자열을 표현하는 데 사용됩니다. 한 번 생성된 문자열은 변경될 수 없으며, 문자열 조작 시 새로운 문자열 객체가 생성됩니다.

 

StringBuilder 클래스

StringBuilder 클래스는 가변(mutable)한 문자열을 효율적으로 처리하는 데 사용됩니다. 문자열을 변경할 때 새로운 객체를 생성하지 않고 기존 객체 내에서 조작이 이루어지므로 성능이 향상됩니다. 그러나 스레드 안전성을 보장하지 않습니다.

 

StringBuffer 클래스

StringBuffer 클래스는 StringBuilder와 유사하게 가변 문자열을 다루는 데 사용됩니다. 하지만 StringBuffer는 스레드 안전성을 보장하도록 설계되었습니다. 따라서 멀티스레드 환경에서 문자열 조작이 필요한 경우에는 StringBuffer를 사용하는 것이 안전합니다. 성능 측면에서는 StringBuilder보다 약간 느릴 수 있습니다.

 

정리

String  StringBuilder  StringBuffer 
불편 가변 가변
스레드 안정성 o 스레드 안전성 x 스레드 안전성 o

 

StringBuilder와 StringBuffer의 속도 차이 예제

컴퓨터 환경마다 다를 수 있습니다.

public class Example {
	public static void main(String[] args) {
    	int n = 100000;
        long startTime, endTime;
        
        StringBuffer stringBuffer = new StringBuffer();
        startTime = System.nanoTime();
        for (int i = 0; i < n; i++) {
            stringBuffer.append(1);
        }
        endTime = System.nanoTime();
        long stringBufferTime = endTime - startTime;
        // stringBufferTime : 6461700 ns
        
        StringBuilder stringBuilder = new StringBuilder();
        startTime = System.nanoTime();
        for (int i = 0; i < n; i++) {
            stringBuilder.append(1);
        }
        endTime = System.nanoTime();
        long stringBuilderTime = endTime - startTime;
        // stringBuilderTime : 1611400 ns
    }
}

 

StringBuilder와 StringBuffer의 스레드 안정성 차이 예제

컴퓨터 환경마다 다를 수 있습니다.

public class Example {
	public static void main(String[] args) {
    	int n = 100000;
        
        StringBuffer stringBuffer = new StringBuffer();
        Runnable stringBufferTask = () -> {
            for (int i = 0; i < n; i++) {
                stringBuffer.append(1);
            }
        };
        
        Thread thread1 = new Thread(stringBufferTask);
        Thread thread2 = new Thread(stringBufferTask);
        
        thread1.start();
        thread2.start();
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        // stringBuffer.length() : 200000        
        
        StringBuilder stringBuilder = new StringBuilder();
        Runnable stringBuilderTask = () -> {
            for (int i = 0; i < n; i++) {
                stringBuilder.append(1);
            }
        };
        
        Thread thread3 = new Thread(stringBuilderTask);
        Thread thread4 = new Thread(stringBuilderTask);
        
        thread3.start();
        thread4.start();
        try {
            thread3.join();
            thread4.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        // stringBuffer.length() : 115539       
    }
}

10만번을 2개의 쓰레드로 실행하였을때 예상 결과값 20만번이 나와야합니다.

StringBuffer는 20만번이 나왔지만 StringBuilder는 2개의 쓰레드가 동시에 접근하여 수행했기 때문에 20만번보다 더 적게 append되었습니다.