정규표현식을 검사를 더 효율적으로 해보자!

공병주(Chris)·2022년 2월 16일
6

Java를 탄탄히

목록 보기
2/9
post-custom-banner

여러 프로그램을 만들다보면, 분명 문자열에 대한 유효성 검사를 할 일이 많을 것이다.

ex) 숫자로만 이루어져있는가? 특정한 문자만으로 이루어져있는가 등등

필자는 아래와 같이 String의 matches 메소드를 통해서 문자열 검사를 해왔었다.

public class Id {
    private static final String ID_REGEX = "^[a-zA-Z]+$";
    private static final String INVALID_ID_EXCEPTION_MESSAGE = "아이디는 영문만 가능합니다.";

    public Id(final String value) {
        if (!value.matches(ID_REGEX)) {
            throw new IllegalArgumentException(INVALID_ID_EXCEPTION_MESSAGE);
        }
    }
}

위와 같은 방식으로 코드를 치던 어느 날, 코드 리뷰어에게 성능에 대한 피드백을 받았다.


String.matches() 의 동작방식

위의 코드 동작 방식을 살펴보자

String의 matches 메소드는 내부적으로 Pattern의 matches 메소드를 실행시킨다.인자는 정규표현식과 String 자기 자신 객체이다.

Pattern p = Pattern.compile(regex);

Pattern의 matches는 compile 메소드에 regex를 넘겨
우리가 지정한 정규표현식을 컴파일 하며 Pattern 객체를 생성한다.

Matcher m = p.matcher(input);

정규표현식에 대한 정보를 가진 Pattern 객체의 matcher 메소드에 검사하려는 값을 넘겨 Matcher를 생성한다.

return m.matches();

Matcher의 matches 메소드를 통해 검사대상이 정규표현식에 맞는지를 반환한다.

String의 matches는 위와 같은 플로우로 실행된다.


String matches의 성능적인 문제

위와 같이 그냥 String의 matches 메소드를 통해 정규표현식 검사를 하면 참 편한다.

하지만, 결론적으로 이는 성능적으로 좋지 못하다.

Pattern p = Pattern.compile(regex);

위의 코드가 실행되면
Pattern은 입력받은 정규표현식에 대해 유한 상태 기계(finite state machine)을 만드는데,
이는 인스턴스의 생성 비용이 높다. (Pattern 객체를 만드는 것은 비용이 높다는 것이다)

new Name("Chris"); //-> Pattern 객체 생성
new Name("Roma");  //-> Pattern 객체 생성
new Name("Alex");  //-> Pattern 객체 생성

//생성자 내부의 String의 matches가 실행될 때마다 Pattern 객체가 생성된다.

거기에 더해 Name 객체가 생성될 때마다 String의 matches 메소드가 실행되고
정규식을 반복적으로 컴파일하며 Pattern 객체가 반복적으로 생성된다. 인스턴스 생성 비용이 높은 Pattern 객체가 말이다.


해결방안 ( Pattern을 캐싱하자 )

그렇다면 어떻게 해야할까?

Pattern을 private static final 로 캐싱해두면 된다.

모든 Name 객체가 같은 정규표현식을 사용하기 때문에 Pattern을 캐싱해두면 된다.

이렇게 하면 많은 Pattern 객체가 생성되고 회수되는 낭비를 없앨 수 있다.

실제로 조슈아 블로그 형님께서는 이 방식으로 속도를 6.5배 증가시키셨다는 글이 Effective Java에 나와있다.


마무리 하며

사실 성능적인 피드백을 받아본 적이 처음이다. 객체 지향에 대한 이해도 상당히 중요하지만

결국 서비스를 사용하는 사용자의 입장에서 속도(성능)이 떨어지면 당연히 안쓰겠구나.. 라는 것을 다시 한번 느낄 수 있었다.

나.. 한 발자국 더 성장했다. 발 뻗고 자야겠다 뿌-듯 😀😀😀


참고자료

post-custom-banner

0개의 댓글