Gogle Java Style Guide를 번역해보자! 오역이 있을 수 있을 수 있습니다.
소스 파일 이름은 포함된 최상위 클래스의 대수문자를 구별하는 이름과 .java
확장자로 구성된다.
소스파일은 UTF-8로 인코딩되어 있다.
줄 끝내기를 제외하고, ASCII horizontal space character (0x20) " "
는 소스파일에 나오는 유일한 공백문자이다. 이것은 다음을 암시한다.
이스케이프(escape)란 특정 문자를 표현하기나 나타내기 위해 역슬래시(
\
)를 사용하는 것을 의미한다. 문자나 문자열 내부에서 띄어쓰기가 아닌 다른 공백문자를 사용하는 경우 역슬래시를 사용해 이스케이프화 시켜주라는 의미인 듯 하다. (\t
:탭 문자,\n
줄 바꿈 문자...)
특수 이스케이프 문자들 (\b, \t, \n, \f, \r, \", \' and \)은 해당 옥텟(\012) 이나 유니코드(\u000a) 이스케이프 대신에 해당 문자가 사용된다.
(유니코드나 옥텟 쓰지말고 그냥 이스케이프 문자를 사용하면 된다)
ASCII 문자가 아닌 경우 유니코드 문자나 유니코드와 동등한 이스케이프가 사용된다. 선택은 오직 어느쪽이 더 읽고 이해하기 쉬운지에 달렸다. 문자열 리터럴이나 주석 외부에서 사용되는 것은 권장되지 않는다.
Tip: 유니코드 이외의 문자를 사용하는 경우, 때때로 유니코드를 사용할 때에도, 보충 설명적인 주석은 매우 도움이 된다.
Tip: 어떤 프로그램이 ASCII 외의 문자를 사용할까봐 당신의 코드의 가독성을 떨어뜨리지 않아야 한다. 만약 그런다면, 그 프로그램은 깨지고 수정되어야 할 것이다.
소스 파일은 다음과 같은 순서로 이루어져 있다.
하나의 공백만이 각 섹션 사이에 존재해야 한다.
만약 라이센스나 저작권이 존재한다면 이 부분에 포함된다.
패키지 구문은 가독성을 위해 줄바꿈하지 않는다. 열의 제한(100자 이내)는 패키지 구문에는 적용되지 않는다.
static 임포트, wiledcard 임포트를 하지 않는다.
와일드카드(wildcard) 임포트:
java.lang.*
처럼 *을 사용해 임포트 하는 것
임포트문은 줄바꿈하지 않는다. 열제한 (100자)는 임포트문에 적용되지 않는다.
임포트문은 다음과 같은 순서를 따른다.
1. 하나의 블럭 안에 모든 static 임포트문
2. 하나의 블럭 안에 모든 static이 아닌 임포트문
static과 static이 아닌 임포트문이 둘 다 있다면, 하나의 빈 줄이 두 블럭 사이를 구분해야 한다. 그외 빈 줄은 없어야 한다.
각 블록 내에서 임포트된 이름은 ASCII 정렬 순서로 나열된다.
Note: ASCII 코드에서 '.'이 세미콜론 ';' 보다 앞에 오므로, 이 부분은 ASCII 순서와 일치하지 않을 수 있다.
(.과 ;의 경우 ASCII 정렬 순서를 고려하지 않고 자바의 import문 문법을 먼저 고려하라는 의미인 것 같다.)
static import는 static nested classes에서 사용되지 않는다. 그것들은 일반적인 임포트를 사용한다.
정적 중첩 클래스 static nested class는 하나의 최상위 클래스 안에서 static으로 선언된 클래스이다. 이 클래스를 static으로 import하지 말고 일반적인 import를 하라는 규칙을 보여주고 있다.
static import (정적 임포트)
- 특정 클래스의 정적(tatic)멤버 (메서드 또는 상수)를 클래스 이름을 명시하지 않고 직접 사용할 수 있게 해주는 기능.
- 코드를 간결하게 작성할 수 있다.
문법:
import static 패키지명.클래스명.정적멤버;
예시:import static java.lang.Math.*; public class Example { public static void main(String[] args) { double result = sqrt(16.0); // Math 클래스의 sqrt 메서드를 직접 사용 System.out.println("Square root of 16: " + result); } }
주의사항: 충돌을 피하기 위해 동일한 이름의 정적 멤버가 다른 클래스에서 사용되는 경우, 명시적인 클래스 이름을 사용해야 한다.
static import를 하면 위의 예시처럼 Math.sqrt
처럼 계속 클래스를 적어주지 않고 바로 sqrt
라는 static 메서드를 사용할 수 있게 된다.
static nested classess (정적 중첩 클래스)
- 중첩 클래스(Nested classess) : 클래스 내부에 정의된 클래스
class OuterClass { // 외부 클래스 // ... class NestedClass { // 중첩 클래스 // ... } }
- 정적 중첩 클래스 (static nested classess) : 내부 클래스는 static 클래스와 아닌 클래스로 구분 가능한데, 그 중 static 클래스.
class OuterClass { // 외부 클래스 // ... class InnerClass { // 내부 클래스 // ... } static class StaticNestedClass { // 정적 클래스 // ... } }
위와 같은 정적 중첩 클래스가 있을 때, 외부에서StaticNestedClass를 사용할 때 일반 import를 사용해야지 import static somepackage.OuterClass.StaticNestedClass;
이런 식으로 static import를 사용하지 말라는 의미인 듯 하다.
소스 파일마다 각자 최상위 클래스가 존재한다.
당신이 결정한 클래스 안의 멤버와 초기화의 순서는 해당 클래스의 학습에 큰 영향을 미친다. 하지만, 그것을 하는 일에 하나의 맞는 방법이 있는 것은 아니다. 다양한 클래스들은 각자의 방법을 가지고 있을 수 있다.
중요한 것은 각 클래스가 특정한 논리적 순서(유지보수자가 물어보면 설명할 수 있는)를 따랴아한다. 예를 들어, 새로운 메서드들을 습관적으로 클래스 끝에 붙이는 것은 권장되지 않는다. 그것은 "시간에 따른 순거"이지 논리적 순서가 아니기 때문이다.
하나의 클래스에서 같은 이름을 공유하는 메서드들(오버로드)은 그 사이 다른 메서드 없이 하나의 연속적인 그룹에 위치해야 한다. 이 규칙은 생성자도 적용된다. 이 규칙은 메서드간 (static이나 private와 같은) 접근 제어자가 다른 경우에도 적용된다.
용어 노트: block-like construct(블럭같은 구조. 중괄호({}
)로 둘러싸인 코드를 말함.)는 클래스, 함수나 생성자의 몸체를 의미한다. 배열 초기화(seciont 4.8.3.1에서의)는 블럭과 같은 구조로 다뤄질 수 있다.
if, else, for, do, while 문에서 몸체가 비어있거나 한 문장만 있는 경우에도 괄호가 사용되어야 한다. 람다 표현식과 같은 선택적 상황에서는 선택적으로 사용될 수 있다.
Consumer<String> lambdaWithoutBraces = s -> System.out.println(s);
Consumer<String> lambdaWithBraces = s -> {System.out.println(s);};
비어있지 않은 블럭과 블럭같은 구조에서 괄호는 Kernighan과 Ritchie 스타일("Egyptian brackets")을 따른다.
예외: 이 규칙들이 세미콜론(;
)으로 끝나는 단일 문인 경우, 여러 문장으로 구성된 블럭이 있을 수 있고, 이 블럭의 열림 괄호는 줄바꿈이 선행되어야 한다. 이런 블럭들은 일반적으로 지역변수의 범위를 제한하기 위해 사용된다. 예를들어 switch 구문 안이 그러하다.
예)
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();
}
{
int x = foo();
frob(x);
}
}
};
Enum 클래스에는 예외가 있다. (4.8.1)
빈 블럭이나 blok-like construct에서 K & R 스타일을 따를 수 있다. 대안으로, 괄호 내에 글자나 줄바꿈 없는 경우 괄호가 열린 직후 닫힐 수 있다.({}
)
multi-block 구문에는 이 규칙이 해당되지 않는다. multi-block이란 여러 블록을 직접 포함하는 구조를 말하며, 예를 들어 if/else
혹은 try/catch/finally
와 같은 경우를 말한다.
예)
// This is acceptable
void doNothing() {}
// This is equally acceptable
void doNothingElse() {
}
// This is not acceptable: No concise empty blocks in a multi-block statement 멀티 블럭 구문에서는 간결한 빈 블럭을 사용할 수 없음.
try {
doSomething();
} catch (Exception e) {}
새로운 블럭이나 block-lick construct가 열리면, 들여쓰기는 2번의 스페이스 공간만큼 증가한다. 블럭이 끝나면 이전의 들여쓰기 단계로 돌아간다. 들여쓰기 단계는 블럭동안 코드와 주석에 모두 적용된다.
한 구문이 끝나면 줄바꿈이 와야 한다.
자바 코드의 열은 100 문자로 제한한다. "문자"란 유니코드 포인트를 말한다. 밑에 서술된 예외들을 제외하고 이 제한을 넘은 라인들은 줄바꿈이 되어야한다.
표시 너비(display width)가 길거나 짧더라도, 각 유니코드 포인트는 하나의 문자로 측정된다. 예를들어, 만약 전체 너비(fullwidth) 문자를 사용한다면, 이 규칙을 엄격하게 요구하는 위치보다 더 빠르게 줄 바꿈을 할 수 있다.
예외:
1. 줄바꿈이 불가능한 경우(ex. Javadoc의 긴 URL, 긴 JSNI 메서드 참조 등)
2. package나 import 구문
3. 쉘(shell)에 복사 붙여넣기 되는 커멘드 라인에 대한 주석
4. 드물게 매우 긴 식별자가 필요한 경우 열 제한을 넘어설 수 있다. 이 경우 "google-java-format"을 사용해 줄바꿈 하는 것이 좋다.
용어 노트: 코드가 하나의 줄에서 여러줄로 나뉠때, 이를 줄바꿈(line-wrapping)이라 한다.
모든 상황에 어떻게 줄바꿈을 해야 하는가에 대한 포괄적이고 결정적인 방식은 없다. 많은 경우 동일한 코드조각들을 줄바꿈하는 데 여러 유효한 방법들이 있다.
Note: 줄을 바꾸는 일반적 이유는 열 제한을 초과하지 않기 위함이지만, 열제한 이내더라도 저자의 재량에 따라 줄을 바꿀 수 있다.
Tip: 메서드나 지역변수를 추출하는 것이 줄 바꿈을 대신할 좋은 방법이 될 수 있다.
줄 바꿈의 첫번째 원칙은, 높은 문법 레벨에서 바꾸는 것이다. 또한:
.
)::
)<T extends Foo & Bar>
)catch (FooException | BarException e)
)예시)
if ((condition1 && condition2) || (condition3 && condition4) { //연산자 이전에 줄바꿈 } someObject .method(); // 점 앞에서 줄바꿈 (catch (FooException | BarException e)). // catch블록 파이프 앞에서 줄바꿈
foreach
)의 콜론에도 적용된다.예)
int result = num1 + num2; // = 앞에서 해도 되고 뒤에서 해도 됨
메서드나 생성자 이름은 열린 괄호((
)와 붙어있어야 한다.
콤마(,
)는 이전 토큰과 붙어있어야 한다.
int a = 5, b = 10, c = 15;
람다의 화살표 바로 옆에서 줄을 바꾸지 않는다. 람다의 body가 중괄호가 없는 하나의 표현식인 경우, 화살표 직후 줄바꿈이 가능하다.
예)
//줄바꿈 하지 않는다. MyLambda<String, Long, Object> lambda = (String label, Long value, Object obj) -> { ... }; //줄바꿈이 가능하다. Predicate<String> predicate = str -> longExpressionInvolving(str);
노트: 줄바꿈의 목표는 분명한 코드를 가지기 위해서다. 최소한의 줄을 가지기 위해서가 아니라.
줄바꿈을 한 경우, 연속되는 코드의 첫 줄은 이전보다 적어도 +4 만큼 들여쓰기 되어야 한다. 계속되는 구문이 여러개인 경우 원하는 만큼 4칸 이상의 들여쓰기가 가능하다. 일반적으로, 두개의 연속되는 문장들이 문법적으로 유사한 요소로 시작되는 경우, 동일한 들여쓰기를 가진다.
4.6.3의 수평 정렬(Horizontal alignment)은, 이전 줄과 맞추기 위해 다양한 크기의 스페이스를 다루는 권장되지 않는 방식에 대해 다룬다.
하나의 공백 라인은 항상 다음과 같을때 나타난다:
클래스의 연속적인 멤버들 혹은 클래스 초기화: 필드, 생성자, 메서드, 중첩 클래스, 정적 초기화, 인스턴스 초기화
이 문서의 다른 섹션( 3.소스파일구조, 3.3.임포트문)에서 요구하는 빈줄도 필요하다.
가독성을 높이는 어디든 공백은 나타날 수 있다. 예를 들어, 코드를 논리적으로 세부항목으로 구조화하기 위해 사용될 수 있다. 첫번째 멤버나 초기화 이전의 빈줄(혹은 멤버나 초기화 이후의 빈줄)은 권장되지도 비권장되지도 않는다.
연속되는 여러 빈줄은 허가되지만, 권장되지는 않는다.
리터럴, 주석, 자바독을 제외하고, 언어나 다른 스타일 규칙으로 요구되는 것을 넘어, 단일 ASCII 공백(space)은 다음과 같은 공간에서만 나타날 수 있다.
(
)와 분리하기 위해.if (condition) // 여기 띄워써야 함
{
)와 분리하기 위해if (condition) {
...
} else { // else 앞에 띄워써야 함
...
}
열림 curly 괄호({
) 앞에서.
@SomeAnnotation({a,b})
공백 사용하지 않는다.String[][] x = {{"foo"}};
{{
사이에는 공백이 필요 없다. (아래의 9번 참조)이항연산자, 삼항 연산자 양쪽에. 다음의 "operator-like"에서도 적용된다.
<T extends Foo & Bar>
catch (FooException | BarException e)
foreach
)의 콜론(:
)에서.(String str) -> str.length()
그러나 다음의 경우에는 띄어쓰기하지 않는다.
::
). Object::toString
.
). object.toString()
.
, :
, ;
뒤에. 그리고 캐스팅의 닫힘 괄호((
) 뒤에.6, 7. 주석이 시작되는 이중 슬래시(//
) 전 후. 여러개의 공백도 허용된다.
타입 변수 사이 List<String> list
배열 선언문 괄호 안의 공백은 선택적이다.
new int[] {5, 6}
, new int[] { 5, 6 }
둘 다 사용 가능타입 애노테이션과 []
사이.
이 규칙은 줄의 시작과 끝에서 띄우는 것에는 해당되지 않는다. 이 규칙들은 내부 공간에서만 적용된다.
용어 노트: 수평정렬(Horizontal alignment)는 이전 줄의 코드와 길이를 맞추기 위해 당신의 코드에 추가적인 스페이스를 두는 것이다.
이 관습은 허용되지만, Google Style에서 필수적이지 않다. 이미 사용된 곳에서 조차도 수평 정렬을 유지할 필요 없다.
예)
private int x; // ok
private Color color; // 이것도 ok
private int x; // 혀옹. 그러나 나중에 수정해야 한다.
private Color color; // 정렬되지 않은 상태로 둘 수도 있다.
팁: 정렬은 가독성을 높일 수 있지만, 미래에 유지보수 문제를 만든다. 코드에서 단 한줄을 수정해야하는 상황을 생각해보자. 이러한 수정이 이전의 정갈했던 코드 정렬을 망칠 수 있다. 이 경우 (아마 당신일)코더는 근처 문장들의 빈칸을 정렬해야 하며, 그것은 연쇄적인 코드 리포맷팅 작업을 유발할 수 있다. 이 한 줄의 코드가 이제는 "폭발 반경"을 가지게 되었다. 이는 최악의 경우 무의미한 작업을 유발하고, 최소 과거 기록 정보를 회손시키며, 리뷰어의 작업을 늦추고 병합 충돌을 악화시킨다.
선택적인 그룹 괄호는 작성자와 리뷰어가 그것없이 잘못 해석될 여지가 없거나, 코드를 쉽고 잘 읽히가 하지 않는 경우 생략 가능하다. 모든 독자가 자바의 연산자 우선순위를 외우고 있다고 추측하는 것은 옳지 않다.
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클래스 역시 클래스이므로, 클래스에 적용되는 포맷팅 형식이 적용된다.
모든 변수 선언declaration (필드 혹은 지역 변수의)은 하나의 변수만 선언 가능하다: int a, b;
와 같은 선언은 사용되지 않는다.
예외: for
루프의 헤더에는 여러 변수가 선언될 수 있다.
for (int i = 0, j = 0; i < 10; i++, j++) {
// 루프 내용
}
지역변수는 그것을 포함하는 블럭이나 block-like construct의 시작부분에서 습관적으로 선언하지 않는다. 대신, 범위를 좁히기 위해 지역 변수는 그것의 첫 사용 (근거가 있는) 근처에서 선언 되어야 한다. 지역변수는 일반적으로 선언되고 즉시 초기화 된다.
배열 초기화는 "block-like construct"처럼 형성될 수 있다. 다음과 같은 예시들은 사용 가능하다. (다른 형태도 더 있을 수 있다)
new int[] { new int[] {
0, 1, 2, 3 0,
} 1,
2,
new int[] { 3,
0, 1, }
2, 3
} new int[]
{0, 1, 2, 3}
변수가 아니라 타입에 대괄호가 붙어야 한다.
String[] args
(O)String args[]
(X)용어 노트: 스위치 블럭의 괄호 안에는 하나 이상의 구문 그룹이 있다. 각 구문은 하나 이상의 switch 라벨(case FOO:
혹은 default;
)구성 되고, 하나 이상의 명령문(마지막 명령문인 경우 0개 이상)으로 구성된다.
다른 블럭처럼, switch 블럭 안의 내용들은 +2 들여쓰기를 해야한다.
swtich 라벨 이후 한 줄을 띄우고, 블럭이 열렸을 때 처럼 +2 들여쓰기를 시행해야 한다. 따라오는 switch 라벨은 블록이 닫힌 것처럼 이전의 들여쓰기로 적용한다.
switch 블럭 내에서 각 문장그룹은 갑작스럽게 종료될 수 있다(break
, continue
, return
이나 예외를 던지면서). 혹은 주석을 남기고 다음 구문으로 진행되도록 할 수 있다. 다음 구문으로 넘어가는 fall-throgu의 경우 주석을 남기는 것이 권장된다.(일반적으로 // fall through
). 이 주석은 switch 블럭의 마지막 구문에서는 필요하지 않다.
switch (input) {
case 1:
case 2:
prepareOneOrTwo(); // << break가 없어 case3가 실행되게 된다. 이런 경우 주석 권장
// fall through
case 3:
handleOneTwoOrThree();
break;
default:
handleLargeNumber(input);
}
모든 switch문은 그 그룹이 코드를 포함하고 있지 않더라도 기본(default
)문을 포합해야 한다.
예외: enum타입의 swtich 구문은 가능한 모든 타입을 다루었다면 default 구문을 생략할 수 있다. 이를 통해 IDEs와 같은 분석 도구가 오류를 보여주도록 만들 수 있다.
'타입 사용 애노테이션(type-use annotations)'은 애노테이션 지정 타입 바로 앞에 위치한다. @Target(ElementType.TYPE_USE)
를 가진 애노테이션을 type-use annotation이라 할 수 있다.
예를 들어:
final @Nullable String name;
public @Nullable Person getPersonByName(String name);
클래스에 적용되는 애노테이션은 documentations block 직후, 클래스 선언 위에 나타날 수 있다. (한 줄 당 애노테이션) 이 줄 바꿈(line breaks)은 line-wrapping으로 간주되지 않으므로 들여쓰기 수준은 증가하지 않는다.
예:
@Deprecated
@CheckReturnValue
public final class Frozzler { ... }
line-breaks: 줄 바꾸는 행위
line-wrapping: 한줄의 코드가 컬럼 한계(column limit)을 초과할 때 코드를 여러줄로 나누는 행위
위 클래스에 적용되는 애노테이션(4.8.5.2)의 규칙과 동일하다.
예)
@Deprecated
@Override
public String getNameIfPresent() { ... }
예외: 하나의 매개변수가 없는 메서드의 애노테이션은 아래와 같이 signature 앞에 나타날 수 있다.
@Override public int hashCode() { ... }
다큐멘테이션 주석 뒤 바로 애노테이션을 적용할 수 있다. 그러나 이 경우, 여러 애노테이션을 (매개변수를 가질수도 있는) 한 줄에 둘 수 있다.
예)
@Partial @Mock DataLoader loader;
파라미터와 지역 변수 애노테이션의 특정한 양식은 없다.(물론 annotation이 type-use annotation인경우는 제외)
이 섹션에서는 구현 주석(implementation comments)을 다룬다. 자바독은 Section7에서 별도로 다룬다.
특정 줄 바꿈 이전에, 임의의 공백을 두고 구현 주석을 작성할 수 있다. (줄바꿈 이전까지는 주석이라는 의미인 듯 하다.) 해당 주석으로 해당 라인은 공백이 아니게 된다.
블럭 주석 스타일은 둘러쌓인 코드와 같은 들여쓰기 레벨을 가진다. 이것은 /* ... */
스타일이나 // ...
안에 있을 수 있다. 여러 줄의 /* ... */
주석인 경우, 연속되는 코드들은 반드시 해당 줄의 코드 전에 *
로 시작되어야 한다.
예)
/*
* This is // And so /* Or you can
* okay. // is this. * even do this. */
*/
주석을 별표 (asterisks)나 다른 문자로 만들어진 상자안에 동봉해서는 안된다.
이런 식으로 만들지 말라는 소리인 듯 하다
/*************
* This is a comment.
*************/
팁: 여러줄의 주석을 작성할 때, 필요 시 문단 스타일로 자동 코드 양식으로 re-wrap하고 싶은 경우 /* ... */
를 사용하라. 대부분의 formatters의 //...
주석 스타일은 re-wrap을 제공하지 않는다.
클래스와 멤버가 접근 제한자를 가질때, 그것들은 Java Language 설명서에서 추천하는 순서로 등장해야 한다.
public protected private abstract default static final transient volatile synchronized native strictfp
long
을 사용하는 경우 대문자 L
접미사를 사용하고, 소문자 사용은 권장되지 않는다. (1과 혼동될 수 있다.)
3000000000L
(O)3000000000l
(X)식별자는 ASCII 문자와 숫자만 사용한다. 드물게 _
를 쓰기도 한다. 따라서 유효한 식별자는 정규식 \W+
와 매칭된다.
Google Style에서 특별한 접두사, 접미사는 사용되지 않는다. 예를들어 다음과 같은 예시들은 Google Style이 아니다:
name_
, mName
, s_name
, kName
_
도 안 됨) com.example.deepspace
com.example.deepSpace
, com.example.deep_space
클래스 이름은 UpperCamelCase로 작성되어야 한다.
UpperCamelCase
- 각 단어의 첫 글자가 대문자로 시작된다.
- ex. 'MyClass', 'PersonInfo', 'CarModel'
클래스명은 일반적으로 명사나 명사구이다. 예를 들어, Character
나 ImmutableList
이다.
인터페이스의 이름은 명사나 명사구일 수 있다. (예를들어, List
) 그러나 때때로 형용사나 형용사구 일 수 있다. (예를들어, Readable
)
애노테이션 타입에 권장되는 규칙은 없다.
테스트 클래스는 이름 끝에 Test
가 붙는다. 예를들어, HashIntegrationTest
. 그것이 하나의 클래스만을 다룬다면, 그것의 내임은 클래스명+Test
가 될 수 있다.
메서드명은 lowerCamelCase로 작성되어야 한다.
lowerCamelCase
- 첫 단어 첫 글자는 소문자로 시작하며, 나머지 단어의 첫 글자는 대문자로 시작한다.
- ex. myVariable, getUserInfo, carModel
메서드명은 일반적으로 동사, 혹은 동사구이다. 예를 들어 sendMessage
, stop
.
JUnit 테스트에서 각 구성요소들은 lowerCamelCase를 지킨 상태에서, 논리적으로 요소들을 구분하기 위해 언더스코어(_)가 사용될 수 있다. (ex. transferMoney_deductsFromSource
) 테스트 메서드 명명에 하나의 정확한 방법은 없다.
상수명은 UPPER_SNAKE_CASE를 사용한다.: 모두 대문자이고 각 단어들은 하나의 언더스코어로 구분한다. 그전에 상수는 무엇일까?
상수는 불변하는 내용을 가졌으며, 부수효과가 없는 메서드를 가진 static final 필드이다. 기본 타입, 문자열, 불변하는 값 클래스들, 그리고 null
로 설정된 것들이 포함될 수 있다. 만약 특정 인스턴스의 상태 변화가 관찰될 때, 그것은 상수가 아니다. 단순히 객체를 변화시키지 않으려는 의도만으로는 부족하다.
예)
// 상수
static final int NUMBER = 5;
static final ImmutableList<String> NAMES = ImmutableList.of("Ed", "Ann");
static final Map<String, Integer> AGES = ImmutableMap.of("Ed", 35, "Ann", 32);
static final Joiner COMMA_JOINER = Joiner.on(','); // because Joiner is immutable
static final SomeMutableType[] EMPTY_ARRAY = {};
// 상수가 아닌 것들
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 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"};
이 이름들은 일반적으로 명사나 명사구이다.
상수가 아닌 필드(static같은) 이름들은 lowerCamelCase로 작성한다.
이러한 이름들은 일반적으로 명사, 명사구이다.
예를들어, computedValues
, index
와 같이.
파라미터 이름은 lowerCamelCase로 작성한다.
public 메서드에서 하나의 문자를 가진 파라미터는 사용하지 않는다.
public void foo(int a) {} // 사용 X
지역변수 이름은 lowerCamelCase로 작성한다.
final이고 불변할 때에도 지역변수는 상수로 고려되지 않으며 상수 스타일로 사용되어선 안된다.
각 타입 변수 이름은 다음 두 스타일 중 하나로 적혀야 한다.
E
, T
, X
, T2
T
를 덧붙이는 클래스 네이밍 형식 (5.2.2 클래스명 참조)RequestT
, FooBarT
때때로 영어를 camel case로 변경하는 하나 이상의 방식이 존재한다. 예를들어 약어(acronyms, 첫글자만 대문자로 표기한 약어)나 IPv6이나 iOS와 같은 비정형적인 구조가 있다. Google Style은 가독성 증진을 위해 다음과 같은 거의 결정적인 방법을 명시하고 있다.
산문형태의 이름으로 시작:
본 단어의 대소문자는 거의 무시된다.
설명이 복잡해서 더 혼란스러울 수 있는데, lowerCamelCase
처럼 첫 단어만 모두 소문자이고, 그 다음 단어부터는 첫 글자를 대문자로 하면 된다.
예)
@Override
애노테이션이 사용 가능하면 이 애노테이션을 사용 한다. 이것은 클래스가 슈퍼클래스 메서드를 override할때, 클래스의 메서드가 인터페이스의 메서드를 구현할 때, 인터페이스 메서드가 슈퍼인터페이스의 메서드를 재구현할 때를 표함한다.
예외: 부모 메서드가 @Deprecated
(사용이 권장되지 않음)일 때 @Override
는 생략 가능하다.
아래에 언급된 경우를 제외하고 처리된 예외에 대해 언급하지 않는 것은 적절하지 않다. (일반적으로 로그를 남기거나, 그것이 불가능하다면 AssertionError
로 다시 던진다.)
AssertionError
Java에서 제공하는 예외 클래스 중 하나로, 주로 단언문(assert)이 실패했을 때 발생한다. 이 단언문은 프로그램이 특정 조건을 만족하는지 확인하고, 조건이 충족되지 않으면 AssertionError를 던지며 프로그램을 중단시킨다.
assert value > 0;
와 같이 사용 시, value가 >0을 만족할때는 아무런 영향을 미치지 않지만 이를 충족하지 못하면 JRE가 AsertionError 예외를 던진다. 이는 '프로그래머가 표명한 조건식이 성립하지 않았다'라는 의미이다.
만약 캐치 블럭에서 아무것도 하지 않는것이 실제로 적절하다면, 이것이 정당한 이유에 대해 주석으로 설명되어야 한다.
try {
int i = Integer.parseInt(response);
return handleNumericResponse(i);
} catch (NumberFormatException ok) {
// 숫자가 아님; 괜찮으니 넘어감
}
return handleTextResponse(response);
예외: 테스트에서, 만약 그것의 이름이 expected
로 시작된다면 주석 없이 무시될 수 있다. 아래는 예상한 예외를 던지는 코드와 관련해 일반적인 관용구로 주석이 필요하지 않다.
try {
emptyStack.pop();
fail();
} catch (NoSuchElementException expected) {
}
정적(static) 클래스 멤버에 참조해야 할 경우, 클래스명으로 참조하는 것이 적절하다. 해당 클래스의 타입을 사용한 참조reference나 표현식expression이 아니라.
Foo aFoo = ...;
Foo.aStaticMethod(); // 클래스명: good
aFoo.aStaticMethod(); // 참조명:bad
somethingThatYieldsAFoo().aStaticMethod(); // Foo인스턴스를 생성하는 메서드: very bad
Object.finalize
를 오버라이드 하는 것은 극히 드물다.
팁: 하지마라. 만약 당신이 필요하다면, Efective Java Item 8: "Avoid finalizers and cleaners"를 신중히 읽고 이해해고 나서, 하지마라.
Javadoc의 일반적 형태는 아래와 같다.
/**
* Multiple lines of Javadoc text are written here,
* wrapped normally...
*/
public int method(String p1) { ... }
혹은 한줄인 경우:
/** An especially short bit of Javadoc. */
기본폼은 항상 사용 가능하다. 한줄양식은 주석기호를 포함하여 Javadoc 블럭의 전체 코드가 한 줄에 맞는다면 사용 가능하다. 이는 @return
과 같은 블럭 태그가 없을 때 적용 가능하다.
하나의 빈 줄-즉 오직 asterisk(*
)만 포함하는 줄-은 단락 사이와 블록 태그 그룹 앞에 나타난다. 가장 첫 번째 문단을 제외하고 모든 문단은 첫번재 단어앞에 <p>
를 가져야 한다.(이후 스페이스를 두지 않는다.) 다른 HTML 블럭 단위 요소(<ul>
이나 <table>
과 같은)는 <p>
태그를 선행하지 않는다.
javadoc의 설명을 HTML을 이용해 작성하기도 한다.
/**
* <p>This is a JavaDoc comment that uses HTML markup.</p>
* <p>You can create links using <a> tags: </p>
* <ul>
* <li>Item 1</li>
* <li>Item 2</li>
* </ul>
* <p>And so on...</p>
*/
public class ExampleClass {
// Class code here
}
다음의 일반적인 "블록 태그 block tags"들이 사용되면, 다음과 같은 순서로 나열된다.: @param
, @return
, @throws
, @deprecated
. 그리고 이 4개의 타입들은 설명을 비워두지 않는다. 블록 태그들이 한 줄에 맞지 않으면, 이어지는 줄은 @
로 부터 4칸 스페이스바 만큼 들여써야 한다.
/**
* 메서드 설명
*
* @param num1 파라미터1 설명
* @param num2 파라미터2 설명
* @return 리턴값 설명
* @throws IllegalArgumentException 예외상황 설명
*/
public int plus(int num1, int num2) {
if (num1 < 0 || num2 < 0) {
throw new IllegalArgumentException("Input values must be non-negative.");
}
return num1 + num2;
}
이런식으로 순서대로 사용 가능하다.
Javadoc은 간단한 요약 문구로 시작된다. 이 요약은 아주 중요하며, 클래스 및 메서드 색인(method index)와 같이 특정 위치에 나타나는 내용들이다.
완벽한 문장이 아니라 명사구나 동사구 조각이다. 이것은 A {@code Foo} is a...
나 This method returns...
, Save the record
와 같은 명령문형식으로 시작되지 않는다. 하지만, 이는 완성된 문장처럼 대문자로 시작되고 구두점으로 끝난다.
팁: /** @return the customer ID */
이런식으로 흔히 잘못 작성하곤 한다. 이것은 적절하지 않으며, /** Returns the customer ID. */
이같이 변경되어야 한다.
최소한, 자바독은 모든 public 클래스 또는 protected 멤버마다 있어야 한다. 단 아래와 같이 몇몇의 예외는 있을 수 있다.
(7.3.4섹션의 Non-required Javadoc에서 설명된 것 처럼 추가적인 자바독 내용이 포함될 수 있다.)
자바독은 getFoo()
와 같이 "단순, 명료"한 멤버들에게는 선택적이다. 이처럼 "Returns the foo"외의 유의미한 설명이 없는 경우 자바독을 생략할 수 있다.
중요: 일반적인 독자에게 유의미한 정보를 생략하기 위해 이 예외를 언급하는 것은 부적잘하다. 예를 들어, 메서드명 getCanonicalName
의 경우, 독자가 "canonical name"의 의미에 대해 모를 수 있으므로 (/** Returns the canonical name. */
이 주석으로 충분하다는 근거를 들며)주석을 생략해서는 안된다.
Javadoc은 슈퍼타입 메서드를 override하는 메서드에 항상 존재하는 것은 아니다.
다른 클래스와 멤버들은 필요하거나 원하는 자바독을 가지고 있다.
클래스와 멤버의 전반적인 목적이나 행위를 정의하기 위해 주석(implementations comment)이 요구되는 경우, 그 주석은 Javadoc을 사용한다.
불필요한 자바독은 섹션 7.1.1, 7.1.2, 7.1.3, 7.2를 엄격하게 따를 필요는 없으나, 권장된다.
해석 관련:
중첩클래스 관련:
AssertionError 관련: