특별한 이유없이 패키지, 클래스, 인터페이스, 메서드, 필드, 타입 변수의 철자 규칙을 무시하지 말자.
철자 규칙을 어길 경우,
- API를 사용하기 어렵고 유지보수가 힘들다.
- 다른 누군가가 코드를 읽기 번거롭거나 다른 뜻으로 오해할 수 있어 오류를 야기할 수 있다.
다음은 각 요소별 명명 규칙이다.
- 패키지와 모듈 이름은 점(.)으로 구분해서 계층적으로 짓는다.
- 요소들은 모두 소문자 알파벳 (드물게) 숫자
- 인터넷 도메인 이름을 역순으로 사용한다 (ex.
com.google
,edu.cmu
등) - 표준 라이브러리와 선택적 패키지들은 각각 java와 javax로 시작한다.
- 패키지 이름의 나머지는 해당 패키지를 설명하는 하나 이상의 요소로 이뤄진다.
- 일반적으로 8자 이하의 짧은 단어 (
utilities
와 같은 단어는util
과 같이 의미가 통하는 약어 사용) - 여러 단어일 경우
awt
와 같은 각 단어의 첫 글자
- 일반적으로 8자 이하의 짧은 단어 (
- 보통 인터넷 도메인 이름 뒤에 요소 하나만 붙인 패키지가 많은데,
java.util
과 같은 많은 기능을 제공하는 경우엔 계층을 나눠 더 많은 요소로 구성 가능하다. (ex.java.util.concurrent.atomic
) 이를subpackage
라고 한다.
- 하나 이상의 단어로 이뤄지며, 각 단어는 대문자로 시작 (
List
,FutureTask
등)- 이때, 단어는 줄여쓰지 않지만
max
,min
과 같이 널리 통용되는 줄임말을 허용된다.
- 이때, 단어는 줄여쓰지 않지만
- 약자의 경우 첫 글자만 대문자로 쓰는 것을 권장한다. (ex. HttpUrl vs HTTPURL)
- 각 약자의 시작과 끝이 명확함
- 첫 글자를 소문자로 쓰는 점만 빼면 클래스 명명 규칙과 동일하다
- 상수 필드를 구성하는 단어는 모두 대문자를 사용하며 단어 사이는 밑줄로 구분 (ex. NEGATIVE_NUMBER, VALUES)
- 상수란 static final 필드를 칭하며 필드의 타입이 기본이거나 불변 참조 타입
- 타입이 가변이어도 가리키는 객체가 불변이라면 상수
Google Java Style에서 발췌한 코드
// Constants
static final int NUMBER = 5;
static final ImmutableList<String> NAMES = ImmutableList.of("Ed", "Ann");
static final Joiner COMMA_JOINER = Joiner.on(','); // because Joiner is immutable
static final SomeMutableType[] EMPTY_ARRAY = {};
enum SomeEnum { ENUM_CONSTANT }
// Not constants
static String nonFinal = "non-final";
final String nonStatic = "non-static";
static final Set<String> mutableCollection = new HashSet<String>();
static final ImmutableSet<SomeMutableType> mutableElements = ImmutableSet.of(mutable);
static final Logger logger = Logger.getLogger(MyClass.getName());
static final String[] nonEmptyArray = {"these", "can", "change"};
- 다른 멤버와 비슷한 명명 규칙이 적용되지만 약어를 사용가능
- 변수가 사용되는 문맥에서 의미가 쉽게 유추 가능
- 입력 매개변수 또한 지역변수여서 동일하게 적용가능하지만 메서드 설명 문서에 작성해야하므로 일반 지역번수보다는 신경을 써주어야 함
- 보통 한 문자로 표현한다
- 임의의 타입 -> T (Type)
- 컬렉션 원소의 타입 -> E (Element)
- 맵의 키와 값 -> K, V (Key, Value)
- 예외 -> X (eXception)
- 메서드 반환 타입 R (Return)
- 그 외에 임의 타입 시퀀스 -> T, U, V 혹은 T1, T2, T3
식별자 타입 | 예 |
---|---|
패키지와 모듈 | org.junit.jupiter.api, com.google.common.collect |
클래스와 인터페이스 | Stream, FutureTask, LinkedHashMap, HttpClient |
메서드와 필드 | remove, groupingBy |
상수 필드 | MIN_VALUE, NEGATIVE_INFINITY |
지역변수 | i, denom, houseNum |
타입 매개변수 | T, E, K, V, X, R, U, V, T1, T2 |
철자 규칙보다 더 유연해서 논란이 많다.
- 클래스 이름은 보통 단수 명사나 명사구를 사용 (ex. Thread, PriorityQueue, ChessPiece)
- 객체를 생성할 수 없는 클래스 이름은 복수형 명사 (ex. Collectors, Collections)
- 인터페이스 이름은 클래스와 똑같이 짓거나
able
또는ible
로 끝나는 형용사 (ex. Collection, Comparator, Runnable, Iterable) - 애너테이션은 다양해서 지배적인 규칙이 없음
- 동작을 수행하는 메서드의 이름은 동사나 동사구 (ex. append, drawImage)
- boolean은
has
,is
,can
등을 사용한다
- boolean은
- 반환 타입이 boolean이 아닌 해당 인스턴스의 속성을 반환하는 메서드의 이름은 보통 명사, 명사구, 혹은
get
으로 시작하는 동사구 사용 (ex. size, hashCode, getTime)
if (car.speed() > SPEED_LIMIT) {
generateAudibleAlert("경찰 조심하세요!");
}
🤔 꼭 get으로 시작하는 형태만 써야할까?
위 코드의 경우 get이 없는 코드의 가독성이 더 좋은 것을 볼 수 있음
get
은 주로 JavaBeans 명세에 뿌리를 두고 있어서 해당 도구와 어우러지는 코드를 작성할 때 이 규칙을 따라도 상관없음
또한, 클래스가 한 속성의 게터와 세터를 모두 제공할 때도 적합한 규칙이다
- 객체의 타입을 바꿔서 다른 타입의 객체로 반환하는 인스턴스 메서드는 보통
toType
사용 - 객체의 내용을 다른 뷰로 보여주는 메서드는
asType
to와 as의 차이
to
는 인스턴스가 생성된 입력과는 독립적으로 새 인스턴스를 반환하는 반면,
as
는 한 유형의 객체를 다른 유형의 객체로 나타내기 위해 사용
ex) toString, asList
- 객체의 값을 기본 타입 값으로 반환하는 메서드의 이름은
typeValue
의 형태로 짓는다 (ex.intValue
) - 정적 팩터리 -
from
,of
,valueOf
,instance
,getInstance
등
API를 잘 설계할 경우 필드가 노출될 일이 없으므로 필드 이름은 클래스, 인터페이스, 메서드 이름에 비해 덜 명확하고 덜 중요하다.
표준 명명 규칙을 체화해서 자연스럽게 베어 나오도록 하자.
다만 "오랫동안 따라온 규칙과 충돌한다면 그 규칙을 맹종해서는 안 된다." 상식이 이끄는 대로 따르자.