이 글은 Google Java Style Guide을 번역하고 공부하기 위해 작성되었습니다.
원본을 읽으며 이해하고 이해한 대로 번역했습니다. (잘 모르는 부분은 직역하기도 했습니다.)
틀린 부분이나 번역에 대한 의견이 다르다면 댓글로 말씀 부탁드리겠습니다.
원본은 google.github.io/styleguide/javaguide.html#s1-introduction
에서 볼 수 있습니다.
1 Introduction
이 문서는 구글에서 자바 프로그래밍언어의 소스코드를 작성하는 완전한 구글 코딩 표준을 제공한다. 자바소스파일은 이 문서에 설명되어 있는 규칙을 준수한 경우에만 Google Style이라고 말할 수 있다.
다른 프로그래밍 스타일 가이드처럼, 포멧팅과 같은 미적 주제 뿐만 아니라 다른 타입의 컨벤션 또는 코딩 표준을 적용한다. 하지만 이 문서는 주로 보편적으로 따르는 엄격하고 빠른 규칙에 초점을 맞추고 있으며, 실행할 수 없는 조언들은 주지 않는다.(사람이든 컴퓨터든)
1.1 용어 노트
1. '클래스'라는 용어는 "일반"클래스, enum 클래스, 인터페이스, 어노테이션(@interface)을 모두 지칭한다.
2. 멤버(클래스의)라는 용어는 중첩클래스, 필드, 메소드, 생성자를 포함한다. 즉. 생성자와 주석을 제외한 클래스의 최상위 내용들을 말한다.
3. 주석은 항상 구현한 주석을 말한다. 우리는 "documentation comments" 대신에 "Javadoc"이라는 용어를 사용한다.
이외의 용어 노트들은 문서를 읽다보면 등장한다.
1.2 가이드 노트
문서의 예제코드는 비표준이다. 이 말은, 예제코드들이 Google Style은 지키고 있지만, 코드를 표현하는 적절한 방법을 유일한 방법이라고는 할 수 없다. 예제에 나오는 선택적인 포멧팅들을 규칙으로 생각하면 안된다.
2 소스파일의 기본
2.1 파일이름
파일 이름은 최상위 레벨의 클래스 이름을 포함하고 대소문자를 구분한 이름에 .java 확장자를 붙인다.
(최상위 클래스명을 파일의 이름으로 한다.)
2.2 파일 인코딩 : UTF-8
소스파일은 UTF-8 로 인코딩된다.
2.3 특수 문자
2.3.1 공백 문자
줄 끝내기 문자를 제외하고 아스키코드의 0x20(스페이스)는 유일한 공백문자이다.
1. 문자열 및 문자 리터럴(변수에 넣는 변하지 않는 데이터)의 다른 모든 공백 문자는 이스케이프된다.
2. 탭 문자는 들여쓰기에 사용되지 않는다.
2.3.2 특수 escape sequences
이스케이프 시퀀스(\b, \t, \n, \f, \r, \", \' , \\)들이 쓰인다.
해당하는 8진수 문자나 유니코드 문자보다 위의 문자들이 쓰인다.
2.3.3 Non-ASCII 문자
남은 non-ASCII 문자들은 유니코드 문자(e.g. ∞)와 동일한 유니코드 이스케이프 시퀀스(e.g. \u221e)가 둘 다 쓰인다.
이 선택은 코드의 가독성을 위함이다. (유니코드는 문자열 리터럴 외부에서 이스케이프 되고 주석은 권장되지 않음에도 불구하고)
팁 : 유니코드 이스케이프나 유니코드가 사용되는 경우에도 주석이 유용하게 쓰일 수 있다. 경우에 따라 다르다.
String unitAbbrev = "μs"; | 최고 : 주석없이도 의도가 명확하다. |
String unitAbbrev = "\u03bcs"; // "μs" | 허용되지만이 이렇게 할 이유가 없다. |
String unitAbbrev = "\u03bcs"; // Greek letter mu, "s" | 허용되지만 어색하고 실수하기 쉽다. |
String unitAbbrev = "\u03bcs"; | 나쁨 : 읽는 사람이 어떤 문자인지 알 수 없다. |
return '\ufeff' + content; // byte order mark | 좋음 : 출력 할 수없는 문자에는 이스케이프를 사용하고 필요한 경우 주석을 추가한다. |
팁 : 프로그램이 ASCII문자를 제대로 처리하지 못할 수 도 있다는 생각에 코드의 가독성을 떨어지는 코딩을 하지 말 것. 이런 일이 발생하면 해당 프로그램이 중단되고 수정되어야 한다.
3 소스 파일 구조
소스 파일은 다음의 순서로 구성된다.
1. 라이센스 또는 저작권의 정보(있는 경우)
2. 패키지(package) 구문
3. 임포트(Import) 구문
4. 하나의 최상위 클래스
정확히 하나의 빈 줄이 각 섹션을 구분짓는다.
3.1 라이센스 또는 저작권 정보 (있는경우)
라이센스나 저작권 정보가 파일에 존재하면 여기에 속한다. (파일의 제일 처음)
3.2 패키지 설명
패키지 구문은 줄바꿈이 되지 않는다. ( 한줄에 모두 작성 )
열 제한(4.4, 열 제한:100)에 패키지 구문은 제약을 받지 않는다.
3.3 Import 문
3.3.1 와일드카드를 이용한 임포트는 불가
static이든 아니든, 와일드카드(*)를 이용한 임포트는 사용하지 않는다.
3.3.2 줄 바꿈 불가
Import 구문은 줄 바꿈을 허용하지 않는다.(한 줄에 하나의 임포트문을 완전히 작성)
Import 구문은 열 제한의 제약을 받지 않는다.
3.3.3 순서 및 간격
임포트 구문은 다음과 같이 표현된다.
1. 한 블럭에 static 임포트를 포함
2. 한 블럭에 non-static 임포트를 포함
static import, non-static import가 둘 다 있는 경우 한개의 빈 줄로 두 블록을 구분한다.
import문들 사이에서 위의 경우 이외의 빈 줄은 없다.
각 블록 내에서의 import 구문들은 ASCII 순서로 정렬되어 있어야 한다.(참고 : ';' 앞에 '.'가 있으므로 임포트 구문 내에서는 ASCII 순서가 아니다.)
(문서에는 없음) 그룹핑의 순서는 (static import → google 내부 package → google 외부 package → java → javax) 이다.
3.3.4 클래스에 대한 정적 가져 오기 없음
static 중첩 클래스에서는 static import가 사용되지 않는다.
일반적 import로 사용된다.
3.4 클래스 선언
3.4.1 정확히 하나의 최상위 클래스 선언
소스 파일에는 각각의 최상위 클래스가 존재한다.
3.4.2 클래스의 내용의 순서
멤버들과 초기화들의 순서는 사용자가 신속하게 코드의 의도를 파악하는데 중요하다. 그러나, 하나의 정답은 존재하지 않고 각각의 클래스들은 각자의 다른 방법으로 내용의 순서를 정의한다.
논리적인 순서를 가지고 멤버와 초기화의 순서를 정의하는 것이 중요하다.
누군가가 물었을 때 대답 할 수 있는 논리적인 순서를 말한다.
예를들어 새로운 메소드를 만들었을 때 클래스의 끝에 붙이는 과정을 반복한다면, 이는 '시간적으로 메소드를 만든 순서' 이지 논리적인 순서를 가지지 않는다.
3.4.2.1 오버로드 : 분리 시키지 말 것
클래스가 여러개의 생성자를 가지거나, 같은 이름의 여러개의 메소드를 가진다면, 이들은 순차적으로 작성되어야 한다.
중간에 다른 코드가 끼어 있으면 안된다.(private 로 선언된 멤버라도)
4 포멧팅
용어 노트 : block-like construct 는 클래스, 메소드, 생성자의 바디를 말한다. 4.8.3.1의 배열 초기화를 포함한 모든 배열의 초기화는 block-like construct으로 처리될 수 있다.
4.1 괄호
4.1.1 선택사항인 경우 괄호가 사용된다
괄호는 if, else, for, do와 while 구문에 사용되며, 바디가 없거나 한줄의 구문을 포함해도 괄호가 쓰인다.
4.1.2 비어있지 않은 블록 : K & R 스타일
괄호는 비어있지 않은 블럭과 block-like constructs에서 Kernighan and Ritchie style ("Egyptian brackets")을 따른다.
- 여는 괄호 앞에는 줄 바꿈이 없다.
- 여는 괄호 뒤에서 줄 바꿈이 있다.
- 닫는 괄호 앞에서 줄 바꿈이 있다.
- 닫는 괄호 뒤에서 줄 바꿈이 있다. 단, 구문이 끝나거나 메소드나 생성자, 익명이 아닌 클래스의 내용이 끝났을 때만 적용된다.
예를 들어, else나 콤마가 뒤에 따라오는 괄호는 줄 바꿈이 없다.
예)
return () -> {
while (condition()) {
method();
}
};
return new MyClass() {
@Override public void method() {
if (condition()) {
try {
something();
} catch (ProblemException e) {
recover();
}
} else if (otherCondition()) {
somethingElse();
} else {
lastThing();
}
}
};
Enum 클래스의 경우 몇가지 예외가 있는데, 4.8.1에서 다룬다.
4.1.3 빈 블록 : may be 간결하게
빈 블럭이나 block-like construct는 K&R style을 따를 수 있다. 대안으로, {}괄호 사이에 문자가 없거나 단순 개행이라면 {이후 바로 }가 올 수 있다. 하지만, multi-block에서는 대안을 사용할 수 없다.
(multi-block : if/else, try/catch/finally)
// 가능
void doNothing() {}
// 가능
void doNothingElse() {
}
// 불가능 : multi-block
try {
doSomething();
} catch (Exception e) {}
4.2 블럭 들여쓰기 : +2 스페이스
새 블록이나 block-like construct가 열릴 때 마다 두번의 스페이스가 들여쓰기된다. 블록이 끝나면 이전의 들여쓰기 레벨로 돌아간다.
들여쓰기 레벨은 코드와 주석 둘 다 적용된다.(4.1.2의 예시처럼)
4.3 한 줄에 한 구문
각 구문은 하나의 줄 바꿈을 가진다.
4.4 열 제한 : 100
자바 코드는 100개의 문자 제한이 있다. "문자"는 모든 유니코드를 뜻한다. 아래의 예외사항들을 제외하고 제한을 넘는 모든 상황에서는 4.5에서 설명하는 방법으로 줄 바꿈을 해야 한다.
각 유니코드 포인트는 화면에 길게 나타나든 짧게 나타나든, 하나의 문자로 친다. 예를들어 전각문자를 사용한다면, 이 규칙보다 일찍 줄 바꿈을 수행할 수 있다.
예외:
1. 열 제한을 따를 수 없는 줄 (Javadoc의 긴 URL, 긴 JSNI 메소드 레퍼런스 등..)
2. package, import 구문
3. 주석 줄 안의 쉘 스크립트에 복사-붙여넣기 할 수 있는 커맨드 라인
4.5 줄 바꿈
용어 노트 : 한 줄로 표현해야하는 줄을 여러개의 줄로 나눈다면 줄 바꿈을 했다고 한다.
줄 바꿈을 모든 상황에서 적용할 수 있는 포괄적인 공식은 없다. 하나의 코드에는 줄 바꿈하는 여러가지 방식이 존재한다.
note : 줄 바꿈의 주된 이유는 열 제한을 넘지 않기 위함이다.
하지만 줄 지한을 넘지 않아도 코드 작성자의 의도에 따라 줄 바꿈이 일어날 수 있다.
팁 : 메소드나 지역 변수를 새로 만드는 것이 줄 바꿈을 대신할 수 있다.
4.5.1 어디서 줄 바꿈을 할 것인가
줄 바꿈이 주요하게 지시하는 사항은 : 문법적으로 높은 레벨에서 줄 바꿈을 하는 것이다.
1. 대입 연산자가 아닌 연산자에서 줄 바꿈은 연산자 이전에서 줄 바꿈이 일어난다.(C++이나 Javascript의 구글 스타일 가이드와 다르다.)
- "operator-like" 기호들도 적용된다.
- dot 분리자 ( . )
- 메소드 레퍼런스의 콜론 두개 ( :: )
- 타입 바운딩의 앰퍼센트 ( <T extends Foo & Bar> )
- catch블럭의 파이프 ( catch (FooException | BarException e) )
2. 줄 바꿈이 대입 연산자에 발생하면 대입 연산자 이후 줄 바꿈이 일어난다. 하지만 둘 다 허용된다.
- 이는 향상된 for문의 "assignment operator-like" 콜론에서도 적용된다.
3. 메서드나 생성자 이름 이후에 붙는 매개변수를 위한 '('는 붙고 이후 줄 바꿈이 일어난다.
4. , (콤마)로 연결되어 있다면 앞의 토큰과 같은 단어로 취급한다.
5. 줄은 람다식의 인접한 화살표에서 줄 바꿈이 일어나지 않는다. 람다식이 괄호를 포함하지 않는 하나의 표현을 가지고 있다면, 화살표 이 후에 바로 줄 바꿈이 일어날 수 있다. 예를 들면,
//람다식이 괄호를 포함
MyLambda<String, Long, Object> lambda =
(String label, Long value, Object obj) -> {
...
};
//괄호를 포함하지 않는 람다식
Predicate<String> predicate = str ->
longExpressionInvolving(str);
note : 줄 바꿈의 목적은 clean code이다. 라인을 줄이는데 있지 않다.
4.5.2 들여쓰기는 계속적으로 적어도 +4의 스페이스를 한다
줄 바꿈을 할 때, 적어도 원래 줄에서 +4의 스페이스만큼 들여쓰기를 한다.
여러개의 지속적인 줄이 있다면, 들여쓰기는 +4이상으로 변경이 가능하다. 일반적으로 두개의 지속적인 줄은 구문상 병렬적인 구조를 가지면 같은 들여쓰기 레벨을 가진다.
4.6.3의 수평 정렬은 여러개의 스페이스를 이전 행과의 정렬을 위해 사용하지 않도록 하는 것에 대해 다룬다.
4.6 공백
4.6.1 수직 공백
다음 상황에서는 항상 한줄 공백을 쓴다 :
1. 클래스의 멤버나 초기화의 연속 : 필드, 생성자, 메소드, 중첩 클래스, static 초기화, 인스턴스 초기화
- 예외 : 두 연속된 필드사이의 공백은 선택이다.(물론 두 코드 사이는 비어있어야 한다.) 그런 공백은 필드의 논리적인 그룹을 나눌 때 필 요하다.
- 예외 : enum 상수 사이의 공백줄은 4.8.1에서 언급한다.
2. 문서의 다른 부분에서도 필요하다.(3절의 소스파일 구조, 3.3절의 임포트 그룹핑)
하나의 공백 라인은 가독성을 향상시키는 어디에서나 나올 수 있다. 예를 들어 코드를 논리적인 subsection으로 구성할 때. 첫 멤버나 초기화 전의 공백 또는 마지막 멤버나 초기화 이후의 공백줄은 권장되지 않는다.
multiple하게 지속적인 공백줄은 허용된다. 하지만 권장되지는 않는다.
4.6.2 수평 공백
리터럴, 주석, Javadoc을 제외하고 언어나 다른 스타일의 규칙을 넘어서는 곳에서 다음의 경우에만 ASCII space를 쓴다.
1. 예약어를 분리시킬 때 : if, for, catch같은 예약어 이후 여는 소괄호를 쓸 때 space (if (~))
2.예약어를 분리시킬 때 : else, catch 같은 예약어 앞에 나오는 닫는 중괄호 이후( } else )
3. 여는 중괄호 앞
- 예외 : @SomeAnnotation({a, b}) (공백 없음)
- 예외 : String[][] x = {{"foo"}}; ( {{ 사이 공백없음, by item 8 below)
4. 이항연산자, 삼항연산자의 양쪽에 공백. 아래의 "operator-like" 기호에도 적용된다.
- 타입 바운딩을 연결시키는 앰퍼센트 ( <T extends Foo & Bar> )
- 여러 예외를 처리하는 catch문 안의 파이프 ( catch (FooException | BarException e) )
- 향상된 for문 안의 ':' ( for(int x : a[y]) )
- 람다식의 화살표 ( (String str) -> str.length() )
아래의 경우는 공백이 적용되지 않는 기호이다.
- 메소드의 레퍼런스를 뜻하는 '::' ( Object::toString )
- '.' 구분자 ( object.toString() )
5. , : ;의 뒤에서 공백 사용. 또는 캐스팅의 닫는괄호 뒤에 띄움. ( (string) num )
6. 명령 문장의 끝줄에서 '//'로 시작되는 주석문의 뒤. 여기서는 여러개의 공백이 허용되지만 필요하지는 않다. // 이렇게
7. 변수형과 변수선언의 사이 ( List<Integr> list )
8. 배열의 초기화에서는 아래의 두 경우가 모두 허용된다.
new int[] {5, 6} 과 new int[] { 5, 6 }
9. 타입 어노테이션과 무언가(예를들면 대괄호) 사이에서 공백.
이러한 규칙은 라인의 시작이나 끝에서 추가의 공백을 요구하거나 금지하는 것이 아니다. ; 내부의 공간에서만 말하는 것이다.
4.6.3 수평 정렬 : 절대 요구되지 않음
용어 노트 : 수평 정렬은 윗줄의 단어를 아랫줄의 단어와 열의 위치가 같게 맞추기 위해 여러개의 공백을 사용하는 것이다.
이것은 허용되지만, Google style에서는 절대 필요로 하지 않는다. 이미 사용하고 있는 수평정렬에서도 이는 필요하지 않다고 말할 수 있다.
예시:
private int x; // 괜찮음
private Color color; // 이것도
private int x; // 허용, 하지만 나중에 고쳐야 함.
private Color color; // 정렬되지 않은 채로 둘 수 있음
팁 : 정렬은 가독성을 높인다. 하지만 미래 유지보수에서 문제를 일으킨다. 미래에 한 줄만 수정해야 한다고 생각해보자. 이 수정으로 잘 포멧팅 된 것이 망가질 수 있고 허용되는 사항이다. 이는 코드 작성자에게 신속하게 그 줄 근처의 공백을 조정하라는 지시를 더 자주 내리게 한다. 이는 계단식으로 리포메팅하는 트리거가 된다. 하나의 라인은 "blast radius"를 가지게 되는 것이다. 이는 바쁜 상황에 무의미한 일을 하는 최악의 경우를 초래할 수 있지만, 기껏해야 리뷰어를 느리게 하고 merge 충돌이 나게하는 부적절한 버전 기록 정보에 대한 일 밖에 안된다.
4.7 그룹을 짓는 괄호 : 추천
선택적 그룹핑 괄호는 코드 작성자와 리뷰어가 괄호를 생략해도 잘못 해석될 가능성이 없고, 더 쉽게 읽을 수 있다고 동의할 때 생략가능하다. 모든 독자가 자바의 연산자 우선순위 테이블을 모두 알고 있다고 가정하는 것은 합리적이지 않다.
따라서 연산자 우선순위가 명확하더라도 그룹을 짓는 괄호를 하는 것을 추천한다.
4.8 특수한 구조
4.8.1 Enum 클래스
각 enum 상수는 콤마(,)이후에 열거되며 줄 바꿈은 선택이다. 추가적인 줄 바꿈(보통 한개)는 허용된다.
private enum Answer {
YES {
@Override public String toString() {
return "yes";
}
},
NO,
MAYBE
}
메소드와 문서가 없는 enum 클래스는 4.8.3.1의 배열 초기화와 같은 포멧을 가질 수 있다.
private enum Suit { CLUBS, HEARTS, SPADES, DIAMONDS }
enum 클래스도 클래스이기 때문에, 클래스 포멧팅 규칙이 적용된다.
4.8.2 변수 선언
4.8.2.1 한번 선언에 한개의 변수
모든 변수 선언(필드나 지역)은 하나의 변수를 선언한다 : int a, b; 와 같은 선언은 사용하지 않는다.
예외 : for 반복문에서의 mutiple 선언은 허용된다. ( for( int a, b=0 ; ~ ; ~) )
4.8.2.2 필요할 때 선언
지역 변수는 꼭 포함하는 블록이나 "block-like construct"의 첫 부분에 선언되는 것은 아니다. 대신에, 지역 변수는 사용되는 범위를 최소화 하기 위해 사용되는 첫 번째 지점의 근처에서 선언된다. 보통 지역 변수 선언은 선언과 초기화를 동시에 한다. 또는 선언 이후 즉시 초기화를 한다.
4.8.3 배열
4.8.3.1 배열 초기화 : "block-like"처럼
모든 배열 초기화는 "block-like 구조" 처럼 포멧팅하게 선택할 수 있다.
예) 아래의 네가지 사항은 모두 가능하다.(철저한 list는 아니다)
new int[] { new int[] {
0, 1, 2, 3 0,
} 1,
2,
new int[] { 3,
0, 1, }
2, 3
} new int[]
{0, 1, 2, 3}
4.8.3.2 C-style의 배열 선언은 하지 말 것
대괄호는 변수형에 붙인다. C처럼 변수명에 붙이지 않는다.
String[] args // 허용
String args[[ // 안됨
4.8.4 Switch 구문
4.8.4.1 들여쓰기
다른 블럭들과 같이, switch의 들여쓰기는 +2 space이다.
switch 라벨 이후, 줄 바꿈이 이루어지고, +2 만큼 들여쓰기가 되고, 블록이 오픈된 것 처럼 즉시 쓰인다.
이후의 switch라벨은 블록이 닫힌 것 처럼 이전의 들여쓰기 레벨과 같게 된다.
4.8.4.2 실패로 끝남(fall through) : 주석
switch문 블록 안에서, 각각의 구문은 갑자기 종료될 수 있다. (break, continue, return, 예외발생 에 의하여)
또는 주석으로 실행 될 것을 가리킬 수 있다.
또는 다음 블록으로 넘어갈 수 있다.
실패를 알려줄 수 있는 어떠한 주석이든 충분하다. (보통 // fall through) 이 특수한 주석은 switch블록의 마지막 구문에 올 필요는 없다. 예를 들면 아래를 볼 수 있다.
switch (input) {
case 1:
case 2:
prepareOneOrTwo();
// fall through
case 3:
handleOneTwoOrThree();
break;
default:
handleLargeNumber(input);
}
case 1: 이후에 주석이 없는 것을 보라. 구문 그룹의 마지막에만 오지는 않는다.
4.8.4.3 default 구문은 존재
각 switch문은 default 를 포함해야 한다. default에 해당하는 코드가 없더라도.
4.8.5 어노테이션
각 어노테이션은 documentation block 이후의 클래스, 메소드, 생성자에 바로 적용된다.
그리고 각 어노테이션은 한줄에 하나씩 쓴다.
이 줄 바꿈은 4.5의 줄 바꿈에 포함되지 않는다. 따라서 아래에서 들여쓰기 레벨이 증가하지 않는다. 예를 들면
@Override
@Nullable
public String getNameIfPresent() { ... } // 들여쓰기 되지 않음
예외 : 한개의 매개변수가 없는 어노테이션은 한 줄에 같이 쓸 수 있다. 예를 들면
@Override public int hashCode() { ... }
documentation block 바로 다음의 필드에도 어노테이션이 적용될 수 있는데, 이 경우엔 multiple 어노테이션(매개변수 가능)을 한줄에 쓸 수 있다. 예를 들면,
@Partial @Mock DataLoader loader;
매개변수, 지역변수, 변수형에 포멧팅되는 특별한 규칙은 없다.
4.8.6 주석
이 섹션은 주석의 구현에 관한 것이다. Javadoc은 7장에 나온다.
줄 바꿈 앞에는 임의의 공백과 공백 이후의 구현 주석이 올 수 있다. 이런 주석은 non-blank한 줄이 되게 한다.
4.8.6.1 블럭 주석 스타일
블록 주석은 주변의 코드와 같은 들여쓰기 레벨을 가진다. /* ... */ 또는 // ... 스타일이다.
여러줄 주석 /* ... */은 앞 줄의 *의 위치가 같게 정렬되어야 하며, *로 시작하여야 한다.
/*
* 이건 // 이것도 /* 이것 역시
* 가능 // 가능함 * 할 수 있다. */
*/
주석은 별표 또는 다른 문자로 그려진 박스에 싸이지 않는다.
팁 : 여러행 주석을 쓸 때, automatic code formatters가 행을 re-wrap(문단 형식으로)하게 하고 싶다면, /*....*/을 사용하라.
대부분의 formatter는 // ... 주석을 re-wrap하지 않는다.
4.8.7 수정자(접근 제한자)
클래스와 메소드의 접근 제한자는 자바 언어 명세서에서 권장되는 포멧팅을 사용한다.
한 줄에 같이 쓰인다면 아래의 순서대로 작성한다.
public protected private abstract default static final transient volatile synchronized native strictfp
4.8.8 숫자형 리터럴
long 형 변수는 대문자 L을 접미어로 사용한다. 숫자 자릿수 1과 혼동되지 않게 하기 위해 소문자는 절대로 사용하지 않는다.
예를 들면, 3000000000L로 쓰지 30000000000l 로 쓰지 않는다.
5 네이밍(이름 짓기)
5.1 모든 식별자에 적용되는 규칙
식별자는 ASCII의 문자, 숫자만 쓰며 아래의 소수의 경우 밑줄_을 쓴다. 그래서 각 식별자의 이름은 정규식과 일치한다. /w+
Google Style에서는 특별한 접두사나 접미사를 쓰지 않는다. 예를 들어 name_, mName, s_name, kName같은 경우는 구글 스타일이 아니다.
5.2 식별자 타입에 따른 규칙
5.2.1 패키지 이름
패키지 이름은 모두 소문자로 이루어진다.
_를 쓰지 않으며, 단순히 단어들이 연속으로 쓰여진 형태이다.
com.example.deepspace // 가능
com.example.deepSpace // 불가
com.example.deep_space // 불가
5.2.2 클래스 이름
클래스 이름은 UpperCamelCase로 작성된다.
클래스 이름은 명사 또는 명사구 이다. (예를 들어 Character, ImmutableList)
인터페이스 이름도 명사 또는 명사구이다. 하지만 간혹 형용사 또는 형용사구가 대신할 수 있다.(예를 들어 Readable)
어노테이션 타입은 특별한 규칙이나 널리 알려진 규칙은 없다.
테스트 클래스는 테스트하는 클래스의 이름이 앞에 오고, 뒤에 Test로 마무리한다. (예를 들어 HashTest, HashIntegerationTest)
5.2.3 메소드 이름
메소드 이름은 lowerCamelCase로 작성된다.
메소드는 동사 또는 동사구이다. (예를 들어 sendMessage, stop)
JUnit의 테스트에서는 논리적인 컴포넌트로 분리시키기 위해 밑줄(_)이 나올 수 있다. 각 컴포넌트의 이름은 lowerCamelCase여야 한다.
하나의 전형적인 패턴은 <methodUnderTest>_<state>이다. (예를 들어 pop_emptyStack)
테스트 메소드의 이름을 짓는 정해진 답은 없다.
5.2.4 상수 이름
상수는 CONST_CASE를 사용한다 : 모두 대문자이다. 각 단어는 밑줄(_)로 구분된다.
그렇다면, 상수란 정확히 무엇인가?
상수는 static final 키워드로 정의된 필드이다. 이 필드의 내용은 불변하며, 메소드는 부작용이 있으면 안된다. 이는 원시 자료형, String, 불변 타입, 불변 타입의 불변 collection을 포함한다. 만약 어떤 인스튼스의 상태가 바뀔 수 있다면 이는 상수가 아니다.
그렇지만 단지 절대 변하지 않는 객체로 표현하는 것은 충분하지 않다. 아래를 보자.
// 상수
static final int NUMBER = 5;
static final ImmutableList<String> NAMES = ImmutableList.of("Ed", "Ann");
static final ImmutableMap<String, Integer> AGES = ImmutableMap.of("Ed", 35, "Ann", 32);
static final Joiner COMMA_JOINER = Joiner.on(','); // Joiner는 불변이기 때문에.
static final SomeMutableType[] EMPTY_ARRAY = {};
enum SomeEnum { ENUM_CONSTANT }
// 상수 아님
static String nonFinal = "non-final"; // final 없음
final String nonStatic = "non-static"; // static 아님
static final Set<String> mutableCollection = new HashSet<String>(); // 가변타입 String 사용
static final ImmutableSet<SomeMutableType> mutableElements = ImmutableSet.of(mutable); // 가변타입의 변수로 초기화 함
static final ImmutableMap<String, SomeMutableType> mutableValues =
ImmutableMap.of("Ed", mutableInstance, "Ann", mutableInstance2); // 마찬가지
static final Logger logger = Logger.getLogger(MyClass.getName());
static final String[] nonEmptyArray = {"these", "can", "change"};
이름들은 전형적으로 명사나 명사 구 이다.
5.2.5 상수가 아닌 필드 이름
상수가 아닌 필드는 (static이던 아니던) lowerCamelCase로 작성한다.
상수가 아닌 필드는 명사 또는 명사구이다. (예를 들면 computedValues, index)
5.2.6 매개변수 이름
매개변수의 이름은 lowerCamelCase로 작성한다.
public 메소드에서 한 문자로 된 파라미터 네이밍은 피해야 한다.
5.2.7 지역변수 이름
지역변수는 lowerCamelCase로 작성한다.
final이나 불변인 지역변수는 상수로 생각되어선 안된다. 따라서 상수 스타일로 네이밍하면 안된다.
5.2.8 타입변수 이름
각 타입 변수는 아래 둘 중 하나의 방법으로 이름을 짓는다.
- 하나의 대문자, 선택적으로 하나의 숫자 추가가능 (예를 들면 E, T, X, T2).
- 클래스를 위한 이름형식(5.2.2 클래스 이름 참고) 에 대문자 추가 (예를 들면, RequestT, FooBarT).
5.3 Camel case : 정의
가끔 영어 구를 카멜 케이스로 바꾸는 하나 이상의 근거있는 방법이 있다. "IPv4"나 "iOS" 와 같이 줄임말이나 특이한 구조가 생길 수 있다. 예측 가능성을 높이기 위해 Goolge Style은 아래의 (거의)결정론적 체계를 지정한다.
산문 형식의 이름으로 시작:
1. 구를 순수 ASCII로 변환하고 apostrophes를 없앤다. 예를들어 "Müller's algorithm" 는 "Muellers algorithm"로 바뀐다.
2. 이 결과를 단어로 나누고, 공백과 남은 구두점으로 분리시킨다.(보통 하이푼을 사용 - )
- 추천 : 단어가 이미 널리 쓰이는 관습적인 카멜 케이스로 작성되어 있다면, 단어를 성분으로 분리시킨다. (예를 들어, "AdWords" 는 "ad words" 로) "iOS"는 카멜 케이스가 아니다. 이는 모든 관습을 무시하고 있다. 따라서 이 추천을 적용하지 않는다.
3. 이제 모두 소문자로 바꾼다.(두음문자.줄임말 도) 그리고 다음의 경우에 첫 문자를 대문자로 바꾼다.
- 각 모든 단어를 upper camel case로 변경하거나
- 첫 단어는를 제외한 모든 단어를 lower camel case로 변경
원래 단어의 대.소문자는 거의 전적으로 무시된다.
산문 | 가능 | camel-case 아님 |
"XML HTTP request" | XmlHttpRequest | XMLHTTPRequest |
"new customer ID" | newCustomerId | newCustomerID |
"inner stopwatch" | innerStopwatch | innerStopWatch |
"supports IPv6 on iOS?" | supportsIpv6OnIos | supportsIPv6OnIOS |
"YouTube importer" | YouTubeImporter YoutubeImporter* |
*(YoutubeImporter)는 가능하나 추천되지 않는다.
노트 : 영어의 몇몇 단어들은 애매하게 하이푼 처리가 되어 있다. : 예를 들면 "nonempty"와 "non-empty"는 둘 다 틀리지 않은 단어이다.
따라서 checkNonempty 와 checkNonEmpty는 둘 다 맞는 메소드 이름이다.
6 프로그래밍 연습
6.1 @override : 항상 명시
@Override 어노테이션을 사용할 수 있는 메소드 마다 붙인다. 이는 슈퍼클래스의 메소드를 오버라이딩하고 있음을 표현하거나, 클래스 메소드가 인터페이스 메소드를 구현하고 있음을 표현하거나, 인터페이스 메소드가 슈퍼인터페이스 메소드를 재 구현하고 있음을 표현한다.
예외 : @Override는 부모 메소드가 @Deprecated(사용을 권장하지 않는다는 뜻의 어노테이션)라면 생략 가능하다.
6.2 예외 잡기 : 무시할 수 없음
아래의 사항 빼고는 예외를 잡고 아무 것도 하지 않는 것은 드물다. ( 전형적으로 로그를 남기거나 불가능하다고 판단 되면 AssertionError를 다시 던져준다.)
catch block에서 정말로 아무일도 안하는 것이 적절하다면, 이유를 주석으로 설명한다.
try {
int i = Integer.parseInt(response);
return handleNumericResponse(i);
} catch (NumberFormatException ok) {
// 숫자가 아니다; 괜찮다. 그냥 계속하라
}
return handleTextResponse(response);
예외 : 테스트에서는 예외를 잡고 주석없이 넘어갈 수 있다. 이름이 expected이거나 expected로 시작한다면.
다음은 expected 키워드로 예외가 나올 것이라고 확신할 수 있는 상황에서 흔히 쓰이는 관용구이다. 여기서는 예외를 설명하는 주석 이 필요 없다.
try {
emptyStack.pop();
fail();
} catch (NoSuchElementException expected) {
}
6.3 Static 멤버 : 클래스를 사용할 수 있다.
static 클래스 멤버로의 참조는 사용 할 수 있다는 자격이 있어야 하는데, 클래스의 이름으로 자격을 증명한다. 클래스 타입이나 인스턴스 참조가 아니다.
Foo aFoo = ...;
Foo.aStaticMethod(); // 좋음
aFoo.aStaticMethod(); // 나쁨
somethingThatYieldsAFoo().aStaticMethod(); // 최악
6.4 Finalizers : 쓰지 않는다.
7 Javadoc
7.1 포멧팅
7.1.1 일반적인 형식
Javadoc 블록의 기본 포메팅은 예시를 보자
/**
* Multiple lines of Javadoc text are written here,
* wrapped normally...
*/
public int method(String p1) { ... }
또는 다음의 한줄 예시를 보자
/** An especially short bit of Javadoc. */
기본 형식은 항상 가능하다. 한줄 형식은 전체 Javadoc 블록이(comment markers를 포함한) 한줄에 딱 맞을때 대체해서 쓸 수 있다. 이는 @return같은 블럭태그가 아닌 것이 없을 때 적용 가능하다.
7.1.2 문단
하나의 빈칸이 있는 줄 - 정렬된 *가 제일 앞에 있는 줄 - 이 문단의 사이, 블록 태그의 그룹 앞에 나타난다.
각 문단은 첫 단어가 나타나기 이전에 <p>가 오고 이후 space가 없다.
7.1.3 블록 태그
@param, @return, @throws, @deprecated의 순서대로 블록 태그를 사용하며, 빈 서술에 절대 사용하지 않는다. 블록 태그가 하나의 줄에 부족하다면, 다음 줄에 @의 위치에서 4번의 스페이스 이상을 들여쓰기한다.
7.2 요약 조각
각 Javadoc 블록은 간결한 summary fragment(요약 조각)으로 시작한다. 이 조각은 매우 중요하다 : 이는 클래스 그리고 메소드 인덱스들과 같이 어떤 문맥을 나타내는 유일한 텍스트이다.
조각 - 완전한 문장이 아닌 명사구 또는 동사구
A {@code Foo} is a..., 또는 This method returns... 와 같이 시작하지 않는다. 또한 Save the recode...와 같이 명령문도 아니다.
그러나 조각은 마치 완전한 문장처럼 대문자와 구두점을 가진다.
팁 : 흔한 실수는 /** @return the custumer ID */ 이다. 이는 틀렸고, /** Returns the customer ID. */가 맞다.
7.3 Javadoc은 어디에 쓰이는가
최소한, Javadoc은 모든 public 클래스에서 쓰이고, public클래스의 public 멤버와 protected멤버에서 쓰인다.
아래에 몇가지 예외 사항들이 있긴 하다.
7.3.4에서 설명하는 Non-required Javadoc처럼 추가Javadoc 내용은 작성 가능하다.
7.3.1 예외 : 자기 설명 메소드
getFoo처럼 "간단하고, 분명"한 메소드, 명확하게 "Foo를 반환한다" 만을 의미하는 경우이다.
중요 : 읽는 사람이 알아야 하는 관련 정보를 생략하면 안된다. 예를 들어 getCanonicalName이라는 메소드는 documentation을 생략하면 안된다.(/** Return the canonical name. */이라는 이론적 설명을 포함) 특정 독자는 "canonical name"이라는 용어의 뜻을 모를 것이기 때문이다.
7.3.2 예외 : 오버라이드
Javadoc은 슈퍼타입 메소드를 오버라이드한 메소드를 항상 주석처리하지는 않는다.
7.3.4 Non-required Javadoc
다른 클래스나 멤버는 필요하거나 원하는 대로 Javadoc을 가진다.
구현한 주석이 클래스나 멤버의 전체적인 목적이나 기능을 정의한다면 주석은 Javadoc으로 대신한다. (/** 이용)
Non-required Javadoc은 7.1.2, 7.1.3, 7.2의 엄격한 포멧팅 규칙을 준수하지 않아도 되지만, 그래도 권장된다.
'Java' 카테고리의 다른 글
String과 StringBuilder (0) | 2020.12.06 |
---|---|
Arrays.asList() (0) | 2020.12.06 |
Java 접근지정자 (0) | 2020.11.08 |
JAVA) 제네릭 (0) | 2020.03.24 |
JAVA) collection - Map (0) | 2020.03.24 |