[Java] Final / Effective Final 성능

Manx·2023년 7월 26일
0

Java

목록 보기
2/2

Final 키워드를 사용했을 때의 대표적인 이점

Final 키워드를 사용할 경우, 한 번 할당된 후에는 그 값을 변경할 수 없어 프로그램의 안정성을 높이고, 버그를 방지할 수 있다.


1. Final 변수 성능 Test

// Final을 사용하지 않았을 경우
@Benchmark
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@BenchmarkMode(Mode.AverageTime)
public static String concatNonFinalStrings() {
    String x = "x";
    String y = "y";
    return x + y;
}

// Fianl을 사용했을 경우
@Benchmark
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@BenchmarkMode(Mode.AverageTime)
public static String concatFinalStrings() {
    final String x = "x";
    final String y = "y";
    return x + y;
}

성능
Final을 사용했을 경우 코드 실행에 걸리는 평균 시간이 2.5배 향상된 것을 확인할 수 있다.

Benchmark                              Mode  Cnt  Score   Error  Units
BenchmarkRunner.concatFinalStrings     avgt  200  2,976 ± 0,035  ns/op
BenchmarkRunner.concatNonFinalStrings  avgt  200  7,375 ± 0,119  ns/op

Final 키워드를 사용하지 않은 경우 컴파일러는 다음 바이트 코드를 생성하여 두 문자열을 연결하였다.

NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
ALOAD 0
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
ALOAD 1
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ARETURN

Final 키워드를 사용했을 경우, 문자열 연결을 완전히 피하고, 생성된 바이트 코드를 정적으로 최적화 하였다.

LDC "xy"
ARETURN

2. Effectively Final

Java 8에서 Effectively Final이 추가되었다.

변수가 명확하게 Final로 선언되지 않았지만, 초기화 후에 값이 변경되지 않았을 때에 컴파일러가 이를 Final로 인식한다.

int num = 1;

Runnable runnable = new Runnable() {
    @Override
    public void run() {
        System.out.println("number: " + num);
    }
};
runnable.run();

해당 코드에서 num 은 초기화 이후 변경되지 않았기 대문에 Effectively Final로 인식된다.

Java 8 이전에는, 해당 코드는 변경이 가능한 num 변수에 접근하기 때문에 컴파일 에러가 발생했다.

Effectively Final이 추가된 이유는, 람다가 Final을 명시하지 않은 로컬 변수를 사용할 수 있도록 하기 위해서이다.

Final로 명시된 변수와 다르게, Effectively Final은 정적 코드 최적화를 수행하지 않는다.


출처
https://www.baeldung.com/

profile
백엔드 개발자

0개의 댓글