서론

java.lang.NumberFormatException은 문자열을 숫자 유형(예: int, float, double 등)으로 변환하려고 할 때 해당 문자열이 적절한 형식이 아닐 경우 발생하는 Java의 일반적인 unchecked exception이다. 이는 unchecked exception이므로 컴파일러가 처리를 강제하지 않아, 제대로 관리하지 않으면 예기치 않은 프로그램 충돌로 이어질 수 있다. 이 가이드에서는 NumberFormatException의 원인과 효과적인 처리 방법을 설명한다.

NumberFormatException의 일반적인 원인

이 예외는 Integer.parseInt(), Double.parseDouble(), Float.parseFloat()와 같은 메서드에서 여러 조건 하에 발생한다.

1. 문자열에 숫자가 아닌 문자가 포함된 경우

가장 흔한 원인은 숫자(및 앞쪽 부호 - 또는 +) 이외의 문자가 포함된 문자열을 파싱하려고 할 때다.

String notANumber = "123a";
int number = Integer.parseInt(notANumber); 
// NumberFormatException 발생: For input string: "123a"

2. 문자열에 공백이 포함된 경우

문자열의 시작이나 끝에 있는 공백도 이 예외를 유발할 수 있다.

String withSpace = " 123 ";
int number = Integer.parseInt(withSpace);
// NumberFormatException 발생: For input string: " 123 "

참고: Integer.valueOf()와 같은 일부 메서드는 공백을 다르게 처리할 수 있지만, parseInt()는 엄격하다. 문자열을 먼저 trim()하는 것이 좋은 습관이다.

3. 문자열이 비어 있거나 null인 경우

빈 문자열이나 null 값을 파싱하려고 하면 NumberFormatException이 발생한다.

String empty = "";
int number1 = Integer.parseInt(empty); // NumberFormatException 발생

String nullStr = null;
int number2 = Integer.parseInt(nullStr); // NumberFormatException 발생

4. 문자열이 표현하는 숫자가 범위를 벗어난 경우

문자열이 대상 데이터 유형의 최대값보다 크거나 최소값보다 작은 숫자를 나타내는 경우 NumberFormatException이 발생한다.

String tooBig = "2147483648"; // Integer.MAX_VALUE보다 1 큼
int number = Integer.parseInt(tooBig);
// NumberFormatException 발생: For input string: "2147483648"

5. 잘못된 소수점 또는 부호 형식

부동 소수점 숫자의 경우, 여러 개의 소수점이나 잘못된 위치의 부호가 있으면 오류가 발생한다.

String badDouble = "12.34.56";
double number = Double.parseDouble(badDouble);
// NumberFormatException 발생

NumberFormatException 처리 방법

이 예외를 처리하는 두 가지 주요 전략이 있다: 파싱 전 유효성 검사와 try-catch 블록 사용이다.

전략 1: 파싱 전 유효성 검사 (LBYL - Look Before You Leap)

문자열을 파싱하기 전에 유효한 숫자인지 확인할 수 있다. 일반적인 방법은 정규 표현식을 사용하는 것이다.

예시:

public boolean isNumeric(String str) {
    if (str == null) {
        return false;
    }
    // 문자열이 유효한 정수인지 확인하는 정규식
    return str.matches("-?\d+"); 
}

String input = "123";
if (isNumeric(input)) {
    int number = Integer.parseInt(input);
    System.out.println("파싱된 숫자: " + number);
} else {
    System.out.println("잘못된 숫자 형식입니다.");
}

이 접근 방식은 예외를 발생시키지 않으므로 잘못된 입력이 흔한 경우 성능이 더 좋을 수 있다.

전략 2: try-catch 블록 사용 (EAFP - Easier to Ask for Forgiveness than Permission)

이것은 예외를 처리하는 가장 일반적이고 견고한 방법이다. 변환을 시도하고 실패할 경우 NumberFormatException을 잡는다.

예시:

String input = "abc";
int number;
try {
    number = Integer.parseInt(input);
    System.out.println("성공적으로 파싱됨: " + number);
} catch (NumberFormatException e) {
    System.err.println("잘못된 숫자 형식: " + input);
    // 기본값을 제공하거나 오류 메시지를 표시
    number = 0; // 기본값
}
// 프로그램은 계속 실행됨
System.out.println("숫자의 값은: " + number);

이 접근 방식은 특히 파싱 로직이 간단할 때 더 깨끗하고 가독성이 좋다.

모범 사례

  • 입력값 다듬기: 파싱하기 전에 항상 str.trim()을 사용하여 사용자 입력의 앞뒤 공백을 제거한다.
  • null 처리: NullPointerException이나 NumberFormatException을 피하기 위해 null 입력을 명시적으로 확인한다.
  • 올바른 전략 선택:
    • 잘못된 입력이 자주 예상되는 경우, 정규식으로 사전 검증(LBYL)하는 것이 성능에 더 좋을 수 있다.
    • 잘못된 입력이 드문 경우(진정한 예외적인 경우), try-catch(EAFP) 접근 방식이 명확성 때문에 일반적으로 선호된다.
  • 사용자 피드백 제공: 사용자 대면 애플리케이션에서는 예외를 잡고 프로그램이 충돌하는 대신 명확하고 사용자 친화적인 오류 메시지를 제공한다.

이러한 기술을 적용하면 숫자 변환을 다룰 때 Java 애플리케이션을 더 탄력적이고 사용자 친화적으로 만들 수 있다.

Leave a comment