본문 바로가기

Java/Java SE, EE

[Java/Java SE, EE] 문자열(String) 클래스 사용법, 상수 풀을 사용한 초기화

문자열(String)

Java의 문자열은 참조(Reference) 타입에 속하며, 문장을 저장하기 위한 데이터 타입입니다. 문자열(String 클래스)의 값을 저장하는 대표적인 방법은 다음과 같습니다.

String a = "리터럴을 사용하여 문자열을 초기화합니다.";
String b = new String("new 생성자를 사용하여 문자열을 초기화합니다.");
String c = String.valueOf("String.valueOf() 함수를 사용하여 문자열을 초기화합니다.");

문자열은 클래스임에도 불구하고, 기본(Primitive) 타입처럼 대입 연산자(=)를 사용하여 피연산자 리터럴을 변수에 저장 할 수 있다는 점이 예외적입니다. 

String 클래스 뿐만 아니라, 래퍼(Wrapper) 클래스의 사용에는 리터럴을 이용하는 것이 좋습니다. Java는 한 번 이상 사용된 리터럴을 상수 풀(Literal pool)에 등록하여 재사용 시 캐싱하기 때문에 효율적입니다.

아래 코드는 앞서 3가지 방식으로 초기화 한 String 타입의 변수에 대해서 비교 연산자(==)를 수행하고 있습니다.

String a = "abc";
String b = new String("abc");
String c = String.valueOf("abc");

System.out.println(a == b);
System.out.println(b == c);
System.out.println(c == a);

클래스는 참조 타입이기 때문에 객체(문장 "abc")에 대한 주소가 저장되어 있습니다. 변수 a는 리터럴을 사용하므로 상수 풀에 저장되어 있는 객체를 사용합니다. 변수 b는 new 연산자를 사용하며, 이렇게 초기화 한 클래스가 참조하는 객체는 새로운 메모리를 할당 받습니다. 마지막으로 변수 c의 경우 Object.valueOf() 함수를 사용하며, 이 방식은 new 연산자와 달리 상수 풀에 저장되어 있는 객체를 사용합니다.

false
false
true

따라서 실행 결과 a와 c는 상수 풀에 있는 객체를 참조하므로 동일한 주소를 갖고있으며, b는 저장하고 있는 문장은 동일하지만 다른 주소를 갖고있습니다. 이는 상수 풀에 의한 결과이므로 Boolean, Byte, Short, Integer 등 다른 래퍼 클래스에서도 완전히 동일한 결과를 보여줍니다.

equals()

두 문자열 간의 문장을 비교하는 String 클래스의 멤버 함수입니다. 문자열이 저장하고 참조하는 객체(문장)의 메모리 주소와 관계 없이, 문장의 단순 비교 결과를 리턴합니다.

리턴 비고
true 두 문장이 일치
false 두 문장이 일치하지 않음

우리가 프로그램을 작성 할 때, 문자열이 참조하는 객체의 메모리 주소를 비교 할 일은 거의 없을 것입니다. 따라서 문자열의 비교는 반드시 equals()를 사용해야 합니다(또는 유사한 다른 함수 등).

String a = "abc";
String b = new String("abc");
String c = String.valueOf("abc");

System.out.println(a.equals(b));
System.out.println(b.equals(c));
System.out.println(c.equals(a));

앞서 상수 풀에 대해서 소개한 예시에서, 3개의 변수에 대한 비교 연산자를 equals()로 변경한 코드입니다. 모두 같은 문장을 저장하고 있으므로 실행 결과는 다음과 같습니다.

true
true
true

equals()는 문장의 대소문자에 대해서 엄격하게 비교합니다. 따라서 다음과 같은 문장의 비교 결과는 false입니다.

String a = "abc";
String b = "ABC";

System.out.println(a.equals(b));		// false

equalsIgnoreCase()

두 문자열 간의 문장을 비교하는 String 클래스의 멤버 함수입니다. equals()와의 차이는 대소문자의 차이는 검사하지 않는다는 점입니다. 아래 코드처럼 문장의 내용만 일치한다면, 대소문자에서 차이가 발생하더라도 같은 문장으로 판단합니다.

String a = "abc";
String b = "ABC";
String c = "aBc";

System.out.println(a.equalsIgnoreCase(b));		// true
System.out.println(a.equalsIgnoreCase(c));		// true

contains()

문자열이 다른 문자열을 포함하고 있는지 검사하는 String 클래스의 멤버 함수입니다. 다른 문자열은 인자로 전달 받은 문자열 리터럴 또는 변수입니다.

리턴 비고
true 다른 문자열을 포함
false 다른 문자열을 포함하지 않음

대소문자를 구분하기 때문에, 같은 문장이어도 대소문자에 차이가 있다면 문자열을 포함하지 않는 것으로 판단합니다.

String a = "This is some string variable";
String b = "variable";
String c = "VarIAblE";

System.out.println(a.contains(b));		// true
System.out.println(a.contains(c));		// false

indexOf()

문자 또는 문자열이 시작되는 첫 번째 인덱스를 리턴하는 String 클래스의 멤버 함수입니다. 

리턴 비고
-1 문자 또는 문자열을 찾지 못함
0 ~ 문자 또는 문자열을 찾음

