Skip to content

01 Java Coding Convention

The Shinee edited this page Aug 6, 2024 · 1 revision

✍ Java Style

구글의 코딩 컨벤션을 참조한다.

GitHub - JunHoPark93/google-java-styleguide: Google의 Java StyleGuide를 번역한 문서 📝

1. 개요

이 문서는 구글의 Java언의 코딩 표준의 완벽한 정의 문서이다. 자바 소스 파일은 이 문서의 규칙을 고수해야만 Google Style이라 칭할 수 있다.

다른 프로그래밍 스타일 가이드처럼, 주제들은 포매팅같은 심미적인 주제뿐만 아니라, 다른 관습들 혹은 코딩 규칙들도 포함한다. 그러나 이 문서는 우리가 보편적으로 따르는 엄격한 규칙에 초점을 맞추고 있으며 명백히 실행할 수 없는 조언들을 주는 것을 지양한다.

2. 수정

해당 내용을 프로젝트에 맞게 수정하였다.

Doc의 내용은 없애고, 자주 의견이 달라질 수 있는 부분만 정리하였다.

☕Java Coding Convention

참조자료

기본적인 자바 코딩 컨벤션은 구글의 컨벤션을 기본으로 한다.

원문 주소 : https://google.github.io/styleguide/javaguide.html

1 소스파일들의 기본

1.1 파일 명

소스 파일들의 이름은 최상위 클래스들을 포함하는 대소문자를 구별하는 이름들로 되어 있고 .java 확장자를 가지고 있다.

1.2 파일 인코딩: UTF-8

소스 파일들은 UTF-8로 인코딩 되어 있다.

2 소스 파일 구조

소스 파일들은 아래와 같이 구성되는 것이 좋다.

  1. 라이센스나 저작권 정보 (만약 있다면)
  2. 패키지(Package) 구문
  3. 임포트(Import) 구문
  4. 정확히 하나의 최상위 클래스

2.1 클래스 정의

2.1.1 정확히 최상위 클래스 하나를 정의

소스 파일마다 각자의 최상위 클래스가 존재한다.

2.1.2 클래스 내 인스턴스 순서 정하기

클래스 내 인스턴스 순서는 유지보수자의 이해가 쉽도록 논리적 순서를 따라야 한다.

2.1.2.1 오버로드

오버로드 사용 시 같은 오버로드는 함께 둔다.

3. 포매팅

용어 노트: block-like construct (블럭과 같은 구조, 괄호로 나타내어지는 구조를 의미)는 클래스, 함수, 생성자의 몸체를 나타낸다. 4.8.3.1에 나와있는 배열 초기화블럭은 블럭과 같은 구조로 간주될 수 있다.

3.1 괄호

3.1.1 괄호는 선택사항에서도 쓰인다.

괄호는 if, else, for, do, while 구문에 쓰이는데 몸체가 없거나 한 줄의 구문에도 괄호가 쓰인다.

3.1.2 비어있지 않은 블럭: K & R 스타일

