자바(Java) 프로그래밍에서 문자열(String)은 기본 데이터 유형만큼이나 중요한 역할을 수행하는 데이터 타입이다. 텍스트 데이터를 처리하고 다루기 위해 문자열을 사용하며, 자바에서는 String 클래스를 통해 문자열을 효과적으로 관리하고 조작할 수 있다. 본 포스트에서는 자바의 String 클래스에 대해 심도 있게 다루며, 기본적인 특징, 문자열 연산, 문자열 비교 및 변환, 그리고 성능 개선을 위해 사용할 수 있는 StringBuilder와 StringBuffer까지 다룰 것이다.
1. String 클래스의 기본 특징
자바의 String 클래스는 텍스트 데이터를 저장하고 다루기 위한 핵심 클래스이다. 문자열을 관리하기 위한 여러 기능을 제공하며, 자바 개발자들이 자주 사용하는 클래스 중 하나이다. 이 클래스의 중요한 특징은 불변성(Immutable) 이다. 문자열이 불변하다는 것은 한 번 생성된 문자열 객체가 절대 변경되지 않는다는 것을 의미한다. 예를 들어, 문자열을 수정하면 기존 문자열을 바꾸는 것이 아니라 새로운 문자열 객체가 생성된다.
String str_example = "Time to";
str_example = str_example + " JAVA"; // 새로운 문자열 객체가 생성되어 str_example에 할당
위 코드에서 "Time to" 문자열에 " JAVA"를 추가하면, 기존 str_example 객체가 변경되는 것이 아니라, "Time to JAVA"라는 새로운 문자열 객체가 생성되고 str_example은 이를 참조하게 된다.
불변성의 장점
- 스레드 안정성(Thread Safety): 여러 스레드에서 동일한 문자열을 사용할 때, 객체의 불변성 덕분에 동기화 처리를 하지 않아도 안전하게 사용할 수 있다.
- 해시코드 캐싱(Hash Code Caching): 불변 객체는 생성 시 해시코드가 계산되며, 이후 값이 변하지 않기 때문에 해시코드를 다시 계산할 필요가 없다.
- 메모리 절약(String Pool): 문자열 리터럴은 메모리 내 String Pool이라는 공간에 저장되며, 동일한 값의 문자열은 새로 생성되지 않고 해당 객체를 재사용한다.
2. 문자열 리터럴과 생성 방식
문자열 리터럴은 큰따옴표로 묶인 문자열 상수를 의미한다. 자바에서 문자열 리터럴은 자주 사용되며, 컴파일러는 동일한 리터럴을 공유하여 메모리를 효율적으로 관리한다. 문자열을 생성하는 두 가지 방법을 알아보자.
문자열 리터럴 생성
문자열 리터럴을 사용하여 문자열을 생성할 때, 자바는 이를 String Pool에 저장한다. 동일한 리터럴이 존재하면 새로 생성하지 않고 기존의 문자열을 참조한다.
String str1 = "JAVA";
String str2 = "JAVA";
boolean isEqual = (str1 == str2); // true, 같은 String Pool을 참조
new 키워드 사용
new 키워드를 사용하여 문자열을 생성하면 String Pool을 사용하지 않고 힙 영역에 새로운 문자열 객체를 생성한다.
String str3 = new String("JAVA");
boolean isEqual = (str1 == str3); // false, 서로 다른 객체
3. 문자열 연산
문자열은 '+' 연산자를 사용하여 손쉽게 결합할 수 있다. 이는 문자열의 연결에 자주 사용되며, 여러 문자열을 조합하여 새로운 문자열을 생성할 때 유용하다.
String prevTitle = "Time to";
String lastTitle = "JAVA";
String title = prevTitle + " " + lastTitle; // "Time to JAVA"로 결합
위 예제에서 prevTitle과 lastTitle 문자열을 '+' 연산자로 결합하면 "Time to JAVA"라는 새로운 문자열이 생성된다. 다만, 자바에서 '+' 연산은 내부적으로 StringBuilder를 사용하여 새로운 문자열을 생성하기 때문에, 반복적인 문자열 결합이 필요하다면 StringBuilder나 StringBuffer를 사용하는 것이 더 효율적이다.
4. 문자열 메서드
String 클래스는 다양한 메서드를 제공하여 문자열을 쉽게 다룰 수 있도록 지원한다. 아래는 자주 사용되는 주요 메서드와 예제 코드이다.
String title = "Time to JAVA";
int len = title.length(); // 문자열의 길이를 반환 (12)
char c = title.charAt(5); // 인덱스에 해당하는 문자를 반환 ('t')
String sub = title.substring(8, 12); // 범위 내의 문자열을 반환 ("JAVA")
int index = title.indexOf("to"); // 특정 문자열의 첫 번째 인덱스 (5)
String upper = title.toUpperCase(); // 모든 문자를 대문자로 변환 ("TIME TO JAVA")
String lower = title.toLowerCase(); // 모든 문자를 소문자로 변환 ("time to java")
boolean starts = title.startsWith("Time"); // 문자열이 "Time"으로 시작하는지 확인 (true)
boolean ends = title.endsWith("JAVA"); // 문자열이 "JAVA"로 끝나는지 확인 (true)
String replaced = title.replace("JAVA", "Python"); // 문자열을 대체 ("Time to Python")
5. 문자열 비교
문자열을 비교할 때는 '==' 연산자가 아닌 equals() 메서드를 사용하는 것이 일반적이다. '==' 연산자는 문자열의 참조를 비교하므로, 같은 값을 가진 다른 객체를 비교할 때 false를 반환할 수 있다.
String str1 = "Time To JAVA";
String str2 = "Time To JAVA";
String str3 = new String("Time To JAVA");
boolean isEqual = str1.equals(str2); // true, 문자열의 값이 같음
boolean isSameRef = (str1 == str2); // true, 동일한 리터럴 참조
boolean isSameRef2 = (str1 == str3); // false, 다른 객체 참조
- equalsIgnoreCase() 메서드: 대소문자를 구분하지 않고 문자열을 비교할 때 사용한다.
boolean isEqualIgnoreCase = str1.equalsIgnoreCase("time to java"); // true
6. 문자열 변환
문자열을 기본 데이터 유형으로 변환하거나 그 반대의 작업은 자주 사용되는 패턴이다. 자바에서는 이를 위한 다양한 방법을 제공한다.
문자열을 숫자로 변환
Integer.parseInt(), Double.parseDouble() 등의 메서드를 사용하여 문자열을 숫자로 변환할 수 있다.
String intStr = "123";
int num = Integer.parseInt(intStr); // 문자열을 int로 변환 (123)
String doubleStr = "3.14";
double dNum = Double.parseDouble(doubleStr); // 문자열을 double로 변환 (3.14)
숫자를 문자열로 변환
숫자 데이터를 문자열로 변환할 때는 String.valueOf() 메서드를 사용할 수 있다.
int intValue = 100;
String intStrValue = String.valueOf(intValue); // 숫자를 문자열로 변환 ("100")
7. StringBuilder와 StringBuffer
불변성은 문자열을 안전하게 만들지만, 대량의 문자열 조작(추가, 수정, 삭제)을 필요로 하는 경우에는 성능 저하를 초래할 수 있다. 이를 보완하기 위해 자바는 StringBuilder와 StringBuffer 클래스를 제공한다. 이 두 클래스는 가변성을 가지며, 내부 버퍼를 사용하여 문자열을 조작하므로 효율적이다.
StringBuilder 예제
StringBuilder는 스레드 안전성을 고려하지 않기 때문에, 단일 스레드 환경에서 빠른 성능을 발휘한다.
StringBuilder sb = new StringBuilder("Time to");
sb.append(" JAVA"); // 기존 객체에 문자열 추가
String result = sb.toString(); // 최종 문자열 ("Time to JAVA")
StringBuffer 예제
StringBuffer는 스레드 안전성을 보장하여 멀티스레드 환경에서도 안전하게 사용할 수 있다. 사용법은 StringBuilder와 동일하다.
StringBuffer sb = new StringBuffer("Time to");
sb.append(" JAVA"); // 기존 객체에 문자열 추가
String result = sb.toString(); // 최종 문자열 ("Time to JAVA")
8. 결론
자바의 String 클래스는 문자열 처리에 강력한 기능을 제공하며, 불변성을 통해 스레드 안전성 및 메모리 관리 효율성을 높일 수 있다. 다양한 문자열 메서드와 문자열 비교, 변환, 그리고 성능을 고려한 StringBuilder와 StringBuffer의 활용까지 이해하면, 더 나은 자바 코드를 작성할 수 있다. 자바에서 문자열을 다루는 방법을 잘 이해하고, 올바른 클래스를 선택하여 효율적인 프로그래밍을 실현해보자.
'JAVA > JAVA 기초' 카테고리의 다른 글
Java Socket 프로그래밍 (0) | 2024.10.16 |
---|---|
Java 이너 클래스 (Inner Class) (0) | 2024.10.14 |
JAVA I/O 입출력 시스템 (0) | 2024.10.13 |
Java 람다 표현식(Lambda Expression)과 스트림(Stream) (0) | 2024.10.12 |
Java Thread 활용 (0) | 2024.10.11 |