본문 바로가기
Language/Java

[Java] Google Java Style Guide 번역

by 1000zoo 2023. 10. 17.

원본 링크


1. Introduction

이 문서는 Google의 Java 프로그래밍 언어에 대한 소스 코드 표준의 정의로 작용합니다. Java 소스 파일은 여기에 명시된 규칙을 준수하는 경우에만 Google Style 로 간주됩니다.

다른 프로그래밍 스타일 가이드처럼, 다루는 문제는 형식의 미적 측면 뿐 아니라 다른 유형의 규칙이나 코딩 표준도 포함합니다. 그러나 이 문서는 우리가 일관성 있게 따르는 명확하고 엄격한 규칙에 주로 중점을 둡니다. 그리고 명확하게 집행할 수 없는 조언은 피합니다.

1.1 용어 설명

이 문서에서는 아래와 같이 용어가 정의됩니다.

  • class 라는 용어는 "보통의" 클래스, "enum" 클래스, 인터페이스나 어노테이션 타입을 포괄적으로 의미합니다.
  • 클래스의 "member"라는 용어는 중첩 클래스, 필드, 메서드, 생성자를 포괄적으로 의미합니다. 즉, 클래스의 최상위 내용물 중 초기화 블록과 주석을 제외한 모든 것입니다.
  • comment 라는 용어는 항상 구현 주석을 의미합니다. "문서화 주석"이라는 구문은 사용하지 않고, 대신 일반적인 용어인 "Javadoc"을 사용합니다.
  • 문서 전반에 걸쳐 다른 용어설명이 나타날 것 입니다.

1.2 가이드 노트

이 문서의 예제 코드는 규범이 아닙니다. 즉, 예제는 Google Style을 따르고 있지만, 코드를 표현하는 유일한 세련된 방법을 보여주는 것은 아닙니다. 예제에서 선택한 선택적 형식은 규칙으로 강제되지 않습니다.

2. Source file basics

2.1 파일 이름

  • 소스 파일의 이름은 그 안에 포함된 최상위 클래스의 대소문자를 구분하는 이름과 .java 확장자로 구성됩니다. 즉, 정확히 하나의 최상위 클래스만 있어야 합니다.

2.2 파일 인코딩

  • 소스파일은 UTF-8로 인코딩 됩니다.

2.3 특수문자

2.3.1 공백문자

라인 종료 문자를 제외하고 ASCII 수평 공백문자(0x20)만이 소스파일 내에 존재할 수 있습니다.

  • 문자열과 문자 리터럴 내의 모든 다른 공백 문자는 [[이스케이프 시퀀스]] 를 이용합니다.
  • 탭 문자는 들여쓰기에 사용되지 않습니다.

2.3.2 특수 이스케이프 시퀀스

특별한 이스케이프 시퀀스(\b, \t, \n, \f, \r, ", ' 및 \)가 있는 문자에 대해서는 해당 8진수(예: \012)나 유니코드(예: \u000a) 이스케이프보다 그 시퀀스가 사용됩니다.

2.3.3 비-ASCII 문자

나머지 비-ASCII 문자에 대해서는 실제 유니코드 문자(예: ∞)나 동등한 유니코드 이스케이프(예: \u221e)가 사용됩니다. 선택은 코드를 읽고 이해하기 쉽게 만드는 것에만 의존합니다. 그러나 문자열 리터럴과 주석 외부에서 유니코드 이스케이프를 사용하는 것은 강력히 지양됩니다.

ex) 2.3.3

예시 설명
String unitAbbrev = "μs"; 최고: 주석 없이도 완벽히 명확합니다.
String unitAbbrev = "\u03bcs"; // "μs" 허용됨, 그러나 이렇게 할 필요는 없습니다.
String unitAbbrev = "\u03bcs"; // 그리스 문자 뮤, "s" 허용됨, 그러나 어색하고 실수하기 쉽습니다.
String unitAbbrev = "\u03bcs"; 나쁨: 읽는 사람은 이게 무엇인지 알 수 없습니다.
return '\ufeff' + content; // 바이트 순서 표시 좋음: 출력 불가능한 문자에 대해서는 이스케이프를 사용하고 필요한 경우 주석을 답니다.

Tip) 유니코드 이스케이프 경우, 실제 유니코드 문자가 사용될 때에도 설명 코멘트는 매우 유용할 수 있습니다.

