변수란
변수는 값을 담는, 이름이 붙은 상자입니다. 자바에서 모든 변수는 고정된 타입을 가지며 — 선언할 때 정해집니다 — 그 타입은 결코 바뀌지 않습니다. 바로 이 점이 자바를 정적 타입 언어로 만듭니다. 컴파일러는 프로그램이 실행되기 전에 모든 변수의 타입을 알고 있으며, 상자에 잘못된 종류의 값을 넣는 코드는 컴파일을 거부합니다.
선언은 세 부분으로 이루어집니다. 타입, 이름, 그리고 (대개) 초기값입니다.
int age = 30;은 "age라는 이름의 int를 만들고 그 안에 30을 넣어라"로 읽습니다. 세미콜론은 문장을 끝내며, 이는 주석 페이지에서 모든 문장이 그렇게 한다고 보여준 것과 같습니다.
지금 선언, 나중에 할당
선언과 첫 할당을 분리할 수 있습니다. 타입은 선언할 때 한 번만 나오고, 그 후에는 이름과 =만으로 할당합니다.
초보자가 걸려 넘어지는 규칙이 하나 있습니다. 지역 변수는 읽기 전에 반드시 값을 할당해야 합니다. 컴파일러는 이를 추적하여, 초기화되지 않은 지역 변수를 읽는 코드를 거부합니다.
int score;
System.out.println(score); // compile error: variable score might not have been initialized
이는 귀찮은 것이 아니라 기능입니다. 프로그램이 실행되기도 전에 한 부류의 버그 전체를 잡아줍니다.
이름 규칙과 관례
자바는 몇 가지 엄격한 규칙을 강제하고, 그 위에 관례를 얹습니다. 규칙은 이렇습니다. 이름에는 글자, 숫자, _, $를 쓸 수 있지만, 숫자로 시작할 수 없고, 예약어(int나 class 같은)일 수 없으며, 대소문자를 구분합니다(age와 Age는 서로 다른 두 변수입니다).
모두가 따르는 관례는 이렇습니다.
- 변수와 메서드는
camelCase를 씁니다:firstName,totalScore. - 상수는
UPPER_SNAKE_CASE를 씁니다:MAX_USERS. - 이름은 값을 설명해야 합니다:
c가 아니라count,x가 아니라userEmail.
명확한 이름은 장식이 아닙니다. 미래의 당신이 코드를 읽어내는 방식 그 자체입니다. totalPrice = itemCount * pricePerItem은 t = c * p가 결코 그럴 수 없는 방식으로 스스로를 설명합니다.
타입 안정성: 상자는 자신의 타입을 지킨다
타입은 선언 시점에 고정되므로, 변수에 잘못된 타입의 값을 떨어뜨릴 수 없습니다. 이는 실수를 컴파일 시점에 잡아줍니다.
int age = 30;
age = "thirty"; // compile error: incompatible types - String cannot become int
숫자 타입 사이의 할당은 확대 변환(widening) 규칙을 따릅니다. 작은 타입은 큰 타입으로 자동으로 흘러 들어가지만, 그 반대는 안 됩니다. 이는 데이터 타입과 타입 캐스팅 페이지에서 자세히 다루겠습니다. 지금은 컴파일러가 지켜보고 있다는 것만 알아 두면 됩니다.
var 키워드
자바 10부터는 타입 대신 var를 쓰고, 컴파일러가 우변의 값으로부터 그것을 추론하게 할 수 있습니다.
var는 동적 타이핑이 아닙니다. name은 String name이라고 썼을 때와 똑같이 String이며, 나중에 거기에 int를 할당할 수는 여전히 없습니다. 단지 타이핑을 줄여줄 뿐입니다. 함정은 이렇습니다. var는 추론할 초기화 식이 필요하므로 var x;는 불법이고, 지역 변수에서만 동작합니다 — 필드, 메서드 매개변수, 반환 타입에는 절대 쓸 수 없습니다. 우변에서 타입이 명백할 때 사용하고, 명시하는 편이 더 명확할 때는 타입을 직접 써 주세요.
final로 만드는 상수
값이 한 번 설정된 뒤 결코 바뀌어서는 안 된다면 final로 표시하세요. 그것을 재할당하려는 어떤 시도든 컴파일 에러가 됩니다.
final은 의도를 전달하고("이것은 고정된 값이다"), 컴파일러가 당신을 대신해 그것을 지키게 합니다. 값이 개념적으로 상수일 때 — 요율, 한도, 설정 키 등 — 주저 없이 사용하세요. 그러면 실수로 인한 재할당이 조용히 버그로 배포되는 대신 잡힙니다.
변수 스코프
변수는 그것이 선언된 블록 — 즉 { ... } — 안에서만 존재하며, 닫는 중괄호에서 소멸합니다. 이것이 그 변수의 스코프입니다. 반복문이나 if 블록 안에서 선언된 변수는 그 바깥에서는 보이지 않습니다.
i와 square는 모두 반복문에 속하며 반복문이 끝나면 사라집니다. total은 바깥 블록에서 선언되었으므로 살아남습니다. 실무적인 교훈은 이렇습니다. 각 변수는 그것이 필요한 가장 작은 블록에서 선언하세요. 좁은 스코프는 주의를 다투는 이름이 줄고, 값이 설정된 곳에서 멀리 떨어져 그 값을 오용할 가능성이 줄어듦을 뜻합니다.
다음: 데이터 타입
이 페이지의 모든 변수는 타입으로 시작했습니다 — int, double, String, boolean. 다음 페이지에서는 자바의 데이터 타입을 자세히 분해합니다. 여덟 가지 기본형, 각각의 크기, 기본형과 객체의 차이, 그리고 언제 어떤 타입을 골라야 하는지를 다룹니다.
자주 묻는 질문
자바에서 변수를 어떻게 선언하나요?
타입을 먼저 쓰고, 그다음 이름을 쓰며, 선택적으로 값을 할당합니다: int age = 30;. 타입(int)은 변수의 생애 동안 고정되고, 이름(age)은 그 변수를 참조하는 방법입니다. 이를 선언과 이후의 할당으로 나눌 수도 있지만 — int age; age = 30; — 지역 변수를 읽기 전에는 반드시 값을 할당해야 합니다.
자바의 var 키워드는 무엇인가요?
자바 10부터 var를 사용하면 컴파일러가 할당한 값으로부터 지역 변수의 타입을 추론합니다: var name = "Ada";는 name을 String으로 만듭니다. 그래도 여전히 정적 타입이며, 타입은 실행 시점이 아니라 컴파일 시점에 고정되어 동적이지 않습니다. var는 초기화 식이 있는 지역 변수에서만 동작하며, 필드나 매개변수, 초기화되지 않은 선언에는 절대 쓸 수 없습니다.
자바에서 상수를 어떻게 만드나요?
final 키워드를 붙입니다: final double PI = 3.14159;. 일단 할당되면 final 변수는 재할당할 수 없으며, 컴파일러가 모든 시도를 거부합니다. 관례적으로 상수는 일반 변수와 구분되도록 UPPER_SNAKE_CASE로 작성합니다.