괄호는 비어있지 않은 블럭과 block-like construct에서 Kernighan과 Ritchie 스타일(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 클래스에는 예외가 있다. 3.8.1

3.1.4 빈 블럭들: 간결하게

빈 블럭이나 block-like construct 에서는 K & R 스타일을 따를 수 있다. 대안으로 { } 괄호 안에 문자가 없거나 줄바꿈이라면 열자마자 끝날 수 있다. 하지만 멀티 블럭 구문에서는 할 수 없다.

예:

  // 허용
  void doNothing() {}

  // 마찬가지로 허용
  void doNothingElse() {
  }
 // 허용되지 않음: 멀티 블럭 구문에서는 간결한 빈 블럭을 사용할 수 없음
  try {
    doSomething();
  } catch (Exception e) {}

3.2 블럭 들여쓰기: +2 스페이스

새로운 블럭이나 block-like construct가 열리면 들여쓰기는 스페이스 2번의 공간을 차지한다. 블럭이 끝나면, 들여쓰기는 이전의 들여쓰기 단계로 돌아간다. 들여쓰기 단계는 코드와 주석에 모두 적용된다.

3.3 줄 당 하나의 서술

하나의 구문은 줄바꿈이 뒤따른다.

3.4 열 제한: 100

자바 코드는 100개의 문자의 제한이 있다. "문자"란 어떠한 유니코드 포인트를 말한다. 밑에 서술된 예외들을 제외하고 이 숫자를 넘어간다면 줄 바꿈 (4.5 참조)을 해야한다.

하나의 유니코드 포인트는 화면상 길든 짧든 하나의 문자를 의미한다. 예를들어, full-width 문자(예를들어, 중국어, 일본어, 한국어)를 쓴다면 규칙보다 일찍 개행하는게 좋다.

예외:

  1. 개행이 불가능한 경우 (예를들어, Javadoc의 긴 URL 혹은 긴 JSNI 메서드 레페런스)
  2. package 나 import 구문들 (3.2 패키지 구문, 3.3 임포트 구문 참조)
  3. 쉘에 복사 붙여넣기 되는 커멘드 라인에 대한 주석

3.5 줄 바꿈

매 상황별 어떻게 줄 바꿈하는지에 대한 정확한 방법은 없다. 주로 같은 조각의 코드에서 줄 바꿈을 한다.

3.5.1 언제 바꾸는가

줄 바꿈의 원칙은 높은 문법 레벨에서 바꾸는 것

  1. non-assignment 연산자에서 줄 바꿈이 일어날 경우 바꿈은 기호 이전에 위치한다. 이것은 "operator-like" 기호에 적용된다.
    • dot (.)
    • 2개의 콜론 (::)
    • 타입 바운딩의 앰퍼센드 기호 (<T extends Foo & Bar>)
    • catch 블럭의 파이프 ( catch (FooException | BarException e) ).
  2. 줄 바꿈이 assignment 연산자에서 일어나면 기호 다음에 위치하지만 바뀌어도 상관없다.
    • 이것은 향상된 for문의 "assignment-operator-like" 콜론에도 적용된다.
  3. 함수나 생성자의 이름에 여는 괄호가 있을 때.
  4. 콤마 앞에 오는 토큰에 연결되어 있을 때.
  5. 줄은 람다식의 인접한 화살표에서는 바뀌지 않는다. 하지만 람다의 몸체가 한 줄로 되어 있다면 바꿔도 된다. 예를들면:
MyLambda<String, Long, Object> lambda =
    (String label, Long value, Object obj) -> {
        ...
    };

Predicate<String> predicate = str ->
    longExpressionInvolving(str);

참고: 줄 바꿈의 목적은 깨끗한 코드를 만듦에 있지, 줄 수를 줄이는데 있지 않다.

3.5.2 들여쓰기 지속은 최소 +4 스페이스

줄 바꿈할때, 각 줄은 원래 줄보다 +4 스페이스만큼 들여쓰기를 한다.

여러 줄 바꿈 줄이 있을 때, 들여쓰기는 +4 이상으로 변동 가능하다. 일반적으로, 두 개의 연속된 줄은 같은 들여쓰기 레벨을 갖고 구문적으로 병렬인 요소일때만 적용된다.

3.6 공백

3.6.1 수직 공백

하나의 공백 줄은 항상 이럴 때 나타난다:

  1. 연속적인 멤버나 클래스의 초기화: 필드, 생성자, 메소드, 중첩 클래스, 정적 초기화 그리고 인스턴스 초기화
    • 예외: 두 개의 연속된 필드의 공백은 선택적이다. 그러한 공백은 필드의 논리적 그룹을 형성하는데 필요하다.
    • 예외: enum 상수의 공백 줄은 4.8.1 절에서 다룬다.
  2. 문서의 다른 부분에서도 필요하다. ( 섹션3 이나 3.3)

하나의 공백 줄은 어디에서나 등장할 수 있고, 가독성을 높인다. 예를들어, 코드를 논리적 부분으로 나눌때 쓰인다. 첫 번째 멤버 나 초기화 앞에있는 빈 줄 또는 클래스의 마지막 멤버 나 초기화 뒤에 오는 공백 줄은 권장되거나 권장되지 않는다.

다수의 공백 줄은 허용은 되나 요구되지는 않는다. (지양)

3.6.1 수평 공백

리터럴, 주석 및 Javadoc을 제외하고 언어 또는 기타 스타일 규칙이 필요한 곳을 넘어서는 경우 단일 ASCII 공간이 다음 장소에만 나타난다.

  1. 예약어를 나누는 경우, if, for, catch 같은 예약어 이후 나오는 여는 괄호에서 사용
  2. 예약어를 나누는 경우, else 나 catch 같은 예약어 이후 나오는 닫는 중괄호에서 사용
  3. 중괄호는 여는 모든 경우에 사용, 예외 두가지
    • @SomeAnnotation({a, b})
    • String[][] x = {{"foo"}};
  4. 임의의 이항 또는 삼항 연산자 양쪽에 사용. 이것은 "operator-like" 기호에도 적용된다.
    • <T extends Foo & Bar> 인접한 타입 바운딩의 앰퍼센드 연산자에서
    • catch (FooException | BarException e) 예외처리의 파이프 에서
    • for ("foreach") statement 향상된 for 문에서
    • (String str) -> str.length() 람다의 화살표에서
    • 하지만 두개의 :: 콜론에서는 띄우면 안된다. Object::toString
    • 그리고 dot(.) 연산자에서도 띄우면 안된다. object.toString()
  5. , : ; 혹은 캐스팅 할때 닫는 괄호 뒤에서 사용
  6. // 더블 슬래시에서 양쪽에 사용. 여러 수의 공백이 허용되지만 필수사항은 아니다.
  7. 변수의 선언문 사이에서 List list
  8. 배열 선언문 사이에서 공백 선택
    • new int[] {5, 6}andnew int[] { 5, 6 } 둘 다 가능
  9. 타입 애너테이션이나 대괄호에서 사용

이 규칙은 라인의 시작이나 끝에서 추가 공간을 요구하거나 금지하는 것은 아니다. 그것은 내부 공간만을 다룬다.

3.7 특별한 구조

3.7.1 Enum 클래스

enum 상수의 각 컴마 다음에 개행은 선택적이다. 추가의 개행(주로 한개)도 허용된다.

private enum Answer {
  YES {
    @Override public String toString() {
      return "yes";
    }
  },

  NO,
  MAYBE
}

메소드와 documentaation이 없는 enum 클래스는 배열 초기화와 같은 포맷으로 작성될 수 있다. (4.8.3.1 배열 초기화 참조)

private enum Suit { CLUBS, HEARTS, SPADES, DIAMONDS }

enum 클래스들은 클래스 이므로 클래스 포맷팅 형식이 적용된다.

3.7.2 변수 선언

3.7.2.1 정의당 하나의 변수

매 변수 초기화는 (필드 혹은 지역) 하나의 변수만 초기화한다: int a, b; 는 쓰이지 않는다.

예외: for 루프의 헤더에는 여러 변수선언이 쓰일 수 있다.

3.7.2.2 필요하면 정의

지역변수는 블럭이나 block-like construct가 시작될 때 습관적으로 쓰일 필요는 없다. 대신에, 지역변수는 범위를 좁히기 위해 그것들이 처음 사용될 때 (이유가 있어야 함) 가까운 위치에 선언한다. 지역변수는 전형적으로 초기화를 시키거나 선언과 동시에 초기화를 시킨다.

3.7.3 배열

3.7.3.1 배열 초기화는 "block-like"

배열 초기화는 "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}

3.7.4 숫자 리터럴

long의 값을 가지는 정수 리터럴은 대문자 L의 접미사를 가진다. (소문자가 아닌 이유는 숫자 1과 헷갈리기 때문). 예를들어 3000000000L을 3000000000l 대신에 쓴다.

4. 네이밍

4.1 모든 식별자에 대한 공통 내용

구글 스타일에서는 특별한 접미사나 접두사는 쓰이지 않는다. 예를들어 name_, mName, s_name, kName은 구글 스타일이 아니다.

4.2 식별자 타입에 대한 룰

4.2.1 패키지 이름

패키지명은 전부 소문자로 단순히 서로 뭍여서 연속된 단어로 이루어져 있다. (언더스코어 없음) 예를들어 com.example.deepspace같은 형식이다. com.example.deepSpace혹은com.example.deep_space 는 잘못되었다.

4.2.2 클래스 이름

클래스 이름은 UpperCamelCase 이다.

클래스 이름은 전형적으로 명사나 명사 구이다. 예를들어, Character 혹은 ImmutableList 처럼 말이다. 인터페이스의 이름은 명사나 명사구가 될 수 있다. 예를들어 List. 그러나 가끔은 형용사나 형용사구가 대신 쓰이기도 한다 (예를들어 Readable)

4.2.3 함수 이름

함수 이름은 lowerCamelCase 이다.

함수 이름은 전형적으로 동사 혹은 동사 구이다. 예를들어, sendMessage 나 stop이다. 언더스코어는 JUnit 테스트에서 논리적 컴포넌트를 분리시키기 위해 각각을 lowerCamelCase로 변경시켜 나올수 있다. 하나의 전형적인 패턴은_ 이다. 예를들어 pop_emptyStack. 테스트 메소드를 작성하는 하나의 정확한 방법은 없다.

4.2.4 상수 이름

상수는 CONSTANT_CASE를 사용한다: 모두 대문자이고 각 단어는 하나의 언더스코어로 구분하는 형식.

4.2.5 상수가 아닌 필드의 이름

상수가 아닌 필드 이름은 (static 같은) lowerCamelCase로 작성한다.

4.2.6 파라미터 이름

파라미터 이름은 lowerCamelCase 이다.

4.2.7 지역변수 이름

지역변수는 lowerCamelCase 이다.

4.2.8 타입 변수 이름

각 타입들은 두 스타일중 하나를 따른다.

  • 하나의 대문자, 혹은 뒤에 하나의 숫자가 따라올 수 있다. (예를들어, E, T, X, T2)
  • 클래스를 위해서 사용되는 (5.2.2절 클래스 이름 참조) 이름의 형식에 T 대문자가 따라오는 형식 (예를들어, RequestT, FooBarT)

4.3 Camel 케이스

두문자어 또는 "IPv6"또는 "iOS"와 같은 비정상적인 구성이있는 경우가 있다. 예측 가능성을 높이기 위해 구글 스타일은 다음과 같이 지정한다.

산문 형태의 이름으로 시작:

  1. 구를 일반적인 ASCII로 변환하고 "'"를 없앤다. 예를들어 Müller's algorithm은 Muellers algorithm로 변환한다.
  2. 결과를 단어로 나누고 남은 공백과 구두점으로 나눈다. (일반적으로 하이픈)
    • 추천: 어떤 단어가 이미 전통적인 캐멀 케이스방식이 쓰인다면 이것을 구성하는 부분들로 나눈다. (예를들어 "AdWords"를 "adwords"로). "IOS"는 캐멀케이스가 아니다. 이 부분은 어떠한 약속에도 위배되므로 적용되지 않는다.
  3. 이제 모두 lowercase로 바꾸고 (심지어 두음문자도) 그리고 첫 번째 글자를 대문자로 바꾸는데 그 바꾸는 문자들은:
    • 각 단어
    • 각 단어지만 첫 번째를 제외, 첫 번째는 lowercase
  4. 이제 하나로 조합한다.
산문 형태 맞음 틀림
"XML HTTP request" XmlHttpRequest XMLHTTPRequest
"new customer ID" newCustomerId newCustomerID
"inner stopwatch" innerStopwatch innerStopWatch
"supports IPv6 on iOS?" supportsIpv6OnIos supportsIPv6OnIOS
"YouTube importer" YouTubeImporter YoutubeImporter*
  • 는 권장되지 않음

5. 프로그래밍

5.1 @Override: 항상 사용

@Override 시 어노테이션을 붙인다.

예외: 부모 함수가 @Deprecated가 되면 @Override를 생략할 수 있다.

5.2 예외 처리: 생략 하지 말 것

아래 명시되 있는 것 외에 예외를 항상 처리해야만 한다.(전형적인 반응은 로그를 남기는 것 혹은 불가능하다고 간주되면 AssertionError로 다시 던져준다)

예외 처리를 하지 않는 것이 정당하다면 주석을 남기는 것으로 정당화한다.

try {
  int i = Integer.parseInt(response);
  return handleNumericResponse(i);
} catch (NumberFormatException ok) {
  // 숫자가 아니다; 괜찮으니 그냥 넘어간다
}
return handleTextResponse(response);

예외: 테스트에서 예외를 잡는 부분은 expected, 혹은 expected로 시작하는 이름을 지으면서 무시할 수 있다. 다음 예제는 테스트에서 예외가 나오는게 확실한 상황에서 사용되는 대중적인 형식으로 주석이 필요가 없다.

try {
  emptyStack.pop();
  fail();
} catch (NoSuchElementException expected) {
}

5.3 정적 멤버: 클래스를 사용할 수 있음

static 클래스 멤버 참조는 그에 대한 자격이 있어야 하는데 그것은 클래스 타입이 아니라 이름이다.

Foo aFoo = ...;
Foo.aStaticMethod(); // 좋음
aFoo.aStaticMethod(); // 나쁨
somethingThatYieldsAFoo().aStaticMethod(); // 아주 나쁨

Clone this wiki locally