그동안 final 키워드에 대해 상수를 정의할 때 사용하고, 무조건 초기화해야 함을 명시적으로 사용할 때 사용한다고 알고 사용하고 있었다.
그러다 static 키워드에서처럼 핵심을 못잡고 사용한다는 느낌이 들어 정리해보기로 했다.
final 키워드
- 재할당 불가를 명시할 때 사용한다.
1
2
3
4
public void test() {
final int num = 3;
num = 5; // X
}
final로 선언한 변수를 위와 같이 재할당하려하면 오류가 발생한다. 수정할 수 없다.
- final로 매개변수를 받으면 메서드 내에서 수정 불가능하다.
1
2
3
public void test(final int num) {
num++; // X
}
- final 키워드를 메서드 앞에 사용하면, 오버라이드가 안된다.
1
2
3
4
5
6
7
public class Test {
public final void test() {}
}
public class Test2 extends Test {
public void test() {} // X
}
- final 키워드를 클래스 앞에 사용하면, 다른 클래스에서 상속할 수 없다.
주의
List같은 컬렉션에 final을 선언한다면 변수 자체의 변경은 불가능하지만, 컬렉션 내부의 변수들은 변경이 가능하다. ( list.add(1) )
static final
1
2
3
public class SessionConst {
public static final String LOGIN_MEMBER = "loginMember";
}
객체가 같은 값을 공유하고, 그 값은 변하지 않는다.
위와 같이 어떠한 불변의 변수들을 선언해두고 관리하는 목적으로 사용할 수 있다.
ex) 메시지 관리
final 키워드 사용 이유
- Thread-Safe 하여 병렬 프로그래밍에 유용하며, 동기화를 고려하지 않아도 된다.
- 멀티 쓰레드 환경에서 동기화 문제가 발생하는 이유는 공유 자원을 동시에 사용하는 것이 가능하기 때문이다.
- 이러한 공유 자원이 불변이라면 동기화를 고려하지 않아도 된다.
- 실패 원자적인 메서드를 만들 수 있다.
- 가변 객체를 통해 작업을 하는 도중 예외가 발생하면 해당 객체가 불안정한 상태에 빠질 수 있다.
- 불변 객체라면 어떠한 예외가 발생해도 메서드 호출 전의 상태를 유지할 수 있다.
- 오류 가능성을 최소화 가능하다.
- 가비지 컬렉션의 성능을 높일 수 있다.
어느 상황에 사용해야 하나
- 서비스에서 값이 변하지 않게 하고 싶은 부분에 final을 사용한다.
- 생성자 주입을 위해 사용한다.
- 불변, 필수, 누락 방지
- final 키워드를 사용하면 반드시 초기화를 해줘야 하기 때문에 누락을 방지할 수 있다.
- 생성자 주입 복습