본문 바로가기
CS/Java

String & StringBuffer & StringBuilder

by cornsilk-tea 2023. 6. 20.

String

 

String (Java Platform SE 8 )

Compares two strings lexicographically. The comparison is based on the Unicode value of each character in the strings. The character sequence represented by this String object is compared lexicographically to the character sequence represented by the argum

docs.oracle.com

1. 불변성

위 이미지는 스트링이 상수, 즉 불변객체라는 말을 하고 있다.

Strings are constant; their values cannot be changed after they are created.

문자열은 상수이며; 그들의 값은 생성된 후에 변경될 수 없다

예제코드

String str = "Hello";
System.out.println(System.identityHashCode(str)); // 27416648
str = str + " World";
System.out.println(System.identityHashCode(str)); // 26648510

String은 이렇게 새롭게 만들 때마다 새로운 String객체가 생성되기 때문에,

문자열 연산이 많은 경우는 StringBuffer나 StringBuilder를 사용해야 한다.

자세한 내용은 가장 마지막에 확인해 보자.

2. 문자열 연결 방식

문자열 연결 연산자(+)에 대한 설명은 다음과 같이 말하고 있다.

String concatenation is implemented through the StringBuilder(or StringBuffer) class and its append method

문자열 연결은 StringBuilder(또는 StringBuffer) 클래스와 그것의 append 메서드를 통해 구현된다


StringBuffer

 

StringBuffer (Java Platform SE 8 )

Inserts the string into this character sequence. The characters of the String argument are inserted, in order, into this sequence at the indicated offset, moving up any characters originally above that position and increasing the length of this sequence by

docs.oracle.com

 

1. 변경 가능

A string buffer is like a String, but can be modified. At any point in time it contains some particular sequence of characters, but the length and content of the sequence can be changed through certain method calls.

문자열 버퍼는 문자열과 비슷하지만 수정이 가능합니다. 어느 시점에서든 특정 문자 시퀀스를 포함하지만 특정 메서드 호출을 통해 시퀀스의 길이와 내용을 변경할 수 있습니다.

예제코드

StringBuffer sb = new StringBuffer("Hello");
System.out.println(System.identityHashCode(sb));// 12844427
sb.append(" World");
System.out.println(System.identityHashCode(sb)); // 12844427

 

2. 동기화 가능

String buffers are safe for use by multiple threads. The methods are synchronized where necessary so that all the operations on any particular instance behave as if they occur in some serial order that is consistent with the order of the method calls made by each of the individual threads involved.

문자열 버퍼는 여러 스레드에서 사용하기에 안전합니다. 메서드는 필요한 경우 동기화되어 특정 인스턴스의 모든 작업이 관련된 각 개별 스레드의 메서드 호출 순서와 일치하는 직렬 순서로 발생하는 것처럼 동작합니다.

 

3. StringBuffer보다 StringBuilder??

As of release JDK 5, this class has been supplemented with an equivalent class designed for use by a single thread, StringBuilder. The StringBuilder class should generally be used in preference to this one, as it supports all of the same operations but it is faster, as it performs no synchronization.

JDK 5 릴리스부터 이 클래스는 단일 스레드에서 사용하도록 설계된 동등한 클래스인 StringBuilder로 보완되었습니다. 동일한 연산을 모두 지원하지만 동기화를 수행하지 않기 때문에 더 빠르므로 일반적으로 이 클래스보다 StringBuilder 클래스를 우선적으로 사용해야 합니다.

이와 같은 특징 때문에 동기화가 필요 없는 경우에는 StringBuffer를 우선적으로 사용해야 한다.


StringBuilder

 

StringBuilder (Java Platform SE 8 )

Inserts the string into this character sequence. The characters of the String argument are inserted, in order, into this sequence at the indicated offset, moving up any characters originally above that position and increasing the length of this sequence by

docs.oracle.com

1. 변경 가능

A mutable sequence of characters. This class provides an API compatible with StringBuffer, but with no guarantee of synchronization.

변경 가능한 문자 시퀀스입니다. 이 클래스는 StringBuffer와 호환되는 API를 제공하지만 동기화를 보장하지는 않습니다.

예제코드

StringBuilder sbr = new StringBuilder("Hello");
System.out.println(System.identityHashCode(sbr)); // 27416648
sbr.append(" World");
System.out.println(System.identityHashCode(sbr)); //27416648

 

2. 동기화 불가능

Instances of StringBuilder are not safe for use by multiple threads. If such synchronization is required then it is recommended that StringBuffer be used.

StringBuilder의 인스턴스는 여러 스레드에서 사용하기에 안전하지 않습니다. 이러한 동기화가 필요한 경우 StringBuffer를 사용하는 것이 좋습니다.


결론

분류 String StringBuffer StringBuilder
변경 가능? 불변! 변경 가능! 변경 가능!
동기화 가능?   가능! 불가능!

 


번외

실제로 문자열 연산이 빈번할 시엔 String보다 StringBuilder를 사용하는 것이 유리할까?

실행시간과 메모리 사용량을 기준으로 알아보자.

1. 실행시간 측정

long startTime, endTime;

// 'String'을 사용한 경우 실행 시간 측정
startTime = System.currentTimeMillis();
String str = "Hello";
for(int i = 0; i < 10000; i++) {
    str += " World";
}
endTime = System.currentTimeMillis();
System.out.println("String을 사용한 경우 실행 시간: " + (endTime - startTime) + "ms");

// 'StringBuilder'를 사용한 경우 실행 시간 측정
startTime = System.currentTimeMillis();
StringBuilder sb = new StringBuilder("Hello");
for(int i = 0; i < 10000; i++) {
    sb.append(" World");
}
endTime = System.currentTimeMillis();
System.out.println("StringBuilder를 사용한 경우 실행 시간: " + (endTime - startTime) + "ms");
---------------------------------------------------------------------------------------
String을 사용한 경우 실행 시간: 57ms
StringBuilder를 사용한 경우 실행 시간: 1ms

2. 메모리 사용량 측정

Runtime runtime = Runtime.getRuntime();
long usedMemoryBefore, usedMemoryAfter;

// 'String'을 사용한 경우 메모리 사용량 측정
runtime.gc(); // 가비지 컬렉터 실행하여 메모리 초기화
usedMemoryBefore = runtime.totalMemory() - runtime.freeMemory();
String str = "Hello";
for(int i = 0; i < 10000; i++) {
    str += " World";
}
usedMemoryAfter = runtime.totalMemory() - runtime.freeMemory();
System.out.println("String을 사용한 경우 메모리 사용량: " + (usedMemoryAfter - usedMemoryBefore) + " 바이트");

// 'StringBuilder'를 사용한 경우 메모리 사용량 측정
runtime.gc(); // 가비지 컬렉터 실행하여 메모리 초기화
usedMemoryBefore = runtime.totalMemory() - runtime.freeMemory();
StringBuilder sb = new StringBuilder("Hello");
for(int i = 0; i < 10000; i++) {
    sb.append(" World");
}
usedMemoryAfter = runtime.totalMemory() - runtime.freeMemory();
System.out.println("StringBuilder를 사용한 경우 메모리 사용량: " + (usedMemoryAfter - usedMemoryBefore) + " 바이트");
---------------------------------------------------------------------------------
String을 사용한 경우 메모리 사용량: 1404936 바이트
StringBuilder를 사용한 경우 메모리 사용량: 232488 바이트

실행 시간과 메모리 사용량을 비교해 보아도 String보다 StringBuilder가 더 유리한 것을 확인할 수 있다.