인자로 받은 문자 또는 문자열을 찾을 경우, 첫 번째 인덱스를 리턴합니다. 예시의 a.indexOf(b)는 문자열이 문자 's'를 다수 포함하고 있지만, 첫 번째에 해당하는 Thi's'의 인덱스 3을 리턴합니다. 인덱스는 첫 번째 문자를 0으로 시작하여 1씩 증가합니다. 대소문자를 ㄱ분하며, 문자 또는 문자열을 찾지 못하는 경우 -1을 리턴합니다.

String a = "This is some string variable";
String b = "s";
String c = "some";
String d = "soME";

System.out.println(a.indexOf(b));     // 3
System.out.println(a.indexOf(c));     // 8
System.out.println(a.indexOf(d));     // -1

charAt

특정 인덱스의 문자(char)를 리턴하는 String 클래스의 멤버 함수입니다. 입력 인덱스는 문자열의 첫 글자에 해당하는 0부터 시작합니다.

String a = "This is some string variable";

System.out.println(a.charAt(0));      // T
System.out.println(a.charAt(1));      // h
System.out.println(a.charAt(-1));     // String index out of range
System.out.println(a.charAt(28));     // String index out of range

만약 입력 인덱스가 0보다 작거나, 문자열의 크기보다 같거나 큰 경우 StringIndexOutOfBoundsException을 발생시킵니다.

java.lang.StringIndexOutOfBoundsException: String index out of range: -1

length

문자열의 길이를 리턴하는 String 클래스의 멤버 함수입니다. 문자열의 인덱스는 0부터 시작하므로, 마지막 문자의 인덱스는 String.length() - 1입니다.

String a = "This is some string variable";

System.out.println(a.length());          // 28

replace

입력 문자열을 다른 문자열로 변환한 결과를 리턴하는 String 클래스의 멤버 함수입니다. 입력 인자는 2개의 문자열입니다. 첫 번째 인자는 바꾸려고 하는 문자열이고, 두 번째 인자는 바뀐 문자열입니다.

String a = "aaa aaa bbb bbb ccc ccc";
String from = "bbb";
String to = "FFF";

System.out.println(a.replace(from, to));      // aaa aaa FFF FFF ccc ccc

replaceAll

입력 문자열을 다른 문자열로 변환한 결과를 리턴하는 String 클래스의 멤버 함수입니다. 기본적인 사용법은 replace와 동일하며 결과 역시 일치합니다.

String a = "aaa aaa bbb bbb ccc ccc";
String from = "bbb";
String to = "FFF";

System.out.println(a.replaceAll(from, to));        // aaa aaa FFF FFF ccc ccc

replaceAll() 함수를 사용하는 이유는 첫 번째 인자에 해당하는 바꾸려는 문자열에 대해서 정규식을 사용 할 수 있다는 점입니다. 아래 예시에서 문자열 "[abc]"는 정규식의 일종입니다. [] 안에 포함된 각 문자(char)들이 모두 대상인 경우 다음과 같은 정규식을 사용합니다.

String a = "aaa bbb ccc";

System.out.println(a.replaceAll("[abc]", "Hi "));

코드를 실행하면, 정규식에 포함된 a와 b, c 문자 각각에 대해서 "Hi "문자열로 변경되었습니다. 정규식에 대한 내용은 다른 포스트에서 추가로 다루도록 하겠습니다.

Hi Hi Hi  Hi Hi Hi  Hi Hi Hi

substring

특정 인덱스 범위 사이에 포함되는 문자열을 리턴하는 String 클래스의 멤버 함수입니다. 입력 인자는 2개의 정수입니다. 첫 번째 인자는 시작 인덱스를 의미합니다. 문자열의 첫 문자는 인덱스 0으로 시작합니다. 두 번째 인자는 종료 인덱스를 의미합니다.

String a = "This is some string variable";

System.out.println(a.substring(0, 3));			// Thi
System.out.println(a.substring(0, a.length()));		// This is some string variable

예시에서 확인 할 수 있지만, 인덱스 범위는 인자에서 입력한 종료 인덱스 - 1까지에 해당합니다. 따라서 첫 번째 substring() 함수에서 처리하고 있는 인덱스 3에 해당하는 's' 문자는 포함되지 않습니다.

이 함수 역시 인덱스를 사용하기 때문에 문자열의 크기를 벗어나는 인덱스를 입력하면 StringIndexOutOfBoundsException을 발생시킵니다.

java.lang.StringIndexOutOfBoundsException: begin 0, end -1, length 28

toUpperCase / toLowerCase

toUpperCase() 함수는 문자열을 대문자로 변환하여 리턴하는 String 클래스의 멤버 함수입니다. 별도의 인자는 필요하지 않고, 현재 문자열에 대해서 처리합니다. 반대로 문자열을 소문자로 변환하기 위해서는 toLowerCase() 함수를 사용합니다.

String a = "This is some string variable";
String b = "This Is Some String Variable";

System.out.println(a.toUpperCase());      // THIS IS SOME STRING VARIABLE
System.out.println(b.toLowerCase());      // this is some string variable

split

문자열을 인자로 받은 구분자에 대해서 분리하는 String 클래스의 멤버 함수입니다. 이 함수의 리턴 결과는 String 타입에 대한 배열입니다. 리턴 결과는 분리된 문자열의 집합입니다.

String a = "This is some string variable";
String b = " ";
String[] c = a.split(b);

for (String _c : c) {
   System.out.println(_c);
}

예시에서는 문자열을 공백(" ")으로 분리합니다. 코드를 실행하면 다음 결과를 출력합니다.

This
is
some
string
variable