Post

[Java] final 변수는 언제 쓰는 게 좋을까요?

final을 사용하기 전 우리는 불변 객체에 대해서 알아야 합니다. 불변 객체 (Immutable Object)는 상태가 변할 수 없는 객체, 즉 수정 불가능한 객체를 말합니다.

자바에 final 키워드를 사용해서 객체를 한 번만 할당할 수 있습니다. 즉, 불변 객체를 만들어냅니다.

프로그래밍에서 불변성은 왜 중요할까요?

1. 멀티 스레드 환경에서의 장점

  • 항상 동일한 값을 보장하므로 동기화를 신경 쓸 필요가 없습니다.
  • 따라서 변경할 수 없는 불변의 객체는 Thread-Safe합니다.

2. GC 최적화

  • 값을 수정할 수 없기 때문에 객체의 수정된 공간을 찾는 알고리즘이 구동 되지 않고 즉시 Garbage를 처리할 수 있습니다.
  • 가변 객체의 생명주기가 길어진다면 GC의 오래된 참조를 추적하기 위해 수행되는 작업이 길어져 Garbage를 찾기 힘들어 불변 객체를 사용하면 수행되는 작업이 짧아집니다.

원시타입 final

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class FinalStudy {
    final String adultName;
    String childName;

    public FinalStudy(String adultName, String childName) {
        this.adultName = adultName;
        this.childName = childName;
    }

    //final 원시타입 사용시 setter 사용 불가능

    public void updateChildName(String childName) {
        this.childName = childName;
    }
}

final 원시 타입은 변수 앞에 final 예약어를 입력하여 사용하는 것입니다. childName 은 final 변수가 아니기 때문에 updateChildName 메서드로 값을 변경할 수 있습니다. 하지만 adultName은 final 변수이기 때문에 setter 메서드를 선언할 수 없습니다. 따라서 adultName 은 초기화 이후 값을 수정할 수 없는 상수가 됩니다.

메서드 인자 final

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class FinalStudy {
    final String adultName;
    String childName;

    public FinalStudy(String adultName, String childName) {
        this.adultName = adultName;
        this.childName = childName;
    }

    //final 원시타입 사용시 setter 사용 불가능

    public void updateChildName(String childName) {
        this.childName = childName;
    }

    public void updateChildNameFinalParm(String childName) {
        childName = "patricia";
        this.childName = childName;
    }
}

위 코드는 final 메서드 인자에 대한 코드입니다.

1
2
3
4
public void updateChildNameFinalParm(String childName) {
    childName = "patricia";        
    this.childName = childName;
}

여러분들은 팀원들을 믿을 수 있습니까? 사람은 누구나 실수를 합니다. 만약 updateChildNameFinalParm 를 A클래스에서 잘 사용하고 있는데 다른 팀원이 B클래스에서 childName = "patricia" 를 무조건 사용해야 한다며 변경해버리면 어떻게 하시겠습니까?

A클래스는 항상 영문도 모른 채 updateChildNameFinalParm 메서드를 호출하면 "patricia"로 변경되겠죠.

1
2
3
4
public void updateChildNameFinalParm(final String childName) {
    childName = "patricia"; //컴파일 에러    
    this.childName = childName;  
}

따라서 final 예약어를 사용하면 메서드가 실행되는 동안 인자의 값을 일관되게 유지하도록 보장합니다. 컴파일러가 컴파일 타임에 재할당을 감지하여 잠재적인 문제를 발견할 수 있습니다. 이는 코드의 안정성을 높입니다.

그래서 언제 쓰는게 좋을까?

원시타입 final

  • ReadOnly를 하고 싶을때
  • 상수로 값을 사용할때

메서드 인자 final

  • 메서드가 실행되는 동안 인자의 값을 유지하고 싶을때
This post is licensed under CC BY 4.0 by the author.