Java에서 final 키워드는 불변성을 보장하고 의도하지 않은 변경을 방지하기 위해 사용되는 강력한 기능이다. 이 포스트에서는 메서드 파라미터와 객체 필드에 final을 사용하는 이유에 대해 작성해보려고 한다.
final 이란?
final은 변수, 메서드, 클래스 등에 사용될 수 있는 키워드로, 변경이 불가능하거나 상속이나 오버라이딩을 금지할 때 사용되며 주로 불변성(immutability)을 보장하기 위해 사용된다.
메서드 파라미터에 final 사용 이유
의도하지 않은 수정 방지: 파라미터를 final로 선언하면 메서드 내부에서 해당 파라미터의 값을 재할당할 수 없게 된다. 이로 인해 파라미터를 의도하지 않게 변경하는 것을 방지할 수 있다.
public Player(final List<Integer> playerNumber, final int digitSize) {
this.playerNumber = playerNumber;
this.digitSize = digitSize;
digitSize = 1; //
}
digitSize가 final이라 할당할 수 없다고 뜬다.
장점으로는 파라미터가 final로 선언되어 있으면, 다른 개발자에게 해당 파라미터의 값이 변경되지 않을 것임을 명시적으로 알릴 수 있어 코드의 가독성과 유지보수성이 향상된다.
final과 객체 불변성
final 은 유용하지만, 객체 불변성에 관한 한계도 있다.
다음과 같은 예시가 있다.
final Player player = new Player("아무 리스트", 10);
player.setDigitSize("5"); // 이 코드는 컴파일 단계에서 통과된다.
불변성이 아니다.
불변 객체 만들기
불변성을 달성하려면, 객체의 모든 필드를 final로 선언하고, 상태를 변경할 수 있는 메서드를 제공하지 않아야 한다.
package level4.domain;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import level4.exception.player.PlayerNumberDuplicateException;
import level4.exception.player.PlayerNumberRangeException;
import level4.exception.player.PlayerNumberSizeException;
public class Player {
private static final int MAX_PLAYER_NUMBER_RANGE = 9;
private static final int MIN_PLAYER_NUMBER_RANGE = 1;
private final List<Integer> playerNumber;
private final int digitSize;
public Player(final List<Integer> playerNumber, final int digitSize) {
validatePlayerNumberRange(playerNumber);
validateDuplicateNumber(playerNumber);
this.playerNumber = playerNumber;
this.digitSize = digitSize;
validatePlayerNumberSize(playerNumber);
}
private void validatePlayerNumberSize(final List<Integer> playerNumber) {
if (playerNumber.size() != digitSize) {
throw new PlayerNumberSizeException();
}
}
private void validatePlayerNumberRange(final List<Integer> playerNumber) {
for (Integer number : playerNumber) {
if (number < MIN_PLAYER_NUMBER_RANGE || number > MAX_PLAYER_NUMBER_RANGE) {
throw new PlayerNumberRangeException(MIN_PLAYER_NUMBER_RANGE, MAX_PLAYER_NUMBER_RANGE);
}
}
}
private void validateDuplicateNumber(final List<Integer> playerNumber) {
final Set<Integer> numberSet = new HashSet<>(playerNumber);
if (numberSet.size() != playerNumber.size()) {
throw new PlayerNumberDuplicateException("중복된 숫자가 있으면 안됩니다.");
}
}
public void setDigitSize(int digitSize) {
this.digitSize = digitSize;
}
public List<Integer> getPlayerNumber() {
return playerNumber;
}
}
위 예시와 마찬가지로 컴파일 단계에서 통과되지도 않는다. 강제로 setter 사용을 막아준다.
위처럼 메서드 파라미터에 final 키워드를 붙이면, 재할당 시 컴파일 에러가 발생하여 예상치 못한 동작을 사전에 방지할 수 있을 것이다.
final 자동으로 붙이는 법
이를 위해 인텔리제이에서는 파라미터에 final 키워드를 자동으로 붙여주는 좋은 기능이 있다.
1. 설정(Preference) -> Editor -> Code Style -> Java
2. Code Generation -> Make generated parameters final
'JAVA' 카테고리의 다른 글
숫자 야구 게임 Lv2 Lv3 회고 (0) | 2024.09.18 |
---|---|
UncheckedException과 CheckedException (1) | 2024.09.13 |
ArrayList는 어떻게 크기가 조절될까? (0) | 2024.09.11 |
Garbage Collection(GC) 더 자세히 살펴보기 (0) | 2024.09.09 |
계산기 도전 과제 회고 (0) | 2024.09.07 |
가비지 컬렉션이란? (0) | 2024.09.06 |
제네릭이란? (2) | 2024.09.04 |
인터페이스와 추상 클래스 (3) | 2024.09.03 |