Tip) 일부 프로그램이 비-ASCII 문자를 제대로 처리하지 못할까 봐 코드를 덜 읽기 쉽게 만들지 마십시오. 그럴 경우 그 프로그램들이 문제가 있고, 수정되어야 합니다.

3. Source File Structure

소스 파일은 다음 순서로 구성됩니다.

  1. 라이선스 또는 저작권 정보
  2. 패키지 선언
  3. 임포트 문
  4. 정확히 하나의 최상위 클래스

각 세션이 존재할 경우, 정확히 하나의 빈 줄로 각 섹션을 구분합니다.

3.1 라이선스 또는 저작권 정보

파일에 라이선스 또는 저작권 정보가 포함되어야 한다면, 맨 최 상단에 위치합니다.

3.2 package 선언

패키지 선언은 줄 바꿈이 없습니다. 열 제한 (Section 4.4 항목)은 여기에 적용되지 않습니다.

3.3 import 문

3.3.1 [[와일드 카드 import]] 금지

와일드카드 import는 어떤 경우에도 사용되지 않습니다.

ex) 3.3.1

import java.util.*;
import static java.util.Arrays.*;

3.3.2 줄 바꿈 없음

import 문은 줄 바꿈이 없습니다. 열 제한 (Section 4.4 항목)은 여기에 적용되지 않습니다.

3.3.3 순서와 간격

import 문은 다음과 같이 정렬됩니다.

  1. 모든 static import는 하나의 블록에서
  2. 모든 non-static import는 하나의 블록에서

static, non-static import가 모두 있는 경우, 하나의 빈 줄로 두 블록을 구분합니다. import 문 사이에는 다른 빈 줄이 없습니다.

각 블록 내에서는 import 된 이름이 ASCII 순서로 나타납니다.

  • import 문 전체를 ASCII 로 정렬한다는 의미가 아니라, 패키지나 클래스의 이름을 ASCII 순서로 정렬한다.

ex) 3.3.3

import animal.Horse;
import animal.Horse.Zebra;
import java.awt.Button;
import java.util.List;

3.3.4 클래스에 대한 static import 금지

정적 중첩 클래스 (Inner class)에 대해서 static import를 사용하지 않습니다.
일반 import를 사용합니다.

3.4 클래스 선언

3.4.1 정확히 하나의 최상위 클래스 선언

각 최상위 클래스는 자신만의 소스 파일에 위치합니다.

ex) 3.4.1

// Animal.java 파일 내부
class Animal {
    //...
}

class Human {
    // 금지
}

3.4.2 클래스 내용의 순서

클래스의 멤버와 생성자의 순서는 가독성에 큰 영향을 미칩니다. 그러나 이를 어떻게 할지에 대한 정확한 방법은 없습니다. 모든 클래스들은 각자 다른 순서를 가질 수 있습니다. (+ 각자 다른 정렬 기준을 가질 수 있습니다.)

중요한 것은 각 클래스가 어떤 논리적인 순서를 사용하고, 그 순서를 쉽게 설명할 수 있어야 한다는 것입니다. 예를들어, 습관적으로 새로운 메소드가 단순히 클래스의 끝에 추가되지 않아야 합니다. 그렇게 되면 추가된 순서이지 논리적인 순서가 아닙니다.

3.4.2.1 오버로드: 분리금지

동일한 이름을 공유하는 클래스의 메소드는 서로 떨어져 있으면 안됩니다. 이것은 항상 같은 이름을 갖게되는 여러 생성자에도 동일하게 적용됩니다. 이 규칙은 'static'이나 'private'과 같은 Modifier가 메소드 사이에 다를 경우에도 적용됩니다.

4. Formating

4.1 Braces (중괄호)

4.1.1 선택적 Braces의 사용

'if', 'else', 'for' 등의 문법에서 중괄호는 반드시 사용되어야 합니다. 그 몸체가 비어있는 경우에도 사용되어야 합니다.

