String 클래스
1. 기본
문자열을 다루기 위해서 char 형 배열을 사용하는 것이 불편하므로 자바에서는 String 클래스를 제공한다.
사용법
String str1 = "hello world";
String str2 = new String("hello world");
문자열을 사용하는 방법은 위와 같다. 쌍따옴표로 문자열을 감싸면 자동으로 자바에서 new String("문자열") 로 변경해준다.
구조
public final Class String{
private final char[] value; // 자바 9 이전
private final byte[] value; // 자바 9 이후
}
String 클래스는 개발자가 사용하기 불편한 char[] 을 감추고 편리하게 문자열을 다룰 수 있게 한다.
2. 비교
- 동일성(Identity) :
==연산자를 사용하여 두 객체의 참조값을 비교 - 동등성(Equality) :
equals()메서드를 사용하여 두 객체의 논리값을 비교
String str1 = new String("java");
String str2 = new String("java");
System.out.println("== 비교 : " + (str1 == str2)); // false
System.out.println("equals 비교 : " + (str1.equals(str2)); // true
String str3 = "java";
String str4 = "java";
System.out.println("== 비교 : " + (str3 == str4)); // true
System.out.println("equals 비교 : " + (str3.equals(str4)); // true
str3 == str4 를 비교했을 때 false 값이 아닌 true 값이 출력된다.
String str3 = "java" 와 같이 문자열 리터럴을 사용하는 경우 자바는 메모리 효율성과 성능 최적화를 위해 문자열 풀을 사용한다. 자바가 실행되는 시점에 클래스에 문자열 풀이 존재하면 문자열 풀에 String 객체를 미리 만들어 놓고 같은 객체가 존재하면 만들지 않는다.
여러 개발자들과 협업을 하거나 외부 라이브러리를 가져와서 사용하는 상황에서 문자열이 문자열 리터럴을 사용했는지 문자열 객체를 만들어서 사용했는지 파악하기 힘들기 때문에 문자열 비교는 equals() 를 사용하여 동등성 비교를 해야 한다.
3. 불변 객체
String 은 불변 객체이기 때문에 생성 이후로 내부의 문자열 값을 변경할 수 없다.
String 이 불변으로 설계된 이유는 문자열 풀에 있는 String 객체의 경우 중간에 변경되면 같은 문자열을 참고하는 다른 변수의 값도 변경되기 때문이다.
4. 주요 메서드
문자열 조회 정보
length(): 문자열의 길이를 반환한다.isEmpty(): 문자열이 비어 있는지 확인한다. (길이가 0)isBlank(): 문자열이 비어 있는지 확인한다. (길이가 0 이거나 공백(Whitespace) 만 있는 경우)charAt(int index): 지정된 인덱스에 있는 문자를 반환한다.
문자열 비교
equals(Object anObject): 두 문자열이 동일한지 비교한다.equalsIgnoreCase(String anotherString): 두 문자열을 대소문자 구분 없이 비교한다.compareTo(String anotherString): 두 문자열을 사전 순으로 비교한다.compareToIgnoreCase(String str): 두 문자열을 대소문자 구분 없이 사전적으로 비교한다.startsWith(String prefix): 문자열이 특정 접두사로 시작하는지 확인한다.endsWith(Strng suffix): 문자열이 특정 접미사로 끝나는지 확인한다.
문자열 검색
contains(CharSequence s): 문자열이 특정 문자열을 포함하고 있는지 확인한다indexOf(String ch) / indexOf(String ch, int fromIndex): 문자열이 처음 등장하는 위치를 반환한다.lastIndexOf(String ch): 문자열이 마지막으로 등장하는 위치를 반환한다.
문자열 조작 및 변환
substring(int beginIndex) / substring(int beginIndex, int endIndex): 문자열의 부분 문자열을 반환한다.concat(String str): 문자열의 끝에 다른 문자열을 붙인다.replace(CharSequence target, CharSequence replacement): 특정 문자열을 새 문자열로 대체한다.replaceAll(String regex, String replacement): 문자열에서 정규 표현식과 일치하는 부분을 새 문자열로 대체한다.replaceFirst(String regex, String replacement): 문자열에서 정규 표현식과 일치하는 첫 번째 부분을 새 문자열로 대체한다.toLowerCase() / toUpperCase(): 문자열을 소문자나 대문자로 변환한다.trim(): 문자열 양쪽 끝의 공백을 제거한다. 단순 Whitespace 만 제거할 수 있다.strip(): Whitespace 와 유니코드 공백을 포함해서 제거한다.
문자열 분할 및 조합
split(String regex): 문자열을 정규 표현식을 기준으로 분할한다.join(CharSequence delimeter, CharSequence... elements): 주어진 구분자로 여러 문자열을 결합한다.
기타 유틸리티
valueOf(Object obj): 다양한 타입을 문자열로 변환한다.toCharArray(): 문자열을 문자 배열로 변환한다.format(String format, Object... args): 형식 문자열과 인자를 사용하여 새로운 문자열을 생성한다.matches(String regex): 문자열이 주어진 정규 표현식과 일치하는지 확인한다.
참고
CharSequence는 String, StringBuilder 의 상위 타입이다. 문자열을 처리하는 다양한 객체를 받을 수 있다.
5. StringBuilder - 가변 String
불변인 String 클래스의 단점은 문자를 더하거나 변경할 때마다 계속해서 새로운 객체를 생성해야 한다는 점이다. 문자를 더하거나 변경할 때 뿐만 아니라 잉여 객체는 Garbage Collector 에 의해서 처리되어야 하니 컴퓨터 자원을 많이 소모한다.
해결 방법은 가변 String 을 사용하면 된다. 자바에서는 StringBuilder 라는 가변 String 을 제공한다. 물론 가변의 경우 사이드 이펙트에 주의해야 한다.
구조
public final class StringBuilder {
char[] value; // 자바 9 이전
byte[] value; // 자바 9 이후
public StringBuilder append(String str) {...}
public int length() {...}
...
}
메소드
append(): 문자열 추가insert(): 특정 위치에 문자열을 삽입delete(): 특정 범위의 문자열을 삭제reverse(): 문자열을 뒤집기toString():StringBuilder의 결과를 기반으로String을 생성해서 반환
StringBuilder 는 보통 문자열을 변경하는 동안만 사용하다가 문자열 변경이 끝나면 불변 String 으로 변환해야 한다.
6. String 최적화
문자열 리터럴 최적화
컴파일 전
String helloWorld = "Hello, " + World!";
컴파일 후
String helloWorld = "Hello, World!";
자바는 문자열 리터럴을 더하는 부분을 자동으로 합쳐준다. 런타임에 별도의 문자열 결합 연산을 수행하지 않기 때문에 성능이 향상된다.
String 변수 최적화
String result = str1 + str2;
String result = new StringBuilder().append(str1).append(str2).toString();
자바가 알아서 최적화를 처리해 주기 때문에 직접 StringBuilder 를 사용하지 않아도 괜찮다. 문자열 더하기 (+) 를 사용해도 된다.
String Builder 를 직접 사용하는 것이 더 좋은 경우
- 반복문에서 반복해서 문자를 연결할 때
StringBuilder sb = new StringBuilder();
for(int i = 0; i < 100000; i++) {
sb.append("java");
}
String result = sb.toString();
- 조건문을 통해 동적으로 문자열을 조합할 때
- 복잡한 문자열의 특정 부분을 변경할 때
- 매우 긴 대용량 문자열을 다룰 때
참고
StringBuilder 와 똑같은 기능을 수행하는 StringBuffer 클래스도 있다.
- StringBuffer 는 내부에 동기화가 되어 있어서, 멀티 쓰레드 상황에서 안전하지만 동기화 오버헤드로 인해 성능이 느리다.
- StringBuilder 는 멀티 쓰레드 상황에서 안전하지 않지만 동기화 오버헤드가 없으므로 속도가 빠르다.
7. 참고 자료
https://velog.io/@tomy8964/String-%ED%81%B4%EB%9E%98%EC%8A%A4