반응형

처음 대학에 들어가 c언어를 배우면서 일상에서 쉽게 사용하던 문자열들이 굉장히 어렵게 처리했던것들이 기억난다. char형의 배열로 문자열형태를 만들고 제어했는데, 자바는 String 클래스 하나면 문자열을 저장하고 합치고 필요한 메소드를 사용해 제어가 가능하다.

 

불과 작년까지 String을 자바의 기본 자료형(primitive type)으로 착각하고 문자열처리는 String 클래스로만 가능할 것이라고 생각했던 것에 반성하며 String, StringBuffer, StringBuilder클래스에 대해 정리해본다.

 

String

String 클래스는 일단 변경 불가능한 클래스(immutable)이다.

쉽게 String클래스에 문자열을 넣어 사용하지만 실제로는 다른 언어처럼 char[] 배열 변수를 인스턴스 변수로 받아서 저장이 된다.

final 상수로 String을 처리하였다.(불변 객체 String)

"Test"+ "Sum" = "TestSum" 이런식으로 String으로 쉽게 문자열들을 합쳐왔을텐데, 인스턴스 내의 문자열이 바뀌는게 아닌 TestSum이라는 새로운 문자열이 생성되는 것이다.

 

String의 문자열 비교는 equals()

여기서 우리가 자주 쓰던 조건문의 eqauls() 사용하는 이유가 나오는데, 문자열은 생성할때 새로운 인스턴스를 생성하고 메모리에 저장한다.

 

public class Test {

	public static void main(String[] args) {
		String a = "test1";
		String b = "test";
		String c = "1";
		String d = b + c;
		
		if(a == d) {
			System.out.println("같아요");
		}else {
			System.out.println("같지 않아요");
		}
		
		if(a.equals(d)) {
			System.out.println("같아요");
		}else {
			System.out.println("같지 않아요");
		}
	}
}

같지 않아요 // 같아요

 

당연히 equals로 비교하지 않았기 때문에 else를 탄다는것을 알지만 왜? 가 여기서 이해가 될 것이다.

test라는 문자열을 생성하고 1을 생성 후 둘을 합치면서 새로운 test1이라는 문자열을 만들었기때문에 둘의 생성된 메모리의 주소값은 다르다. 그래서 두 변수의 문자열의 값만 비교하는 eqauls()를 통해 boolean값을 얻는다.

 

계속해서 말하는 내용이지만 결합이나 추출 등의 작업이 나오면 새로운 문자열이 생성된다. 즉, 문자열을 합칠때마다 새로운 문자열을 만들기 위해 인스턴스를 생성하고 메모리를 잡아먹는다.

문자열의 결합, 추출 등의 작업이 필요하다면 String이 아닌 StringBuffer를 통해 처리하는것이 시스템상 좋을 것이다. 왜? 인스턴스를 매번 생성하고 메모(간단하게 합치고 추출정도는 현대의 컴퓨터 연산과 메모리에 큰 영향이 없으므로 상관 없을것같다.)

 

 

 

StringBuffer

StringBuffer는 불변객체가 아니다. 내부적으로 buffer를 가지고 있는데,

StringBuffer 인스턴스를 생성할때는 적절한 길이의 char형 배열이 생성되고, 이 배열은 문자열을 저장하고 편집할때 사용하는 buffer가 된다.

 

기본 사이즈는 16

여기서 적절한 길이를 지정해야 하는 이유는, 수정하는 문자열이 버퍼의 길이를 넘어가면 버퍼의 길이를 늘려주는 작업이 추가되기 때문이다. 배열은 길이를 바꿀수 없기때문에 이전에 작업하던 배열의 값을 복사해서 넣어준다.

 

StringBuffer의 문자열 비교

StringBuffer의 equals는 String의 equals와는 다르게 (==) 비교 연산이라 문자열 비교시 원하는 결과를 얻을 수 없다.

toString()을 통해 String인스턴스화를 거친 후 비교를 한다.

public class Test {

	public static void main(String[] args) {
		StringBuffer sb = new StringBuffer("test1");
		StringBuffer sb2 = new StringBuffer("test1");
		if(sb.equals(sb2)) {
			System.out.println("같아요");
		}else {
			System.out.println("같지 않아요");
		}
		
		String str1 = sb.toString();
		String str2 = sb.toString();
		if(str1.equals(str2)) {
			System.out.println("같아요");
		}else {
			System.out.println("같지 않아요");
		}
	}
}

같지 않아요 // 같아요

 

StringBuffer의 문자열 합치기, 추출, 제거하기

문자열 합치기

StringBuffer에는 append()메소드가 존재한다. 해당 메소드를 통해 문자열을 추가할 수 있다.

StringBuffer sb = new StringBuffer("a");
sb.append("b"); //ab
sb.append("c").append("d").append("e"); //abcde
System.out.println(sb); //abcde

"abcde"

 

위 캡처처럼 계속 연결해서 사용할 수도 있다.

 

 

문자열 제거

delete(), deleteCharAt() 메소드를 통해 문자열을 지우거나 특정 문자를 제거할 수도 있다.

StringBuffer sb = new StringBuffer("abcde");
sb.delete(0, 2);
System.out.println(sb); //cde

"cde"
"abd"

 

 

문자열 추출

String의 substring의 StringBuffer에도 존재한다. 사용법은 동일하다.

StringBuffer sb = new StringBuffer("hello world!");
String str1 = sb.substring(6); //world!
String str2 = sb.substring(0, 5); //hello

"hello"

 

 

문자열 역순처리

reverse()메소드는 문자열을 거꾸로 나열할 수있다.

StringBuffer sb = new StringBuffer("!dlrow olleh");
sb.reverse(); //reverse
System.out.println(sb); //hello world!

문자열 역순처리로 hello world! 출력

 

 

 

StringBuilder

StringBuilder는 기본적으로 사용하는 메소드나 사용법은 동일하여 서로 호환이 됩니다.(append(), delete(), reverse() 등)

StringBuffer와의 차이점은 동기화를 하는지 않하는지의 차이인데

StringBuffer - 동기화O // StringBuilder - 동기화X

싱글쓰레드 환경에서의 개발이라면 StringBuilder를 멀티쓰레드 환경이라면 동기화처리가된 StringBuffer를 사용하면 됩니다.

즉, StringBuffer의 동기화 처리를 빼고 만들어진 클래스가 StringBuilder입니다.

 

그럼 무시하고 무조건 StringBuffer만 쓰면 되는것이 아니냐? 라고 물어볼 수도 있지만...

동기화처리는 시스템의 불필요하게 성능만 느리게 하므로 차이를 알고 사용하는게 시스템 성능향상에 도움이 될 것입니다.

 

 

반응형