본문으로 건너뛰기
안동민 개발노트 아이콘

안동민 개발노트

본문 시작
2장 : 변수와 데이터 타입

기본 타입과 값의 범위

프로그램의 계산은 값을 어떤 타입으로 저장할지 정하는 일에서 시작됩니다.

Java의 여덟 기본 타입은 객체 참조와 달리 값 자체를 변수에 담습니다.

같은 숫자처럼 보여도 정수와 부동소수점은 표현 방식과 가능한 연산이 다릅니다.

범위를 넘는 계산은 자동으로 더 큰 공간을 사용하지 않으므로 타입 선택이 결과에 직접 영향을 줍니다.

이 절에서는 크기를 외우기보다 표현하려는 값과 연산을 기준으로 타입을 고릅니다.


정수 타입은 범위와 의도를 함께 본다

byte, short, int, long은 저장 범위가 다르며 일반 정수 계산의 기본은 int입니다.

큰 리터럴은 L을 붙여 long임을 명확히 해야 합니다.


실수 타입은 근삿값을 저장한다

floatdouble은 이진 부동소수점이라 십진 소수를 항상 정확히 표현하지 못합니다.

측정값에는 적합하지만 금액처럼 정확한 십진 계산에는 BigDecimal 같은 별도 타입이 필요합니다.

아래 프로그램은 정수 범위와 문자 표현에서 경계를 넘었을 때 어떤 일이 생기는지 먼저 보여 줍니다. 부동소수점의 근사 오차는 뒤의 measured 비교 예제와 다음 절의 숫자 변환에서 별도로 다룹니다.

PrimitiveRanges.java
public class PrimitiveRanges {
    public static void main(String[] args) {
        int max = Integer.MAX_VALUE;
        System.out.println("max=" + max);
        System.out.println("overflow=" + (max + 1));
        System.out.println("codePoint=" + "😀".codePointAt(0));

        try {
            System.out.println(Math.addExact(max, 1));
        } catch (ArithmeticException error) {
            System.out.println("checked overflow");
        }
    }
}

max + 1은 예외 없이 최솟값으로 순환하지만 Math.addExact는 같은 범위 초과를 예외로 드러냅니다. 이모지는 char 하나가 아니라 코드 포인트 하나로 읽어야 하므로 정수값 128512가 출력됩니다.

max=2147483647
overflow=-2147483648
codePoint=128512
checked overflow

일반 덧셈은 조용히 순환하지만 addExact는 오버플로를 실패로 드러냅니다.

타입을 고를 때는 저장 크기 표부터 외우기보다 세 질문을 순서 없이 함께 봅니다.

  • 최솟값과 최댓값이 타입 범위 안에 있는가?
  • 근삿값을 허용하는 측정인지, 정확한 십진값이 필요한 계산인가?
  • 범위를 넘었을 때 순환을 허용하는가, 즉시 실패해야 하는가?

같은 int라도 비트 마스크처럼 순환을 의도한 값과 결제 수량처럼 손실이 허용되지 않는 값은 사용할 연산이 달라집니다.


문자와 논릿값은 숫자와 다른 계약을 가진다

char는 UTF-16 코드 단위 하나이며 모든 유니코드 문자를 하나에 담는다는 뜻은 아닙니다.

boolean은 조건의 참과 거짓만 표현하며 정수와 자동 변환되지 않습니다.

charboolean은 저장 크기만 보고 작은 정수처럼 다루면 안 됩니다. 전자는 UTF-16 코드 단위이고 후자는 참·거짓 조건을 표현하는 타입이라, 허용 연산과 의미가 정수 타입과 다릅니다.

비교 1
long population = 8_100_000_000L;
double measured = 0.1 + 0.2;
boolean ready = true;
비교 2
// int tooLarge = 8_100_000_000; // 컴파일 오류: int 리터럴 범위 초과
// boolean flag = 1;             // 컴파일 오류: 정수와 boolean은 변환되지 않음

오버플로는 실행 중 조용히 일어날 수 있다

정수 계산이 범위를 넘으면 예외 없이 하위 비트만 남을 수 있습니다.

외부 입력이나 누적 합에서는 더 넓은 타입과 Math.addExact 같은 검사를 고려해야 합니다.


기본값을 업무 기본값으로 착각하지 않는다

필드의 0이나 false는 JVM이 채운 초기값일 뿐 업무적으로 유효하다는 보장은 없습니다.

아직 결정되지 않은 상태가 필요하면 별도 객체나 명시적인 상태를 사용합니다.

필드의 0, false, null은 JVM이 메모리를 초기화하기 위한 값일 뿐 도메인에서 유효하다는 보장은 없습니다. 예를 들어 수량 0과 아직 수량을 입력하지 않은 상태가 다르다면 생성자에서 명시적으로 구분해야 합니다.


기본 타입은 메모리 크기 표보다 값의 범위, 정확도, 허용할 연산을 한 묶음으로 판단하는 것이 실용적입니다.