4.1.2 비어있지 않은 블록: [[K & R style]]

  • 비어있지 않은 블록과 유사한 구조에 대해 K & R style 을 따릅니다.
    • 여는 괄호 앞에 줄바꿈이 없습니다. (특별케이스 제외)
    • 여는 괄호 뒤에 줄바꿈이 있습니다.
    • 닫는 괄호 앞에 줄바꿈이 있습니다.
    • 닫는 괄호 뒤에 줄바꿈이 있습니다.
      • 단 그 중괄호가 문장을 종료하거나 메서드, 생성자, 명명된 클래스의 몸체를 종료하는 경우에만 해당됩니다.
      • 예를들어 'else'나 쉼표가 뒤따르는 경우에는 줄바꿈이 없습니다.
  • 예외
    이 규칙이 세미콜론으로 끝나는 단일 문장을 허용하는 경우에, 여러 문장의 블록이 나타날 수 있으며, 이 블록의 여는 중괄호는 줄바꿈으로 시작됩니다. 이러한 블록은 일반적으로 지역 변수의 범위를 제한하기 위해 도입됩니다. 예를들어 'switch'문 내에서 그렇게 됩니다.

4.1.3 빈 블록: 간결하게 표현 가능

빈 블록이나 블록과 유사한 구조는 K & R 스타일로 표현할 수 있습니다. 대안적으로는, 여는 중괄호와 닫는 중괄호 사이에 문자나 줄바꿈 없이 바로 닫을 수 도 있습니다. 단, 이것이 여러 블록을 포함하는 다중 블록 문장의 일부인 경우에는 그렇게 할 수 없습니다.

ex) 4.1.3

//허용되는 경우
void doNothing() {}
void doNothingElse() {
}

//허용되지 않는 경우
try {
    doSomething();
} catch (Exception e) {}

4.2 블록 들여쓰기: +2 스페이스

새로운 블록이나 블록과 유사한 구조가 열릴 때 마다 들여쓰기가 두 칸 증가합니다. 블록이 끝날 때는 들여쓰기가 이전 수준으로 돌아갑니다. 들여쓰기 수준은 블록 전체의 코드와 주석에 모두 적용됩니다.

4.3 한 줄에 하나의 문장

각 문장 다음에는 줄바꿈을 해야합니다.

4.4 열 제한: 100

Java 코드에는 100자의 열 제한이 있습니다. "문자"라는 것은 어떤 유니코드 코드 포인트든지 의미합니다.
이 제한을 넘어가는 것은 Section 4.5를 참고합니다.

4.5 Line-wrapping

용어 설명

단일 라인에 올 수 있는 코드가 여러 라인으로 나누어 질 때, 이 행위를 "Line-wrapping"이라고 합니다.

라인을 어떻게 래핑할 것인지에는 정답은 없습니다. 대부분의 경우, 동일한 코드 조각을 여러가지 방법으로 래핑할 수 있습니다.

참고

라인 래핑의 일반적인 이유는 열 한도를 넘지 않기 위함이지만, 실제로 열 한도 내에 들어갈 수 있는 코드도 작성자의 재량에 따라 래핑될 수 있습니다.

4.5.1 어디서 wrapping을 할 것인가

라인 래핑의 주된 규칙은 더 높은 구문 수준에서 래핑하는 것을 선호한다는 것입니다.

  1. 비할당 연산자에서 래핑할 때, 래핑은 해당 기호 앞에서 일어납니다.
    • 이것은 다음과 같은 "연산자와 유사한"기호에도 적용됩니다.
      • 점 구분자 (".")
      • 메서드 참조의 두 콜론 ("::")
      • 타입 바운드에서의 앰퍼샌드 (<T extends Foo & Bar>)
      • catch 블록에서의 파이프 (catch (Exception1 | BarException2 e))
  2. 할당 연산자에서 라인이 래핑될 때, 일반적으로 래핑은 해당 기호 뒤에서 일어납니다. 하지만 두 가지 방식 모두 허용됩니다.
    • 이것은 'foreach' 문과 같은 콜론에도 똑같이 적용됩니다.
  3. 메서드나 생성자 이름은 뒤이어 오는 열린 괄호 "(" 에 붙어있습니다.
  4. 쉼표는 앞선 토큰에 붙어있습니다.
  5. 람다의 화살표 뒤에서는 라인이 "절대" 래핑되지 않습니다. 단, 람다의 본문이 중괄호 없는 하나의 표현식으로 이로어 져 있을 경우, 화살표 바로 뒤에서 래핑될 수 있습니다.

ex) 4.5.1

MyLambda<String, Long, Object> lambda =
    (String label, Long value, Object obj) -> {
        ...
    };
// 허용되는 경우
Predicate<String> predicate = str ->
    longExpressionInvolving(str);

4.5.2 연속 라인은 최소 +4 스페이스로 들여쓰기

