우선, 비교적 생소한 StringTokenizer에 대해 알아보자.
String[] result = "100,200,300,400".split(",");
Scanner sc = new Scanner("100,200,300,400").useDelimiter(",");
이 두 방법은 ‘정규식 표현’을 사용해야하므로 정규식 표현에 익숙하지 않은 경우 StringTokenizer를 사용하는 것이 간단하면서 명확한 결과를 얻을 수 있다.StringTokenizer를 생성하는 방식 3가지
생성자 | 설명 |
---|---|
StringTokenizer(String str) | 문자열(str)을 기본 구분자(띄어쓰기)를 기준으로 나누는 StringTokenizer를 생성한다. |
StringTokenizer(String str, String delim) | 문자열(str)을 지정된 구분자(delim)로 나누는 StringTokenizer를 생성한다. (구분자는 토큰으로 간주되지 않음) |
StringTokenizer(String str, String delim, boolean returnDelims) | 문자열(str)을 지정된 구분자(delim)로 나누는 StringTokenizer를 생성한다. returnDelims의 값을 true로 하면 구분자도 토큰으로 간주된다. |
리턴값 | 메서드 | 설명 |
---|---|---|
String | nextToken() | 객체에서 다음 토큰을 반환 |
String | nextToken(String delim) | delim 기준으로 다음 토큰을 반환한다. |
int | countTokens() | 전체 토큰의 수를 반환한다. |
boolean | hasMoreTokens() | 토큰이 남아있는지 알려준다. |
boolean | hasMoreElements() | hasMoreToken()과 동일한데 엘리먼트보다 토큰으로 된 메서드를 주로 사용 |
Object | nextElement() | nextToken 메서드와 동일하지만 문자열이 아닌 객체를 리턴 |
\t
), 줄바꿈(\n
), 캐리지 리턴(\r
) 등 기본 구분자가 적용된다. public StringTokenizer(String str) {
this(str, " \t\n\r\f", false);
}
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) {
String ex = "x=100*(200+300)/2";
StringTokenizer st = new StringTokenizer(ex, "+-*/=()", true);
while(st.hasMoreTokens()){
System.out.println(st.nextToken());
}
}
}
// 출력 결과
x
=
100
*
(
200
+
300
)
/
2
+
-
*
/
=
(
)
가 각각 구분자가 된다.)()
→ 이렇게 문자 두 개 이상이 붙어있는 것을 찾고 싶다면)StringTokenizer | Split() |
---|---|
java.util에 포함된 클래스다. | String 클래스에 속해있는 메소드 |
문자로 문자열을 구분 | 정규표현식으로 구분 |
오직 단 한 문자의 구분자만 사용 가능 | 정규표현식을 이용하면 두 문자 이상의 구분자도 사용 가능 |
결과값이 문자열 String | 결과값이 문자열 배열 String[] |
빈 문자열을 토큰으로 인식하지 않음 | 빈 문자열을 토큰으로 인식함 |
→ 데이터 양이 적을 때 배열에 담아 반환하는 split는 데이터를 바로 잘라서 반환해주는 StringTokenizer보다 느릴 수 있다.
StringTokenizer is a legacy class that is retained for compatibility reasons although its use is discouraged in new code. It is recommended that anyone seeking this functionality use the split method of String or the java.util.regex package instead.
StringTokenizer는 호환성을 위해 유지되는 레거시 클래스(legacy class
)이지만 새 코드에서는 사용하지 않는 것이 좋습니다. 이 기능을 원하는 사람은 대신 String 또는 java.util.regex 패키지의 split 메서드를 사용하는 것이 좋습니다.
출처 :
StringTokenizer (Java Platform SE 7 )
놀랍게도 공식홈페이지에서는 StringTokenizer는 레거시 클래스라며, split 메서드로 대체할 것을 권장하고 있다. 하지만 알고리즘을 풀다보면 때때로 StringTokenizer가 split 메소드보다 더 빠른 속도를 보이기 때문에 StringTokenizer를 쓰는 풀이가 심심치 않게 보인다.
그렇다면 정말 StringTokenizer는 아예 쓰지 말아야 할까?
궁금증이 계속해서 커져갈 때,
고맙게도 StringTokenizer와 Split에 대해 심층적으로 분석한 블로그 글들을 찾았다.
💡 [StringTokenizer VS String.split] 누가 더 빠른가
위 블로그에선 StringTokenizer와 split()의 성능 차이를 비교하는 테스트를 진행했고, 이 둘에 대해 다음과 같이 서술했다.
StringTokenizer의 내부의 메서드들의 효율이 매우 나쁘다. 그에 반해서, split은 제법 일정한 성능을 보이고 있다.
StringTokenizer가 더 나은 성능을 보였던 것은 아래의 조건인 경우였다.
1. 구분자가 1개였다.
2. 구분자가 유니코드가 아니었다.
3. 분리된 첫번째 토큰 값만 필요했기에, hasMoreToken을 사용하지 않고, nextToken을 1회 호출 하였다.
StringTokenizer의 내부 메소드 효율은 왜 나쁘고, 위와 같은 조건에선 왜 StringTokenizer가 우세한 성능을 보였을까?
이는 다음 블로그를 참고하면 이해할 수 있다.
💡 java StringTokenizer : 생각보다 느릴까? 뜯어보자.
➡️ 위 블로그에서 일부 요약정리
구분자 중에 유니코드가 있을 경우, 수행시간이 어마어마하게 늘어난다.
delimiterCodePoints
라는 int[] 배열을 만들어 그 안에 유니코드 구분자를 담는다.구분자를 비워두면 기본값으로 ‘스페이스’가 구분자가 된다고 하지만, 실제 내부적으로는 스페이스( ), 탭(\t
), 줄바꿈(\n
), 캐리지 리턴(\r
), \f
이렇게 총 5개의 구분자가 기본으로 적용된다.
public StringTokenizer(String str) {
this(str, " \t\n\r\f", false);
}
즉 구분자의 길이가 문자 5개인 것으로, 만약 이 5개가 아닌 문자인 경우 구분자인지를 검사할 때 6번 가량 순회해야 하는 것.
다음과 같은 상황인 경우엔 StringTokenizer를 쓰는 것이 적합할 것 같다.
1. 구분자에 유니코드 문자가 없고, 구분자의 길이가 길지 않을 때
(StringTokenizer가 속도 측면에서 더 빠를 가능성이 높다)
- 구분자가 복잡하지 않은 '한 문자'일 때
(두 문자 이상이 아니라 정규표현식이 필요하지 않을 때)
- 반환 타입이 배열이 아니라 문자열인 경우가 적합할 때
➡️ 사실 3번은 개인적으로 알고리즘 문제를 풀 때 StringTokenizer를 써야겠다고 생각한 상황이다.
문자열을 쪼갤 때, 이 문자열들을 보관할 필요없이 일시적으로 쓰는 경우라면 split() 메서드는 부적합하다. split()은 무조건 배열로 반환하기 때문에, 배열에 한번 담았다가 꺼내는 불필요한 코드(작업)을 추가적으로 거쳐야 하기 때문.
+) 자세한 것 다음 주소의 알고리즘 오답풀이를 참고
[TIL_Algorithm] 구간 합 구하기 공식, StringTokenizer
➡️ 그러나 프로젝트에서 StringTokenizer를 적용하는 경우라면 좀더 신중히 생각해야 할 것 같다.
공식적으로 legacy 코드로 분류되었기 때문에 이후 jdk 버전을 올리면서 StringTokenizer가 사라지면, 이와 관련된 코드를 모두 수정해야하는 일이 발생하므로.
[Java] StringTokenizer 문자열 분리하기 (split과 차이는 뭘까?)
[Java] StringTokenizer 기본 및 사용법
[JAVA 자바] StringTokenizer 클래스로 문자열 분리하기! split 비교.
[StringTokenizer VS String.split] 누가 더 빠른가
java StringTokenizer : 생각보다 느릴까? 뜯어보자.
남궁성, <자바의 정석>, pp.513-517