본문 바로가기
Language/Java

[Java] 성능 최적화 - String.replaceAll, String.replace

by graycode 2023. 4. 5.

String.replaceAll

특정 문자열을 정규식을 활용해 치환할 때 Java 에선 String.replaceAll 을 지원한다.

다만 해당 메소드는 아래와 같이 complie() 을 호출하고, Pattern 객체를 생성하는데,

이러한 과정이 내부적으로 상당한 연산량으로 이루어져 있다.

public String replaceAll(String regex, String replacement) {
    return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}

 

만약 replaceAll() 을 한 두번 수행한다면 큰 오버헤드는 없겠지만,

정규식과 대상의 관계가 1 : n 일 경우 위의 연산과정을 불필요하게 반복해 수행하게 된다.

String rnn = "0000101-345678";
Pattern pattern = Pattern.compile("(.{5}$)");

int n = 100;
while (n-- > 0) {
    rnn = pattern.matcher(rnn).replaceAll("******");
    // rnn = rnn.replaceAll("(.{5}$)", "******"); 
}

이런 경우에는 위와 같이 미리 Pattern 객체를 생성해두고, 이를 참조하는 방식으로 구현해 최적화할 수 있다.

 

String.replace

위의 예시들은 언제까지나 정규식을 활용하는 경우이고 일반적인 치환에서는 String.replace 를 사용하는 것이 좋다.

 

그러나 Java 8 에서 String.replace(CharSequence, CharSequence) 의 경우, 

내부적으로 여전히 Pattern 객체를 사용하며 이는 Java 9 이상 부터 최적화되었음을 인지할 필요가 있다.

이에 Java 9 이전 버전 replace 의 대안으로 Apache Commons 라이브러리 StringUtils.replace 가 주로 사용된다.

 

문자열 제거

아직까지 Java 에선 String.remove 와 같은 문자열 제거에 대한 메소드를 따로 지원하지 않는다.

Java 는 빈 문자 리터럴이 존재하지 않으므로,

Java 8 에서도 충분히 최적화되어 있는 String.replace(char, char) 를 활용하기 어렵고

String.replace(value, "") 와 같은 패턴으로 구현해야 한다.

 

따라서 더 나은 성능적 대안으로써 Apache Commons 라이브러리의 StringUtils.remove 활용을 고려해볼 수 있다.

public String removeDot(String target) {
    return StringUtils.remove(target, '.');
    // return target.replace(".", "");
}

 

다만 위에서 언급했다시피 Java 8 이후 버전 상승에 따른 지속적인 최적화로, (replace 는 Java 13에서 대폭 개선)

제 3 라이브러리보다 표준 replace 메소드를 활용하는 것이 더 나은 선택지가 될 수 있다.

댓글