라인 래핑을 할 때, 첫 번째 라인 다음의 각 연속 라인은 원래 라인에서 최소한 +4 공백으로 들여쓰여집니다.

여러 개의 연속 라인이 있을 때, 들여쓰기는 +4 이상으로 원하는 대로 조절될 수 있습니다. 일반적으로, 두 개의 연속 라인은 구문적으로 병렬적인 요소로 시작할 때만 동일한 들여쓰기 수준을 사용합니다.

섹션 4.6.3에서는 이전 라인의 특정 토큰과 정렬하기 위해 공백의 가변적인 수를 사용하는 것이 권장되지 않는 사항에 대해 다룹니다.

4.6 공백

4.6.1 수직 공백 (줄바꿈)

단일 빈 줄은 항상 다음과 같은 경우에 나타납니다.

  1. 클래스의 연속된 멤버나 생성자 사이 (필드, 생성자, 메서드, 내부 클래스, static 생성자, 그리고 인스턴스 생성자)
    • 예외: 두 연속된 필드 사이, 그 사이에 다른 코드가 없을 경우, 빈 줄은 선택적입니다.
    • 예외: enum 상수 사이의 빈 줄은 Section 4.8.1에서 다룹니다.
  2. 이 문서의 다른 섹션에 의해 필요한 경우, (Section3) 단일 빈 줄은 코드를 논리적 하위 섹션으로 구성하기 위한 문장 사이 등 가독성을 향상시키는 어디에서나 나타날 수도 있습니다. 클래스의 첫 번째 멤버나, 생성자 앞, 또는 마지막 멤버나 생성자 뒤에 빈 줄은 권장되지도, 금지되지도 않습니다.

4.6.2 수평 공백 (띄어쓰기)

언어나 다른 스타일 규칙에서 필요한 경우를 제외하고, 리터럴, 주석, 그리고 Javadoc을 제외하고 단일 ASCII 공백은 다음과 같은 경우에만 나타납니다:

  1. 예약어와 그 뒤를 따르는 열린 괄호 "(" 사이
  2. 예약어와 그 앞에 오는 닫는 중괄호 "}" 사이
  3. 열린 중괄호 ({) 앞
    • 어노테이션의 경우, @SomeAnnotation({a, b}) => 공백 없음
    • 배열의 경우, String[][] x = {{"foo"}} => 공백 필요 없음
  4. 이진 또는 상항 연산자의 양쪽, 이것은 다음과 같은 "연산자와 유사한" 기호에도 적용됩니다.
    • 연속 타입 바운드에서의 앰퍼샌드: <T extends Foo & Bar>
    • 여러 예외를 처리하는 catch 블록에서의 파이프: catch (FooException | BarException e)
    • "foreach" 문에서의 콜론
    • 람다 표현식에서의 화살표
    • 다음 사항에서는 적용되지 않습니다.
      • 메서드 참조의 두 콜론 ("::") => Object::toString처럼 작성됩니다.
      • 점 구분자 (".") => object.toString() 과 같이 작성됩니다.
  5. 캐스트의 닫는 괄호 ")" 뒤에 있는 ,:; (콤마, 콜론, 세미콜론) 뒤에
  6. 주석을 시작하는 두개의 슬래시와 그 뒤의 내용 사이, 여러 공백이 허용됩니다.
  7. 선언에서의 타입과 변수 사이: List<String> list
  8. 배열 초기화자의 두 괄호 안쪽은 선택적입니다.
    1. new int[] {5,6}, new int[] {5, 6} 모두 허용됩니다.
  9. 타입 어노테이션과 [], ... 사이에

이 규칙들은 한 줄의 시작이나 끝에서 추가 공백을 필요로 하거나 금지하는 것으로 해석되지 않습니다. 이는 오직 내부 공백에만 관련이 있습니다.

4.6.3 수평 정렬 (절대적으로 요구되지는 않음)

용어설명

수평 정렬은 이전 줄의 특정 토큰 바로 아래에 특정 토큰이 나타나도록 코드에 가변적인 수의 추가 공백을 추가하는 관행입니다. 허용되기는 하나, 꼭 사용되어야 하는 것은 아닙니다. 심지어 이미 이런 스타일로 작성된 코드에서 이를 유지할 필요는 없습니다.

예시

// 아래의 경우 모두 허용
private int x;
private Color color1;

private int   y;
private Color color2;

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 }

