기본 타입과 리터럴
값의 범위와 연산에 맞는 타입·리터럴을 선택하고 컴파일러가 허용하는 이름과 읽기 좋은 이름을 구분합니다.
변수 이름이 의미를 설명한다면 타입은 그 값에 허용되는 범위와 연산을 제한합니다.
회원가입의 나이는 정수이고, 회원 식별자는 int 범위를 넘을 수 있으며, 활성 여부는 0과 1보다 boolean이 정확합니다.
리터럴은 소스에 직접 적은 값이므로 접미사와 따옴표까지 타입의 일부로 읽어야 합니다.
정수 리터럴의 범위
다음 프로그램은 값이 30억인 회원 식별자를 long 변수에 넣으려 하지만 오른쪽 리터럴 자체가 기본 int 범위를 넘습니다.
public final class TooLargeLiteral {
public static void main(String[] args) {
long memberId = 3_000_000_000;
System.out.println(memberId);
}
}lab\TooLargeLiteral.java:3: error: integer number too large
long memberId = 3_000_000_000;
^왼쪽이 long이어도 오른쪽 정수 리터럴은 접미사가 없으면 먼저 int로 해석됩니다.
값 뒤에 대문자 L을 붙여 리터럴 자체를 long으로 만듭니다.
long memberId = 3_000_000_000L;소문자 l도 문법상 가능하지만 숫자 1과 헷갈리므로 대문자 L을 사용합니다.
밑줄은 숫자 값을 바꾸지 않고 자릿수만 읽기 쉽게 나눕니다.
3_000_000_000L과 3000000000L은 같은 값입니다.
문자열 리터럴도 숫자로 자동 변하지 않습니다.
public final class StringIsNotInt {
public static void main(String[] args) {
int age = "45";
System.out.println(age);
}
}error: incompatible types: String cannot be converted to int"45"는 숫자처럼 보이는 두 문자로 이루어진 문자열입니다.
계산하려면 Integer.parseInt("45")처럼 변환 성공과 실패가 있는 별도 경계를 통과해야 합니다.
JAVA · COMPILE FLOW
리터럴의 표기가 대입 전에 타입을 결정한다
왼쪽 변수보다 먼저 오른쪽 리터럴의 표기·범위·초기 타입을 판정해야 대입 성공과 실패를 설명할 수 있습니다.
먼저 오른쪽 리터럴의 타입과 범위를 확인합니다
L 없음 · 리터럴 단계에서 실패
long memberId = 3_000_000_000;왼쪽은 long이어도, L 없는 십진 정수 리터럴이 int 범위를 넘습니다.
컴파일 오류:
integer number too largeL 있음 · long 값을 만듦
long memberId = 3_000_000_000L;접미사 L이 리터럴 자체를 long으로 해석하게 하므로 대입할 값을 만들 수 있습니다.
리터럴 타입:
long그 값이 왼쪽 변수 타입에 대입 가능한지 확인합니다
문자열을 정수로 바로 대입 · 실패
int age = "45";"45"는 유효한 String 리터럴이지만 int로 자동 변환되지 않습니다.
컴파일 오류: String → int 대입 불가
명시적으로 파싱 · 별도 변환 경계
int age = Integer.parseInt("45");이 예제는 정수 45를 만듭니다. 다른 문자열은 형식이나 범위에 따라 변환에 실패할 수 있습니다.
표기도 타입의 일부입니다
45 → int · 0.75 → double · true → boolean · 'A' → char · "45" → String
타입은 목적지 변수의 장식이 아닙니다. 소스 표현이 먼저 값을 만들고, 그 결과가 목적지 계약을 통과해야 합니다.
기본 타입과 값의 대응
public final class MemberTypes {
public static void main(String[] args) {
int age = 45;
long memberId = 3_000_000_000L;
double signupRate = 0.75;
boolean active = false;
char grade = 'A';
String email = "[email protected]";
System.out.println("age=" + age);
System.out.println("memberId=" + memberId);
System.out.println("signupRate=" + signupRate);
System.out.println("active=" + active);
System.out.println("grade=" + grade);
System.out.println("email=" + email);
}
}age=45
memberId=3000000000
signupRate=0.75
active=false
grade=A
[email protected]정수형은 byte, short, int, long이 있지만 일반적인 정수 계산은 int, 큰 누적값은 long을 우선합니다.
파일의 원시 바이트처럼 API가 byte를 요구할 때는 그 타입을 사용합니다.
작은 값을 담는다고 무조건 작은 타입을 택하면 변환과 오버플로 검토가 늘어날 수 있습니다.
실수형은 float와 double이 있습니다.
접미사 없는 0.75는 double이고 float 리터럴은 0.75F처럼 표시합니다.
일반 계산은 double을 사용하지만 금액처럼 정확한 십진 연산이 필요한 경우에는 부동소수점 자체의 오차를 고려해 뒤에서 BigDecimal 같은 타입을 선택합니다.
boolean은 true와 false만 가집니다.
int active = 2처럼 유효하지 않은 세 번째 상태를 만들지 않습니다.
'A'나 '가'처럼 작은따옴표로 쓰는 값은 char, 큰따옴표로 쓰는 문자열은 String입니다.
정확히는 char 하나가 UTF-16의 16비트 코드 단위 하나를 담습니다. 화면에 보이는 문자 하나가 언제나 char 하나인 것은 아닙니다. 예를 들어 "😀"는 String으로 표현하고 UTF-16 코드 단위 두 개를 사용합니다. 이 수업의 등급 'A'는 한 단위로 표현되므로 char를 써도 됩니다. 문자와 코드 단위의 차이는 문자열 수업에서 다시 다룹니다. Java 언어 명세의 기본 타입 정의도 이 구분을 사용합니다.
실제 업무의 제목과 상태 라벨은 길이가 변하므로 대부분 String이 자연스럽습니다.
리터럴과 타입
| 소스 표현 | 리터럴 타입 | 회원가입에서의 의미 |
|---|---|---|
45 | int | 회원 나이 |
3_000_000_000L | long | 큰 회원 식별자 |
0.75 | double | 가입 전환율 |
true | boolean | 활성 여부 |
'A' | char | 문자 하나인 등급 |
"[email protected]" | String | 회원 이메일 |
리터럴은 고정된 소스 표현이고 변수의 현재 값은 대입으로 바뀔 수 있습니다.
int age = 45; age = 60;에서 45와 60은 각각 리터럴이며 age의 값만 시간에 따라 달라집니다.
숫자 타입의 범위를 암기하기보다 경계를 출력해 확인할 수 있습니다.
public final class NumericRanges {
public static void main(String[] args) {
System.out.println("byte=" + Byte.MIN_VALUE + ".." + Byte.MAX_VALUE);
System.out.println("short=" + Short.MIN_VALUE + ".." + Short.MAX_VALUE);
System.out.println("int=" + Integer.MIN_VALUE + ".." + Integer.MAX_VALUE);
System.out.println("long=" + Long.MIN_VALUE + ".." + Long.MAX_VALUE);
System.out.println("float.precision=" + Float.PRECISION);
System.out.println("double.precision=" + Double.PRECISION);
}
}Float.PRECISION과 Double.PRECISION은 이진 부동소수점 가수의 비트 정밀도를 보여 줍니다.
표현 가능한 최대 크기와 정확히 보존되는 십진 자릿수는 같은 개념이 아닙니다.
식별자 문법과 관례
다음 선언은 컴파일되지 않습니다.
public final class IllegalNames {
public static void main(String[] args) {
int 2age = 45;
int class = 1;
}
}식별자는 숫자로 시작할 수 없고 class 같은 예약어를 변수 이름으로 쓸 수 없습니다.
문자, 숫자, 밑줄, 달러 기호를 조합할 수 있지만 숫자는 첫 글자가 될 수 없습니다.
Java는 대소문자를 구분하므로 age와 Age는 다른 변수지만 이런 차이로 의미를 구분하면 읽기 어렵습니다.
문법상 가능한 다음 이름도 피합니다.
int $ = 45;
int _age = 50;
int a = 60;일반 변수와 메서드는 memberAge처럼 소문자로 시작하는 로어 카멜 케이스를 사용합니다.
클래스는 MemberTypes처럼 대문자로 시작하고, 변경되지 않는 상수는 뒤에서 MAX_AGE처럼 대문자와 밑줄을 사용합니다.
m보다 age, flag보다 active가 값의 단위와 의미를 직접 알려 줍니다.
회원 정보의 타입 설계
회원가입 결과에 나이와 활성 여부를 추가합니다.
이 예제에서는 나이·식별자 인자가 각각 int·long 범위 안의 정수 문자열이며 나이는 1세 이상이라고 가정합니다. 빠진 인자는 기본값으로 채웁니다. 숫자가 아닌 인자의 실패 처리는 다음 장에서 배웁니다.
처음 보는 표현은 다음 뜻으로 읽으면 됩니다.
조건 ? 왼쪽 값 : 오른쪽 값은 조건이 참이면 왼쪽, 거짓이면 오른쪽 값 하나를 고릅니다. 첫 줄은 인자가 있으면 그 값을, 없으면 기본 이메일을 고릅니다.Integer.parseInt와Long.parseLong은 문자열을 각각int,long값으로 바꿉니다."45"와 숫자45를 연결하는 단계입니다.(double) age는 나눗셈 전에 나이를 실수 계산에 참여시키고,age >= minimumAge는 나이가 기준 이상인지boolean으로 만듭니다.
조건 선택은 switch 식과 삼항 연산, 변환 위치는 스코프와 숫자 형변환에서 직접 연습합니다. 여기서는 각 결과가 어느 타입에 담기는지 먼저 따라가세요.
public final class MemberPreview {
public static void main(String[] args) {
String email = args.length > 0 ? args[0] : "[email protected]";
int age = args.length > 1 ? Integer.parseInt(args[1]) : 45;
long memberId = args.length > 2 ? Long.parseLong(args[2]) : 3_000_000_000L;
int minimumAge = 18;
double ageRatio = (double) age / minimumAge;
boolean eligible = age >= minimumAge;
System.out.println("email=" + email);
System.out.println("age=" + age);
System.out.println("memberId=" + memberId);
System.out.println("ageRatio=" + ageRatio);
System.out.println("eligible=" + eligible);
}
}[email protected]
age=45
memberId=3000000000
ageRatio=2.5
eligible=true3_000_000_000L의 L은 리터럴 자체를 long으로 해석하게 합니다.
문자열 인자를 읽을 때도 Integer.parseInt와 Long.parseLong을 구분해야 합니다.
계산 타입은 마지막 저장 타입만 보고 정해지지 않습니다.
연습 문제
MemberValueCatalog를 작성해 다음 값을 적절한 타입과 이름으로 선언하고 출력하세요.
- 회원 나이 90세
- 회원 식별자 9,000,000,000
- 가입 전환율 82.5%
- 활성 여부
- 등급 문자
B - 이메일
[email protected]
큰 정수 리터럴과 변수 이름의 단위가 코드에 드러나야 합니다.
해설 보기
public final class MemberValueCatalog {
public static void main(String[] args) {
int age = 90;
long memberId = 9_000_000_000L;
double signupRate = 82.5;
boolean active = true;
char grade = 'B';
String email = "[email protected]";
System.out.println("age=" + age);
System.out.println("memberId=" + memberId);
System.out.println("signupRate=" + signupRate);
System.out.println("active=" + active);
System.out.println("grade=" + grade);
System.out.println("email=" + email);
}
}위 해설은 문제에서 정한 퍼센트 값 82.5를 사용하지만, signupRate와 출력 라벨만으로는 퍼센트인지 0부터 1 사이 비율인지 알 수 없습니다. 단위를 코드에 드러내라는 조건까지 충족하려면 해당 변수를 signupPercent로 바꾸고 출력에도 %를 붙이세요.
double signupPercent = 82.5;
System.out.println("signupPercent=" + signupPercent + "%");이 출력은 signupPercent=82.5%입니다. 숫자만 맞는 답과 단위까지 분명한 답을 구분해야 합니다.
0.825 비율을 선택한다면 이름을 signupRatio로 바꾸어 단위를 드러냅니다.