이 글은 Google Java Style Guide의 내용을 번역하여 핵심만 정리한 글이다.
이후 본문 전체에 대한 번역을 추가하며 수정해 나갈 예정이다.
이 문서는 구글의 Java 코딩 스타일을 정의한 문서이다.
소스 파일은 클래스를 포함하는 이름으로 되어있고 .java
확장자를 가진다.
소스 파일은 UTF-8로 인코딩 된다.
ASCII 가로 공백 문자(0x20)가 유일한 공백 문자
특수 이스케이프 시퀀스는 다음을 사용한다. (\b
, \t
, \n
, \f
, \r
, \"
, \'
and \\
)
8진수 (e.g. \012
) 또는 유니코드 (e.g. \u000a
) 등은 쓰지 않는다.
비 아스키 문자의 경우 유니코드 (e.g. ∞
) 또는 유니코드 이스케이프 (e.g. \u221e
) 등이 있다.
유니코드를 사용하는것이 좋지는 않지만 가독성이 좋다면 써도 되긴 한다.
Examples:
가장 좋은 경우
String unitAbbrev = "μs";
return '\ufeff' + content; // byte order mark
허용되지만 권장되지는 않음
String unitAbbrev = "\u03bcs"; // "μs"
String unitAbbrev = "\u03bcs"; // Greek letter mu, "s"
안됨
String unitAbbrev = "\u03bcs";
소스 파일은 다음 순서대로 작성해야함:
각 섹션은 하나의 빈 줄로 구분
기존의 코드 스타일
package com.ozragwort.moaon.springboot.service.videos;
import com.ozragwort.moaon.springboot.domain.categories.Categories;
import com.ozragwort.moaon.springboot.domain.categories.CategoriesRepository;
import com.ozragwort.moaon.springboot.domain.channels.Channels;
import com.ozragwort.moaon.springboot.domain.channels.ChannelsRepository;
import com.ozragwort.moaon.springboot.domain.videos.*;
import com.ozragwort.moaon.springboot.dto.videos.*;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkArgument;
import static com.ozragwort.moaon.springboot.domain.specs.VideosSpecs.searchWith;
import static com.ozragwort.moaon.springboot.domain.specs.VideosSpecs.VideosSearchKey;
import static com.ozragwort.moaon.springboot.util.Calculation.calcScore;
import static com.ozragwort.moaon.springboot.util.ConvertTo.DurationStringToSecond;
import static com.ozragwort.moaon.springboot.util.ConvertTo.StringToUTCDateTime;
import static java.util.Objects.isNull;
google java code style로 수정된 코드 스타일
/*
* 저작권이 있는 경우 작성
*/
package com.ozragwort.moaon.springboot.service.videos;
import static com.ozragwort.moaon.springboot.domain.specs.VideosSpecs.searchWith;
import static com.ozragwort.moaon.springboot.util.Calculation.calcScore;
import static com.ozragwort.moaon.springboot.util.ConvertTo.DurationStringToSecond;
import static com.ozragwort.moaon.springboot.util.ConvertTo.StringToUTCDateTime;
import static java.util.Objects.isNull;
import static org.h2.mvstore.DataUtils.checkArgument;
import com.ozragwort.moaon.springboot.domain.categories.Categories;
import com.ozragwort.moaon.springboot.domain.categories.CategoriesRepository;
import com.ozragwort.moaon.springboot.domain.channels.Channels;
import com.ozragwort.moaon.springboot.domain.channels.ChannelsRepository;
import com.ozragwort.moaon.springboot.domain.specs.VideosSpecs.VideosSearchKey;
import com.ozragwort.moaon.springboot.domain.videos.*;
import com.ozragwort.moaon.springboot.dto.videos.*;
import java.util.*;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
라이선스 또는 저작권 정보가 있는 경우 추가한다.
패키지 문은 줄바꿈 하지 않고 작성한다. (아무리 길어도 한줄로 쓰라는 의미)
static 또는 기타의 와일드카드 import는 하지 않는다.
아무리 길어도 한줄로 쓰라는 의미이다.
다음 순서대로 import 해야한다.
두 블록 사이는 하나의 빈 줄로 구분한다.
각 블록내에서는 ASCII 정렬로 순서를 정한다.
클래스에는 static import를 하지 않는다.
1 JAVA 파일 1 Class → 하나의 java 파일엔 하나의 Class만 만들자.
클래스의 멤버의 순서는 딱 정해진것은 없지만 논리적인 순서가 있어야 한다.
단순하게 새로운 메서드를 만들때 가장 뒤에 만드는 식으로 만들면 안된다는 의미이다.
여러 생성자, 같은 이름을 가진 메서드 들은 꼭 모아서 순차적으로 나타낸다.
private도 포함해야한다.
예를들어 if
, else
, for
, do
and while
에서 내용이 비어있거나 한줄이어도 중괄호를 꼭 사용함
틀린 예시
if (sum > 0)
return sum;
else
return -1;
옳은 예시
if (sum > 0) {
return sum;
}
else {
return -1;
}
Kernighan & Ritchie 스타일
Examples:
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();
}
}
};
그냥 중괄호를 열고 닫아도 됨.
Examples:
// 됨
void doNothing() {}
// 됨
void doNothingElse() {
}
// 안됨 (try에는 내용이 있기 때문에)
try {
doSomething();
} catch (Exception e) {}
새 블록에 진입할 때 마다 2칸의 space로 들여쓰기를 추가함
명령문 뒤에 줄 바꿈
한 줄에 길이가 100이 넘으면 안됨.
길이의 기준은 모든 유니코드 코드 포인트를 의미함
Exceptions:
한줄의 코드를 여러줄로 나누는 활동을 말한다. 쉽게 말해 엔터치는걸 말한다.
모든 상황에서 정확한 공식은 없지만 여러 방법이 있다.
줄 바꿈을 하게되는 경우는 다음과 같다.
.
)::
)<T extends Foo & Bar>
)catch (FooException | BarException e)
).new StringBuilder()
.append("a")
.append("b");
"a"
+ "b";
StringTokenizer stk = new StringTokenizer(
br.readLine());
public Videos(Channels channels,
String videoId,
String videoName,
String videoThumbnail,
String videoDescription,
LocalDateTime videoPublishedDate,
long videoDuration,
int viewCount,
int likeCount,
int dislikeCount,
int commentCount,
double score,
List<String> tags) {
}
MyLambda<String, Long, Object> lambda =
(String label, Long value, Object obj) -> {
...
};
Predicate<String> predicate = str ->
longExpressionInvolving(str);
줄 바꿈 시 첫 번째 이후 들여쓰기는 최소 +4 space로 들여쓰기한다.
다음의 경우 한 줄의 세로 공백을 나타낸다.
if
, for
or catch
, 뒤에 오는 ((
) 사이에 공백else
or catch
, 와 그 앞에 있는 (}
) 사이에 공백{
), 앞에 공백 예외 두 가지:@SomeAnnotation({a, b})
(공간을 사용하지 않음)String[][] x = {{"foo"}};
(공백이 필요하지 않음{{
, )<T extends Foo & Bar>
catch (FooException | BarException e)
for
문 에서 (for (int n : list)
)(String str) -> str.length()
::
) : Object::toString
.
) :object.toString()
,:;
또는 타입 변경 cast 시 ()
) 뒤에 공백//
) 뒤 공백. 여러개가 가능하지만 필수는 아님List<String> list
new int[] {5, 6}
and new int[] { 5, 6 }
둘 다 사용 가능[]
)or (...
).가독성을 위해 공백을 이용하여 정렬을 하는 경우가 있지만 google 스타일에선 요구되지 않음
private int x; // 괜찮음
private Color color; // 괜찮음
private int x; // 해도 되지만 후에 수정해야함
private Color color; // 괜찮음
코드 작성자와 검토자가 합의한 경우에만 생략된다.
java의 연산자 우선 순위 테이블을 가지고 있다고 해도 가능하면 써야한다.
예를들면 int n = 5 * 3 + 1
로 써도 되지만 가능하면 int n = (5 * 3) + 1
로 쓰라는 말이다.
enum 상수의 각 컴마 다음에 개행은 선택적이다. 추가의 개행도 허용된다. (보통 한번):
private enum Answer {
YES {
@Override public String toString() {
return "yes";
}
},
NO,
MAYBE
}
별다른 documentation이 없는경우 배열 초기화와 같은 포맷으로 작성해도 된다. (4.8.3.1)
private enum Suit { CLUBS, HEARTS, SPADES, DIAMONDS }
int a, b;
이렇게 하지 말라는 의미이다.
하지만 for
문의 헤더에서는 여러 변수 선언이 쓰일 수 있다.
꼭 블럭이 시작될 때 변수를 선언하지 않아도 된다는 의미이다.
하지만 지역 변수는 그 변수가 사용될 곳에서 최대한 가까이 선언하고 선언과 동시에 초기화를 시킨다.
배열 초기화는 "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
처럼 선언할 수 있고, String args[]
처럼 선언하지 않는다.
다른 코드처럼 space +2로 한다.
switch문은 break
, continue
, return
과 같이 switch문을 종료시킬 수 있다. 이런 경우가 아닌 경우 다름 구문을 실행하게 되는데 이 때 주석을 사용할 수 있다. 또한 이 주석은 해당 case의 마지막에 온다. case 1에는 쓰지 않고 case 2에서 한번에 주석을 달면 된다.
switch (input) {
case 1:
case 2:
prepareOneOrTwo();
// fall through
case 3:
handleOneTwoOrThree();
break;
default:
handleLargeNumber(input);
}
default
를 포함default
에서 아무 코드가 없더라도 포함하여 코드를 작성한다.
클래스, 메서드, 생성자에 적용되는 어노테이션은 documentation 블럭 바로 이후에 나열된다.
Example:
@Override
@Nullable
public String getNameIfPresent() { ... }
Exception: 파라미터가 없는 단일 어노테이션은 한줄에 쓸 수 있다.
@Override public int hashCode() { ... }
필드에서 사용되는 어노테이션은 한줄에 쓸 수 있다.
@Partial @Mock DataLoader loader;
이 부분은 단순 주석이다.
Javadoc은 7절에 있다.
/* ... */
, // ...
을 사용할 수 있다. 단 여러 줄의 /* ... */
를 사용하면 두 번째 줄 이후의 *
는 이전 줄의 *
과 정령되어야 한다.
/*
* This is // And so /* Or you can
* okay. // is this. * even do this. */
*/
사용 가능한 클래스와 멤버의 접근 제한자는 다음과 같다. :
long형 숫자의 경우 3000000000l
대신 3000000000L
으로 쓴다.
소문자 l은 숫자 1과 헷갈릴 수 있기 때문이다.
식별자는 ASCII 숫자와 문자만을 사용한다. 일부의 경우 _
를 쓰기도 한다.
하지만 google style에서는 특별한 접미사나 접두사는 쓰지 않는다 : name_
, mName
, s_name
and kName
.는 쓰지않는다.
패키지 이름은 모두 소문자이며 연속된 단어는 단순히 함께 연결된다.
com.example.deepspace
로 쓰고 com.example.deepSpace
or com.example.deep_space
로 쓰지 않는다.
클래스 이름은 "UpperCamelCase"로 작성한다.
주석의 경우 정해진 규칙은 없다.
테스트 클래스의 이름은 해당 클래스의 뒤에 Test를 추가한다.
naming convention의 네 가지 종류
메서드 이름은 "lowerCamelCase"를 사용한다.
상수 이름은 "CONSTANT_CASE"를 사용한다.
상수는 내용이 변경되지 않아야 한다. 따라서 상태가 바뀐다면 상수가 아니다.
// 상수
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(','); // because Joiner is immutable
static final SomeMutableType[] EMPTY_ARRAY = {};
enum SomeEnum { ENUM_CONSTANT }
// 상수가 아님
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"};
"lowerCamelCase"를 사용한다.
"lowerCamelCase"를 사용한다.
"lowerCamelCase"를 사용한다.
E
, T
, X
, T2
)T
를 합쳐서 사용(examples: RequestT
, FooBarT
).가끔씩 "IPv6" 또는 "iOS"와 같이 비정상적인 형식이 있을 수 있다.
따라서 Google Style은 다음과 같은 체계를 사용한다.
Examples:
@Override
: 항상 사용@Override
annotation 은 사용 가능하면 늘 붙인다.
예외 : 부모 함수가 @Deprecated가 되면 @Override를 생략할 수 있다.
다음과 같은 경우가 아닌경우 catch의 내용을 생략하지 말자.
정말 빈칸이어도 되는 경우 주석으로 설명을 써두자.
try {
int i = Integer.parseInt(response);
return handleNumericResponse(i);
} catch (NumberFormatException ok) {
// 숫자가 아니어도 그냥 리턴해도 된다.
}
return handleTextResponse(response);
Exception: 테스트를 할 때, 예외 발생 시 이름을 expected
로 쓰는 경우 주석없이 무시될 수 있다.
try {
emptyStack.pop();
fail();
} catch (NoSuchElementException expected) {
}
정적 클래스 멤버에 대한 참조는 해당 클래스의 이름을 바로 사용하여 작성해도 된다.
Foo aFoo = ...;
Foo.aStaticMethod(); // 좋음
aFoo.aStaticMethod(); // 나쁨
somethingThatYieldsAFoo().aStaticMethod(); // 아주 나쁨
Object.finalize
와 같이 재정의하지 않음
Javadoc의 기본 형식은 다음과 같다:
/**
* Multiple lines of Javadoc text are written here,
* wrapped normally...
*/
public int method(String p1) { ... }
한줄 예제:
/** An especially short bit of Javadoc. */
기본 형식은 항상 허용된다.
단 한줄로 작성하는 경우는 @return
이 없을 때만 가능하다.
문단과 문단 사이에는 하나의 빈 줄이 추가된다. (*)만 포함되는 줄
사용되는 표준 블럭 태그는 @param
, @return
, @throws
, @deprecated
가 있다. 이 네 가지 유형의 설명은 빈칸으로 두면 안된다. 한 줄이 넘어가면 줄 바꿈을 한 뒤 띄어쓰기 4번 이상을 한다.
Javadoc은 해당 내용의 간단한 요약으로 시작한다. 클래스 및 메소드에 대해 나타나는 유일한 부분이기 때문이다.
/** @return the customer ID */
가 아닌 /** Returns the customer ID. */
와 같이 작성해야 한다.
모든 public class
, public
,protected
에서 예외를 제외하고 가능하면 다 쓰자.
Javadoc은 간단하고 명료한 메소드에 경우 선택적으로 사용해도 된다.
예를들면 getFoo
와 같은 경우이다. 이것은 foo를 반환하는것이 너무나 당연하기 때문이다.
overrides 어노테이션을 사용하는 경우 작성하지 않아도 된다.
구현 구석과 착각하여 사용하는 경우가 있을 수 있는데 (/**
를 사용한 경우) 필수가 아닌 Javadoc은 7.1.2, 7.1.3, 7.2와 같은 규칙을 꼭 따라야 하는건 아니지만 권장은 한다.