4.9 변수 선언

4.9.1 변수 선언당 하나의 변수

모든 변수 선언은 오직 하나의 변수만을 선언합니다. int a, b; 와 같은 선언은 허용되지 않습니다.

  • 예외: for 루프의 헤더에서는 다중 변수 선언이 허용됩니다.

4.9.2 필요할 때 선언

로컬 변수는 그것이 포함된 블록 또는 블록과 유사한 구조의 시작부분에서 일관되게 선언되지 않습니다. 대신 로컬 변수는 처음 사용되는 지점에 가깝게 (합리적인 범위 내에서) 선언됩니다. 로컬 변수 선언은 일반적으로 초기자를 가지거나, 선언 직후에 초기화 됩니다.

4.9.3 배열

4.9.3.1 배열 초기화자, 블록과 유사하게 가능

new int[] {
    0, 1, 2, 3
};
new int[] {
    0, 1,
    2, 3
};
new int[] {
    0,
    1,
    2,
    3
};
new int[] 
    {0, 1, 2, 3};

위 경우 모두 허용

4.9.3.2 C 스타일 배열 선언 금지

String args[] 금지

4.9.4 스위치 문

용어참고

스위치 블록의 중괄호 안에는 하나 이상의 문장 그룹이 있습니다. 각 문장 그룹은 하나 이상의 스위치 레이블(case FOO: 또는 default:)로 구성되고, 그 뒤에 하나 이상의 문장이 따릅니다(마지막 문장 그룹의 경우, 문장이 없을 수도 있습니다).

4.9.4.1 들여쓰기

다른 블록과 마찬가지로, 스위치 블록의 내용은 +2 들여쓰기됩니다.

스위치 레이블 뒤에는 줄바꿈이 있고, 들여쓰기 수준이 +2 증가합니다. 마치 새로운 블록이 열린 것처럼 처리합니다. 다음 스위치 레이블에서는 이전의 들여쓰기 수준으로 돌아갑니다.

4.9.4.2 Fall-through: 주석처리

