Guava에 있는 com.google.common.base.Preconditions
같은 코드에 evaluation(계산식)
을 사용하는 것이 성능 저하를 만들 수 있습니다.
왜냐하면 계산이 실제로 필요하든 아니든, 메소드 호출을 하기 위해, 매개변수 값을 얻기 위하여 계산식이 항상 실행되기 때문입니다.
마찬가지로 문자열 concatenated 연산을 포함한 매개변수를 로깅 메소드로 넘겨주게되면, log level에 관계없이 문자열 concat 연산이 발생해 성능 저하를 만들 수 있습니다.
계산식 대신 정적인 값이나 사전에 계산이 완료된 값만을 Preconditions와 log 호출에 사용해야합니다.
특히 문자열 concatenation 대신 빌트인된 문자열 포맷팅 방식을 따라야합니다. 그리고 메시지가 만약 어떤 메소드 호출의 결과라면, Preconditions 과정 자체가 함께 스킵되거나, 관련된 예외를 조건부로 던지도록 변경해야 합니다.
규칙을 어긴 코드
logger.log(Level.DEBUG, "Something went wrong: " + message); // 규칙을 어긴 코드; 로그 레벨과 관계 없이 문자열 concatenation이 발생합니다.
logger.fine("An exception occurred with message: " + message); // 규칙을 어긴 코드
LOG.error("Unable to open file " + csvPath, e); // 규칙을 어긴 코드
Preconditions.checkState(a > 0, "Arg must be positive, but got " + a); // 규칙을 어긴 코드. a값에 관계 없이 문자열 concatenation이 발생합니다.
Preconditions.checkState(condition, formatMessage()); // 규칙을 어긴 코드. formatMessage()은 condition에 관계없이 호출됩니다.
Preconditions.checkState(condition, "message: %s", formatMessage()); // 규칙을 어긴 코드
규칙을 준수한 해결책
logger.log(Level.SEVERE, "Something went wrong: {0} ", message); // 필요할 때만 문자열 포맷팅이 적용됩니다
logger.fine("An exception occurred with message: {}", message); // SLF4J, Log4j
logger.log(Level.SEVERE, () -> "Something went wrong: " + message); // Java 8 버전부터는 Supplier 인터페이스를 사용할 수 있습니다. 이를 통해 늦은 evaluation이 가능해집니다
LOG.error("Unable to open file {0}", csvPath, e);
if (LOG.isDebugEnabled() {
LOG.debug("Unable to open file " + csvPath, e); // 이런 경우에는 괜찮습니다. Debug일 때만 문자열 concatenation이 발생하기 때문입니다
}
Preconditions.checkState(arg > 0, "Arg must be positive, but got %d", a); // 필요할 때만 문자열 포맷팅이 적용됩니다
if (!condition) {
throw new IllegalStateException(formatMessage()); // formatMessage()이 조건을 만족할 때만 호출됩니다
}
if (!condition) {
throw new IllegalStateException("message: " + formatMessage());
}
If you like SONARKUBE, don’t forget to give me a star.