String 클래스
String 클래스
String의 기본
1
2
3
4
5
6
7
8
9
10
public class CharArrayMain {
public static void main(String[] args) {
char[] charArr = new char[]{'h', 'e', 'l', 'l', 'o'}; // 옛날 방식
System.out.println(charArr);
String str = "hello"; // 자바에서 쉽게 사용하게 String 클래스를 제공
System.out.println("str = " + str);
}
}
참조형인데 어떻게 참조 값이 아닌 문자열을 넣을까?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class StringBasicMain {
public static void main(String[] args) {
String str1 = "hello";
String str2 = new String("hello");
String str3 = "hello";
System.out.println(str1 == str2); // false
System.out.println(str1.equals(str2)); // true
System.out.println(str1 == str3); // true
String intern = str2.intern();
System.out.println(str1 == intern); // true
}
}
리터럴 문자열의 경우
==비교 시true가 나오는데, 이는 풀에 이미 같은 값의 문자열이 존재하면 해당 참조 값을 가져오기 때문입니다.
new String()한 경우라도intern()이라는 함수를 실행하면 같은 참조 값을 가집니다. 아마도intern()함수는 풀에 동일한 문자열이 있으면 해당 참조 값을 반환하는 것 같습니다.
String 비교
어떤 게 리터럴 문자열로 생성된 객체고 어떤 게 new String()으로 생성된 것인지 전부 알 수는 없습니다.
그래서 String 비교는 안전하게 equals() 함수를 통해 해야 합니다.
String이 불변 객체로 설계된 이유
같은 문자열의 경우 풀에서 같은 참조 값 찾아 사용한다고 했는데, 내부적으로 값이 수정이 가능해져 버리면 모두 수정되는 사이드 이펙트가 발생하게 되어 불변 객체로 설계된 것 입니다.
StringBuilder
불변인 String의 단점은 문자를 변경할 때 계속 객체를 만들고 GC를 해야 합니다. 따라서 자원을 더 많이 사용하게 됩니다.
StringBuilder는 가변 String으로 자원을 효율적으로 사용할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class StringBuilderMain1_1 {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
sb.append("A");
sb.append("B");
sb.append("C");
sb.append("D");
System.out.println("sb = " + sb);
sb.insert(4, "Java");
System.out.println("insert = " + sb);
sb.delete(4, 8);
System.out.println("delete = " + sb);
sb.reverse();
System.out.println("reverse = " + sb);
//StringBuilder -> String
String string = sb.toString();
System.out.println("string = " + string);
}
}
StringBuilder vs StringBuffer
StringBuilder: 동기화 오버헤드가 없어서 빠른 대신, 멀티 스레드 환경에서 안전하지 않음StringBuffer: 내부에 동기화가 되어 있어 느린 대신, 멀티 스레드 환경에서 안전함
String 최적화
문자열 리터럴 최적화
1
2
String HelloWorld = "Hello, " + "World!"; // 컴파일 전
String helloWorld = "Hello, World!"; // 컴파일 후
런타임에 별도의 문자옆 결합 연산을 수행하지 않기 때문에 성능이 향상된다.
변수 최적화
1
2
String result = str1 + str2;
String result = new StringBuilder().append(str1).append(str2).toString(); // 최적화
자바 9부터는
StringConcatFactory를 사용해서 자동으로 최적화를 수행합니다.
최적화가 어려운 경우
1
2
3
4
5
6
7
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
String result = "";
for (int i = 0; i < 100000; i++) {
result += "Hello Java ";
}
}
1
2
3
4
5
6
7
8
9
public static void main(String[] args) {
String result = "";
for (int i = 0; i < 100000; i++) {
result = new StringBuilder()
.append(result)
.append("Hello Java")
.toString();
}
}
이렇게 되기 이루어 지기 때문에 반복문에서는 비효율 적입니다.
1
2
3
4
5
6
7
8
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 100000; i++) {
sb.append("Hello Java ");
}
}
반복문에서는 위와 같이 StringBuilder를 사용하여 줍시다.
반복문이 아닌 대부분의 경우
+연산을 사용해도 최적화가 된다는 사실!
StringBuilder를 직접 사용하는 것이 더 좋은 경우
- 반복문에서 반복해서 문자를 연결할 때
- 조건문을 통해 동적으로 문자열을 조합할 때
- 복잡한 문자열의 특정 부분을 변경해야 할 때
- 매우 긴 대용량 문자열을 다룰 때
참고
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.