[Java] 숫자와 문자열을 어떻게 상수화 할까

이상현·2023년 12월 6일
0

Java

목록 보기
13/21
post-thumbnail

상수화 해야하는 값

프로그래밍을 하다보면 숫자나 문자열을 하드코딩하게 되는 경우가 있다.
다음은 그 예시들이다.

  • 매직넘버: 의미가 명확하지 않은 구체적인 숫자 값
    for(int i=0; i<10; i++)

  • 문자열 리터럴: 로그 또는 에러메세지, 텍스트 등 자주 사용되는 문자열
    "[ERROR] 잘못 된 주소 입력입니다."

  • 환경설정 값: DB연결 문자열, API, 포트번호 등
    "jdbc:mysql://localhost:3306/mydatabase?user=root&password=1234"

  • 파일 경로
    "/resources/testImages/lena.png"

  • 정규 표현식
    "[가-힣a-zA-Z]+\d+"

프로그램의 가독성과 유지보수를 향상시키기 위해 이 값들은 상수화 할 필요가 있다.

상수

상수란, 프로그램이 실행되는 동안 '값이 고정되어 변경할 수 없는 메모리 공간' 을 의미한다.

자바 프로그래밍을 할 때, 문자열이나 매직넘버 등을 상수화 할때 사용할만한 방법은 두 가지가 있다.

  1. static final: 단순한 값 표현
  2. 열거형(enum): 상수 집합에 대한 명확한 타입 표현

상수 값이 애플리케이션에서 중요한 역할을 하고, 그 값들이 명확히 구분되어야 하며, 추가 기능이 필요한 경우 enum을 사용하는 것이 좋다. 그러나 만약 단순한 상수 값만 필요하고 추가 로직이 필요하지 않은 경우에는 static final 을 사용하는 것이 코드를 간결하게 유지할 수 있다.

static final 예시 (상수 클래스)

public final class GameConstants {
    public static final String ERROR_INVALID_INPUT = "[ERROR] 잘못된 숫자 입력입니다.";
    public static final String ERROR_INVALID_CONTINUE_INPUT = "[ERROR] 1 또는 2 를 입력하세요.";
    public static final int MIN_NUMBER = 1;
    public static final int MAX_NUMBER = 9;
    public static final int MAX_NUMBER_LENGTH = 6;
   	public static final String INPUT_REGEX = "\\d+";

    private GameConstants() {} // 인스턴스화 방지
}

// 다른 파일에서..

void numberInput(String inputString) {
    if (!Pattern.matches(INPUT_REGEX, inputString)) {
        throw new IllegalArgumentException(ERROR_INVALID_INPUT);
    }
}

단순한 값 표현은 이렇게 사용하면 된다.

열거형 예시

public enum GameStatus {
    CONTINUE("1"),
    STOP("2");

    private final String status;

    GameStatus(String status) {
        this.status = status;
    }

    public String getStatus() {
        return status;
    }
    
    public static boolean isValidStatus(String inputStatus) {
        for (GameStatus status : GameStatus.values()) {
            if (status.getStatus().equals(inputStatus)) {
                return true;
            }
        }
        return false;
    }
}

// 다른 파일에서..

void continueInput(String inputContinue) {
    if (!GameStatus.isValidStatus(inputContinue)) {
        throw new IllegalArgumentException(ERROR_INVALID_CONTINUE_INPUT);
    }
}

상수 값이 명확히 구분되고, 비슷한 카테고리로 묶이는 경우나, 추가 로직이 필요한 경우에는 열겨형이 확실히 깔끔하다.

상수 클래스 주의점

상수 클래스를 만들면, 전역에서 접근 가능한 값이 생긴것이다.
이 상수를 로직에서 사용할 때는 정확히 나타내는 의미를 이해하는것이 중요하다.

예를 들어, MAX_SIZE = 3이라는 상수를 정의하고 프로그램의 여러 부분에서 이 값을 사용하여 구현했다. 처음에는 이 상수가 프로그램의 다양한 부분에 적합한 것처럼 보일 수 있다. 하지만, 추후에 유지보수 과정에서 MAX_SIZE의 값을 변경하게 되면 문제가 발생할 수 있다.

변경된 MAX_SIZE 값이 여러 부분에서 사용되었던 것이 각각 서로 다른 의미를 가지고 있었을 가능성이 있기 때문이다. 예를 들어, 한 곳에서는 MAX_SIZE가 최대 허용 파일 개수를 의미했을 수 있고, 다른 곳에서는 사용자의 최대 인원 수를 의미했을 수 있다. 이러한 경우, 단일 상수 값의 변경이 서로 다른 부분에서 예상치 못한 결과를 초래할 수 있다.

해결 방안

  1. 명확한 네이밍
    이를 해결하기 위해, 상수 네이밍을 명확하게 해야한다.
    MAX_FILE_SIZEMAX_PEOPLE_COUNT 와 같이 명확한 네이밍을 하면 실수 가능성이 줄어든다.

  2. 전역 상수 줄이기
    상수 클래스에는 정말 전역에서 명확한 의미를 가지고 사용되는 값만 저장하고,
    그렇지 않은 상수들은 사용되는 클래스에서만 private로 정의하여 그곳에서만 사용하는것이 좋다. 이럴 경우 추후 유지보수를 진행해도 다른 파일에서 오류가 발생할 가능성이 적어진다.

0개의 댓글