스위치 블록 내에서 각 문장 그룹은 갑작스럽게 종료되거나(break, continue, return 또는 예외 발생), 실행이 다음 문장 그룹으로 계속되거나 할 수 있음을 나타내는 주석이 달립니다. Fall-through를 나타내는 아무 주석이나 충분합니다(일반적으로 // fall through). 이 특별한 주석은 스위치 블록의 마지막 문장 그룹에서는 필요하지 않습니다. 예시:

switch (input) {
  case 1:
  case 2:
    prepareOneOrTwo();
    // fall through
  case 3:
    handleOneTwoOrThree();
    break;
  default:
    handleLargeNumber(input);
}

case 1: 뒤에는 주석이 필요하지 않으며, 문장 그룹의 끝에서만 필요합니다.

4.9.4.3 default 레이블의 존재

각 스위치 문에는 코드가 없더라도 default 문장 그룹이 포함됩니다.

예외: 열거형 타입에 대한 스위치 문은 그 타입의 모든 가능한 값을 명시적으로 처리하는 경우에는 default 문장 그룹을 생략할 수 있습니다. 이렇게 하면 IDE나 다른 정적 분석 도구에서 누락된 경우에 대해 경고를 발생시킬 수 있습니다.

4.9.5 어노테이션

4.9.5.1 타입 사용 어노테이션

타입 사용 어노테이션은 어노테이션이 달린 타입 바로 앞에 나타납니다. 어노테이션이 @Target(ElemenType.TYPE_USE) 메타 어노테이션을 가지고 있을 때, 이것은 타입 사용 어노테이션입니다. 예시:

final @Nullable String name;

public @Nullable Person getPersonByName(String name);

4.9.5.2 클래스 어노테이션

클래스에 적용되는 어노테이션은 문서 블록 바로 다음에 나타나며, 각 어노테이션은 자신만의 줄에 나열됩니다(즉, 줄당 하나의 어노테이션). 이러한 줄바꿈은 줄 나눔(line-wrapping, Section 4.5 참조)을 구성하지 않으므로 들여쓰기 수준은 증가하지 않습니다. 예시:

@Deprecated
@CheckReturnValue 
public final class Frozzler { ... }

4.9.5.3 메서드와 생성자 어노테이션

메서드와 생성자 선언에 대한 어노테이션 규칙은 이전 섹션과 동일합니다. 예시:

@Deprecated 
@Override
public String getNameIfPresent() { ... }
예외

단일한 매개변수가 없는 어노테이션은 대신 서명의 첫 줄과 함께 나타날 수 있습니다. 예를 들어:

@Override public int hashCode() { ... }

4.9.5.4 필드 어노테이션

필드에 적용되는 어노테이션도 문서 블록 바로 다음에 나타나지만, 이 경우에는 여러 어노테이션(매개변수화될 수 있음)이 같은 줄에 나열될 수 있습니다. 예를 들어:

@Partial @Mock DataLoader loader;

4.9.5.5 매개변수와 지역 변수 어노테이션

매개변수나 지역 변수에 대한 어노테이션 포맷팅에 대한 특별한 규칙은 없습니다(물론 어노테이션이 타입 사용 어노테이션인 경우를 제외하고).

4.9.6 주석

이 부분은 구현 주석에 대해 다룹니다. Javadoc 은 Section 7에서 별도로 다룹니다.
임의의 공백 뒤에 구현 주석이 오는 줄 바꿈이 있을 수 있습니다. 이러한 주석은 줄을 공백이 아닌 것으로 만듭니다.

4.9.6.1 Block comment style

블록 주석은 주변 코드와 동일한 수준에서 들여쓰기 됩니다.

/*
 * 이것은
 * 괜찮습니다.
 */

// 이것도
// 괜찮습니다.

/* 이렇게도
 * 할 수 있습니다.*/

여러 줄을 작성할 때는, 가능한 /**/ 를 사용하십쇼

4.9.7 Modifiers

클래스와 멤버의 수식어가 존재할 경우, Java Language Specification 에서 권장하는 순서대로 나타냅니다.

public protected private abstract default static final transient volatile synchronized native strictfp

5. Naming

5.1 모든 식별자에 공통적인 규칙

식별자는 오직 ASCII 문자와 숫자만 사용하며, 아래에 명시된 소수의 경우에는 밑줄_도 허용됩니다. 따라서 유효한 식별자 이름은 정규 표현식 \w+에 의해 매치됩니다.

특별한 접두사나 접미사를 사용하지 않습니다. 예를들어, 다음과 같은 이름은 구글 스타일이 아닙니다.
name_, mName, s_name, kName

5.2 식별자 유형 규칙

5.2.1 Package 이름

패키지의 이름은 오직 소문자와 숫자만 사용됩니다. (언더바 X) 연속되는 단어들은 그냥 붙여서 사용합니다. 예를 들어, com.example.deepspace 이며, camel case나 snake case 는 허용되지 않습니다.

5.2.2 클래스 이름

클래스 이름은 UpperCamelCase 로 작성됩니다.

클래스 이름은 대체로 명사나 명사구입니다. 예를들어, Character 나 ImmutableList 등 입니다. 인터페이스 이름도 명사나 명사구일 수 있습니다. (List) 하지만 때로는 형용사나 형용사구일 수 도 있습니다. (Readable)

어노테이션 타입을 명명할 때 특별한 규칙이나 잘 정립된 관례는 없습니다.

테스트 클래스의 이름은 Test로 끝납니다. 예를 들어, HashIntegrationTest 같은 것이며, 하나의 클래스만을 다룰 경우, 그 클래스의 이름 뒤에 Test를 붙입니다. 예를 들어 HashImplTest 같은 것입니다.

5.2.3 메소드 이름

메소드 이름은 lowerCamelCase로 작성됩니다.

메소드 이름은 대체로 동사나 동사구입니다. 예를 들어, sendMessage나 stop 등 입니다.

JUnit 테스트 메소드 이름에서는 논리적인 구성 요소를 분리하기 위해 밑줄을 사용할 수 있습니다. 각 구성요소는 lowerCamelCase로 작성됩니다. 예를들어, transferMoney_deductsFromSource 같은 것입니다. 테스트 메소드를 명명하는 정답은 없습니다.

5.2.4 상수 이름

상수 이름은 UPPER_SNAKE_CASE를 사용합니다. 모든 글자는 대문자로, 각 단어는 다음 단어와 하나의 언더바로 구분됩니다. 그렇다면 상수는 정확히 어떤 건가요?

상수는 깊게 불변인 내용을 가지고 있고, 그 메소드가 감지할 수 있는 부작용이 없는 static final 필드입니다. 예를 들어 원시 타입, 문자열, 불변 값 클래스, 그리고 null로 설정된 모든 것이 해당됩니다. 인스턴스의 관찰 가능한 상태가 변할 수 있다면, 그것은 상수가 아닙니다. 단순히 객체를 변경하지 않으려는 의도만으로는 충분하지 않습니다. 예를 들어:

// Constants
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 = {};

// 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 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 비상수 필드 이름

비상수 필드 이름(정적이든 아니든)은 lowerCamelCase로 작성됩니다.
이러한 이름은 일반적으로 명사나 명사구입니다. 예를 들어, computedValues 또는 index.

5.2.6 매개변수 이름

매개변수 이름은 lowerCamelCase로 작성됩니다.
공개 메서드에서 한 글자 매개변수 이름은 피해야 합니다.

5.2.7 로컬 변수 이름

로컬 변수 이름은 lowerCamelCase로 작성됩니다.
final과 불변이더라도 로컬 변수는 상수로 간주되지 않으며, 상수처럼 스타일링되어서는 안됩니다.

5.2.8 타입 변수 이름

각 타입 변수는 두 가지 스타일 중 하나로 이름이 지어집니다:
단일 대문자, 필요한 경우 단일 숫자를 뒤에 붙인 것(예: E, T, X, T2) 클래스에 사용되는 형식의 이름 뒤에 대문자 T를 붙인 것(예: RequestT, FooBarT).

5.3 Camel case: 정의

때로는 영어 문구를 Camel Case 로 변환하는데 하나 이상의 합리적인 방법이 있을수 있습니다. 예를들어, "IPv6" 또는 "iOS"와 같은 약어나 특이한 구조가 있을 경우입니다. 예측 가능성을 높이기 위해, Google Styled은 다음과 같은 결정적인 방식을 지정합니다.

이름의 문장 형태로 시작하여:

  1. 문구를 일반 ASCII로 변환하고 그 아포스트로피를 제거합니다. 예를 들어, Müller's algorithmMuellers algorithm이 될 수 있습니다.
  2. 이 결과를 단어로 나눕니다. 공백과 남아있는 구두점 (일반적으로 하이픈)을 기준으로 분리합니다.
    • 권장사항: 만약 어떤 단어가 이미 일반적인 사용에서 관례적인 카멜케이스 모양을 가지고 있다면, 이를 그 구성요소로 분리합니다. (예: AdWords는 ad words가 됩니다.) "iOS"와 같은 단어는 자체적으로 카멜케이스가 아니기 때문에, 이 권장사항은 적용되지 않습니다.
  3. 이제 모든 것을 소문자로 변경한 다음, 다음의 첫 글자만 대문자로 변경합니다.
    • 각 단어, 상위 카멜케이스를 생성하기 위해 또는
    • 첫 번째 단어를 제외한 각 단어, 하위 카멜 케이스를 생성하기 위해
  4. 마지막으로, 모든 단어를 하나의 식별자로 결합합니다.
  5. 원래 단어의 대소문자는 거의 완전히 무시됩니다.

예시

Prose form Correct Incorrect
"XML HTTP request" XmlHttpRequest XMLHTTPRequest
"new customer ID" newCustomerId newCustomerID
"inner stopwatch" innerStopwatch innerStopWatch
"supports IPv6 on iOS?" supportsIpv6OnIos supportsIPv6OnIOS
"YouTube importer" YouTubeImporter YoutubeImporter*

6. Programming Practices

6.1 @Override: 항상 사용

@Override 어노테이션은 해당 메서드가 부모 클래스나 인터페이스의 메서드를 오버라이드할 때 항상 사용됩니다. 예외적으로 부모 메서드에 @Deprecated가 붙어 있을 경우에는 생략할 수 있습니다.

6.2 예외 처리: 무시하지 않음

아래에 설명된 예외를 제외하고, 예외를 잡아서 아무 것도 하지 않는 것은 대체로 잘못된 접근입니다. 일반적으로 예외를 로깅하거나, "불가능하다"고 판단되면 AssertionError로 다시 던집니다. 예외를 잡고 아무 것도 하지 않을 경우에는 그 이유를 주석으로 명시해야 합니다.

예시

try {
  int i = Integer.parseInt(response);
  return handleNumericResponse(i);
} catch (NumberFormatException ok) {
  // it's not numeric; that's fine, just continue
}
return handleTextResponse(response);

예외

예외가 발생하는 것이 예상되는 테스트 케이스에서는, 예외 이름이 'expected'로 시작한다면 주석없이 예외를 무시할 수 있습니다.

예를 들어, 테스트 중에 예외가 발생할 것으로 예상되는 코드 부분에서 실제로 예외가 발생하면, 그 예외를 잡아서 테스트를 계속 진행할 수 있습니다. 이 경우 예외의 이름이 'expected'로 시작하기 때문에, 왜 예외를 무시하는지에 대한 추가적인 주석은 필요하지 않습니다.

이는 코드가 예상한 대로 예외를 던지는지 확인하기 위한 일반적인 패턴입니다. 예외가 발생하지 않으면 테스트는 실패(fail())하게 됩니다.

try {
  emptyStack.pop();
  fail(); // 예외가 발생하지 않으면 테스트 실패
} catch (NoSuchElementException expected) {

}
// 예상한 예외가 발생했으므로 아무 것도 하지 않고 테스트를 계속 진행

6.3 정적 멤버: 클래스 이름으로 지정

정적 클래스 멤버에 접근할 때는 해당 클래스의 이름을 사용하여 접근해야 하며, 해당 클래스의 타입을 가진 참조나 표현식을 사용해서는 안 됩니다.

예시

Foo aFoo = ...;
Foo.aStaticMethod(); // good
aFoo.aStaticMethod(); // bad
somethingThatYieldsAFoo().aStaticMethod(); // very bad

6.4 파이널라이저: 사용하지 않음

Object.finalize를 오버라이드하는 것은 매우 드문 경우입니다. 절대로 사용하지 말아야 하며, 만약 사용해야 한다면 Effective Java의 아이템 8을 철저히 읽고 이해한 후에도 사용하지 않는 것이 좋습니다.

이러한 규칙들은 코드의 일관성을 유지하고, 가독성을 높이며, 버그를 줄이는 데 도움이 됩니다.

7. Javadoc

7.1 Formatting

7.1.1 General form

Javadoc 블록의 기본 형태는 주석 마커/** ... */와 그 사이의 텍스트로 구성됩니다. 이 텍스트는 여러 줄일 수도, 한 줄일 수도 있습니다. 특히 한 줄에 모든 내용이 들어갈 수 있는 경우는 한 줄로 작성이 가능합니다.

7.1.2 Paragraphs

단락 구분은 빈 줄(별표만 있는 줄)을 사용하여 이루어집니다. 첫 번째 단락을 제외하고는 각 단락이 <p> 태그로 시작합니다.

7.1.3 Block tags

Javadoc에서 사용되는 표준 "블록 태그"(@param, @return, @throws, @deprecated)는 항상 설명과 함께 나타나야 합니다. 한 줄에 들어가지 않는 경우에는 줄을 바꿀 때 4개 이상의 공백으로 들여쓰기를 합니다.

7.2 The summary fragment

모든 Javadoc 블록은 간단한 요약 문구로 시작합니다. 이 요약 문구는 매우 중요하며, 클래스나 메소드의 인덱스 등에서만 나타날 수 있습니다.

7.3 Where Javadoc is used

7.3.1 Exception: self-explanatory members

간단하고 명확한 멤버(예: getFoo())에 대해서는 Javadoc이 선택적입니다.

7.3.2 Exception: overrides

상위 타입의 메소드를 오버라이드하는 메소드에는 항상 Javadoc이 있을 필요는 없습니다.

7.3.4 Non-required Javadoc

필수적이지 않은 다른 클래스와 멤버에도 필요에 따라 Javadoc을 작성할 수 있습니다. 이러한 Javadoc은 엄격하게 앞서 언급한 포맷팅 규칙을 따를 필요는 없지만, 권장됩니다.

이렇게 Javadoc을 통해 코드의 목적이나 동작, 사용 방법 등을 명확하게 문서화하여, 다른 개발자나 미래의 자신이 코드를 이해하고 유지보수하기 쉽도록 합니다.

'Language > Java' 카테고리의 다른 글

[Java] Enum 활용하기  (0) 2023.10.24
[Java] Functional Interface  (0) 2023.10.24
[Java] JDK Java version 변경하기 (M1)  (0) 2023.09.25
[Java] 정규식 정리 (Regular Expression)  (0) 2023.09.21
[Java] List<int[]> 를 int[][] 로 변환  (0) 2023.09.06