본문 바로가기
Programming/Refactoring

[Refactoring] 반복문에서 계산 연산을 주의하자(Pattern)

by 흑시바 2023. 3. 12.

반복문에서 사용하는 연산 유형에 주의해야 한다. 😱

계산을 많이 하는 연산을 반복문 내에서 수행하게 되면 프로그램 속도가 느려지면서 성능에 영향을 미친다.

 

특히 문자열 검색에 정규식을 사용할 때 Pattern.matches() 메서드 활용을 주의해야 한다. 해당 메서드는 정규식을 활용해서 반복되는 복잡한 문자열 패턴을 조회하는데 큰 도움이 되는 유용한 메서드지만, 연산 과정이 복잡하고 상당한 시간이 걸린다.

 

자세한 내용은 하단 Reference의 java.util.regex.Pattern compile() 메서드를 참고해 보길 바란다.

 

@Test
void goodRefactoring() {
	long startTime = System.currentTimeMillis();
	for (int i = 0; i < 10_000_000; i++) {
		if(Pattern.matches("/^[a-z0-9_+.-]+@([a-z0-9-]+\\.)+[a-z0-9]{2,4}$/", "blackShiba@naver.com")) {
		}
	}
	System.out.println(System.currentTimeMillis() - startTime);
}

 

해당 코드를 실행하면 내 PC로 대략 7초가 걸린다.

 

해당 문제를 해결하려면 연산을 2개 과정으로 분리하면 된다.

 

1. 컴파일된 정규식을 생성하는 compile() 메서드는 계산이 많이 필요하므로 반복문 밖에서 호출한다.

2. matcher() 메서드를 통해 컴파일된 표현식 실행 과정을 수행한다.

 

@Test
void goodRefactoring() {
	long startTime = System.currentTimeMillis();
	Pattern pattern = Pattern.compile("/^[a-z0-9_+.-]+@([a-z0-9-]+\\.)+[a-z0-9]{2,4}$/");
	for (int i = 0; i < 10_000_000; i++) {
		if(pattern.matcher("blackShiba@naver.com").matches()) {
		}
	}
	System.out.println(System.currentTimeMillis() - startTime);
}

 

결과는 내 PC 기준으로 대략 0.6초가 걸린다.

 

해당 내용을 보고 '그러면 정규식 사용할 때 Pattern.matches만 주의하면 되는 거 아닌가?'🤔라는 생각을 할 수도 있는데, 사실 java.lang.String.replaceAll()처럼 일반적으로 자주 사용되는 유명한 자바 API에도 동일한 내용이 들어가 있다.

 

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

 

만약 replaceAll() 메서드를 사용하는 경우라면, 위 해결 방법과 동일하게 2단계로 분리하여 compile() 메서드를 따로 빼고 matcher() 메서드 호출 후 replaceAll() 메서드를 호출하는 것이 적절하다.

 

REFERENCE

https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#replaceAll(java.lang.String,%20java.lang.String) 

 

String (Java Platform SE 7 )

Compares two strings lexicographically. The comparison is based on the Unicode value of each character in the strings. The character sequence represented by this String object is compared lexicographically to the character sequence represented by the argum

docs.oracle.com

https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html#compile(java.lang.String) 

 

Pattern (Java Platform SE 7 )

Enables canonical equivalence. When this flag is specified then two characters will be considered to match if, and only if, their full canonical decompositions match. The expression "a\u030A", for example, will match the string "\u00E5" when this flag is s

docs.oracle.com

댓글