Java & Android
Java String
그레이트쪼
2016. 9. 12. 19:29
- Java에서 String은 immutable 객체로서 변경이 불가능하다.
String concatenation - StringBuilder vs. StringBuffer
- 따라서 String의 '+' 연산자를 통해 확장해나갈 경우 매순간 새로운 객체를 생성한다.
1 2 3 4 5 6 7 8 | // This code creates n String instances temporarily public String repeatString (String str, int n) { String result = ""; for (int i = 0; i < n; i++) { result += str; } return result; } |
- 그에 반해 StringBuilder와 StringBuffer는 가변적인 크기의 공간 (자동으로 크기가 늘어나는 char [])을 가지기 때문에 append operation에서는 비용이 발생하지 않고 String을 최종 생성할 때만 객체 생성이 일어난다.
1 2 3 4 5 6 7 8 | // Just a String instance is created on calling toString() public String repeatString (String str, int n) { StringBuffer buffer = new StringBuffer(); for (int i = 0; i < n; i++) { buffer.append(str); } return buffer.toString(); } |
- StringBuffer와 StringBuilder는 operation이 동일하다.
- 그렇다면 StringBuffer와 StringBuilder의 차이는 무엇인가? 가장 큰 차이는 StringBuffer가 synchronized되어 있고 (= thread safe) StringBuilder는 아니라는 점이다. (따라서 StringBuilder가 조금 성능이 더 좋을 것이다)
- StringBuffer는 String과 함께 출시되었다. 반면 StringBuilder는 Java 5 (JDK 1.5)에서 새로 추가되었다.
- 성능 비교하자면 대충 이정도
- 한편, Java 5 (JDK 1.5) 이상에서는 String의 "+" operation을 컴파일러가 자동으로 StringBuffer연산으로 바꿔준다.
1 2 3 4 | // In Java 5, the following code String s = "Hello " + "Beautiful " + "world"; // is changed like this automatically. String s = (new StringBuffer ("Hello Beautiful ")).append("world").toString(); |
- 그럼에도 불구하고 StringBuilder를 쓰자. StringBuffer보다 (성능상 조금) 나을 뿐 아니라, 컴파일러가 모든 상황에서 '+' 연산자를 다 알아서 변경해준다고 가정할 수는 없다. 예를 들어, 아래와 같은 코드는 변경 안해준다 (안해줄 것으로 예상된다).
1 2 3 4 | // How about this code? String s = "Hello "; s += "Beautiful "; s += "world"; |
- Tip! - 마지막 iteration을 제외하고 뒤에 구분자 삽입하기
- 보통은 iteration의 마지막을 체크하여 예외적으로 구분자를 삽입하지 않는 코드를 짠다.
1 2 3 4 5 6 7 8 9 10 | int[] array = {1, 2, 3...}; StringBuilder sb = new StringBuilder(); for (int i : array) { if (sb.length() != 0) { sb.append(","); } sb.append(i); } return sb.toString(); |
- 그런데 이를 달리 생각하여 첫 번째를 iteration을 제외하고 앞에 구분자 삽입하기로 바꿀 수도 있다.
1 2 3 4 5 6 7 8 9 | int[] array = {1, 2, 3...}; StringBuilder sb = new StringBuilder(); sb.append(array[0]); for (int i = 1; i < array.length; i++) { sb.append(","); sb.append(array[i]); } return sb.toString(); |
String decomposition - StringTokenizer vs. String.split()
- StringTokenizer는 String을 기본적으로 공백문자 기준으로 token화 시키는 것이다.
- 용법은 문자열을 생성자에 넣어주고 hasMoreTokens()와 nextToken()을 순환하면 된다.
- 예제
1 2 3 4 5 | StringTokenizer st = new StringTokenizer("this is a test"); while (st.hasMoreTokens()) { System.out.println(st.nextToken()); } |
- 공백문자가 아닌 다른 문자를 delimiter로 넣어주고 싶으면 생성자에 넣어주면된다. 예를 들어, 공백문자, 탭, 콤마를 delimiter로 지정하고 싶다면 아래와 같이 사용한다. (신기한 건 s와 t 앞에 backslash를 두 번 한다는 것이다. Regular expression에 근거)
1 | StringTokenizer st = new StringTokenizer("this is a test", ",\\s\\t"); |
- 사실 StringTokenizer는 호환성을 위해 남겨진 코드이고 최근 코드에서는 String의 split()을 사용한다.
1 2 3 4 5 | String[] tokens = "this is a test".split("\\s"); for (token : tokens) { System.out.println(token); } |
- 기능적으로는 거의 같지만 약간의 차이는 있다. Tokenizer의 경우 delimiter가 연속되면 그 모든 것들이 무시되는 반면 split()의 경우에는 delimiter 사이를 공백문자열로 생성하여 배열을 반환한다.