프로그래밍 언어/Java

[Java] 자바 코드 컨벤션 정리(Google Java Style Guide)

fladi 2023. 10. 18. 03:03
728x90

백준이든 api를 만들든 나는 항상 코드가 잘 돌아가기만 하면 된다고 생각했다. 그래서 몇 중 for문이든 그냥 쓰고, 함수로 빼는 일도 잘 없었다. 하지만 팀원들은 내 코드를 보고 이해하기 어려워서 손도 못대겠다고 했다.. 😥😥😥

 

잘 짠 코드는 남이 알아보기 쉽게 작성한 코드라고 한다. 기능이 잘 돌아가는 것 외에 코드를 어떻게 깔끔하게, 남이 알아보기 쉽게 만들 수 있는지 고민을 해볼 단계가 된 것 같다.

 

이번에 우테코를 지원하였는데, 프리코스의 문제 요구사항 중 코드컨벤션 맞추기가 있었다. 이번에 Google Java Style Guide를 정리하며 자바 코드 컨벤션을 공부하고, 컨벤션에 맞추어 코드를 짜는 연습을 해보려고 한다.

 

https://google.github.io/styleguide/javaguide.html

 

Google Java Style Guide

1 Introduction This document serves as the complete definition of Google's coding standards for source code in the Java™ Programming Language. A Java source file is described as being in Google Style if and only if it adheres to the rules herein. Like ot

google.github.io

  • 이 사이트는 영어 원문이다
  • 영어를 잘 하지 못하기 때문에 영어원문과 해석본을 비교하면서 공부를 해보려고 한다. 해석된 사이트 2가지는 다음과 같음

https://github.com/JunHoPark93/google-java-styleguide

 

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

Google의 Java StyleGuide를 번역한 문서 📝. Contribute to JunHoPark93/google-java-styleguide development by creating an account on GitHub.

github.com

https://newwisdom.tistory.com/m/96

 

[JAVA] Google Java Style Guide 번역

2020년 11월 27일 작성 글 우아한 테크코스 과제는 Clean Code, 즉 코딩 컨벤션을 준수해야 한다. 우테코 측에서 프로그램 요구사항으로 제시한 구글 자바 스타일 문서를 번역기로 돌려 보았더니 허허

newwisdom.tistory.com

 

 

들어가기 전

저는 제가 보기 쉽게 정리하였고, 글을 읽고 제가 생각하여 작성한 예시가 포함되어 있습니다.

틀리는 경우가 있을 수 있으니, 보다 정확한 자료를 원하신다면 위 링크를 참고해주세요!

 

 

목차

 

 

1. 용어

  • class는 일반적인 class, enum, interface 또는 어노테이션 유형(@Interface) 을 의미하는 포괄적인 의미로 사용
  • member: 중첩된 클래스, 필드, 메서드 또는 생성자 의미
  • comment: 주석 (Javadoc)

 

 

2. 소스 파일 기본사항

  • 파일 이름은 최상위 클래스의 대소문자 구분 이름과 .java 확장자로 구성
  • 파일인코딩 = UTF-8
  • 특수문자
    • 공백문자: tab문자는 들여쓰기에 사용되지 않음
    • Non-ASCII문자: 실제 유니 코드 문자 또는 동등한 유니 코드 이스케이프가 사용됨

 

3. 소스 파일 구조

  • 소스파일 순서(하나의 빈 줄이 각 섹션을 구분함)
라이센스 또는 저작권 정보  
Package 구문 열 제한이 없음
Import 구문

static이나 와일드카드 import 사용x
줄바꿈 금지
단일 블록에서 모든 static imports -> 단일 블록의 모든 non-static imports 순서로 씀
정확히 하나의 최상위 Class   

 

클래스 선언

  • 메서드를 오버로드 할 경우 위치 분할을 하지 않는다
  • 이 메서드들 사이에는 다른 코드 없이 순차적으로 나타내야함

 

 

4. Formatting

  • block-like construct는 클래스, 메서드 또는 생성자의 본문을 나타낸다

 

괄호

  • 중괄호는 무조건 필수다
  • K&R(Rernighan 및 Ritchie)스타일을 따른다  = Egyption brakets
    • 여는 중괄호 앞에 줄 바꿈이 없음
    • 여는 중괄호 뒤에 줄 바꿈
    • 닫는 중괄호 앞에 줄 바꿈
    • 닫는 중괄호 뒤의 줄 바꿈
    • 중괄호 뒤에 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();
    }
  }
};
  • 빈 블록의 경우 열린 직후 닫힐 수 있다  void doNothing() {}

 

블록 들여쓰기

  • 블록 들여쓰기의 경우 +2 공백
  • 각 문 뒤에는 줄바꿈이 있음 (while, for 등)

 

열 제한: 100

  • 열 제한 100자 -> 유니 코드 코드포인트 기준
    • 예외: 열 제한을 따를 수 없거나/ package, import문/ 셀에 복붙되는 ㅈ석의 명령 줄

 

줄 바꿈

  • 줄바꿈은 공식이 없음
    • 주요 지침은 더 높은 문법 수준에서 중단
    • 기본목표: 명확한 코드 만들기
    • lamda의 경우 화살표 옆에서 줄이 안끊어짐 (예외 - 단일식)
MyLambda<String, Long, Object> lambda =
    (String label, Long value, Object obj) -> {
        ...
    };

Predicate<String> predicate = str ->
    longExpressionInvolving(str);
  • 연속 줄을 최소 +4 공백 들여쓰기

 

공백

  • 하나의 빈 줄(세로공백)은 이럴 때 나타남
    • 연속적인 멤버 or 클래스의 초기화 (필드, 생성자, 메소드, 중첩클래스, 정적 초기화, 인스턴스 초기화)
    • 예외는 두 개의 연속 된 필드 사이에 다른 코드가 없는 빈 줄은 선택사항이다(필드의 논리적 그룹을 위함)
    • enum상수 사이 빈 줄은 뒤 참고
    • 첫 번째 멤버 or 이니셜라이저 앞이나 클래스 마지막 멤버or이니셜라이저 뒤의 빈 줄 가능은 함
    • 여러 개의 연속 된 빈 줄 가능은 함
int a;
int b;
             //허용
int c;
int d;
  • 띄어쓰기(가로공백)는 다음 위치에만 나타남(리터럴, 주석 및 Javadoc을 제외)
    • 예약어 나누는 경우 해당 줄에서 뒤에오는 여는 괄호
    • 예약어 나누는 경우 else 또는 catch 이후 나오는 닫는 중괄호에서 분리
    • 여는 중괄호 앞
      • 예외1: @SomeAnnotation({a,b}) //공백 사용x
      • 예외2: String[][] x = {{"foo"}}; //공백 필요x
    • 이항 또는 삼항 연산자 양쪽 -> 다음과 같은 "operator-like" 기호에도 적용된다
      • 인접한 Type 바인딩의 앰퍼샌드 //<T extends Foo & Bar>
      • 여러 예외 처리 catch블록 파이프 //catch (FooException | BarException e)
      • for(int a : list)문의 콜론
      • 람다식 화살표 //(String str) -> str.length()
      • 허용되지 않음1: 메소드 참조의 두 콜론 //Object::toString
      • 허용되지 않음2: 다음과 같이 쓰인 점 구분 기호 //object.toString()
    • 캐스트 뒤 , :: 또는 )
    • // 주석을 시작하는 이중 슬래시 양쪽 -> 여러 개 공백 허용
    • 선언의 type과 변수 사이
    • 배열 선언문 괄호 안에 공백 :new int[] {5,6}  new int[] { 5,6 }
    • type annotation과 [] 또는 ...

 

  • 수평 정렬: 허용됨, 하지만 비추
    • 특정 토큰이 이전 줄 다른 특정 토큰 바로 아래에 표시되도록 코드에 다양한 수의 추가공백 넣는 방법
    • 가독성에 도움은 될 수 있지만 향후 유지관리에 문제됨 (포맷을 위한 한 줄 변경이 폭발 변경을 갖습니다/ 무의미한 작업 초래/ 버전 기록 정보를 손상시키고/ 검토자의 속도를 늦추고/ 병합충돌을 악화시킴)
    • 이렇게까지 말하는데 웬만하면 쓰지말자
private int x; // OK
private Color color; // OK

private int   x;      // OK, but future edits
private Color color;  // 맞춰지지 않은 상태로 둘 수 있음

 

  • 그룹화 괄호: 권장됨
    • 코드가 잘못 해석 될 가능성이 없음
    • 코드를 읽기 어렵다고 동의하는 경우만 생략된다
    • 자바 연산자 우선순위 테이블 매번 볼거임? 그러지 말고 우선순위가 명확해도 괄호로 감싸자!

 

Enum 클래스

  • enum 상수 뒤에 오는 각 쉼표 뒤 줄바꿈은 선택사항, 추가 빈 줄도 허용
  • 메서드와 주석 없으면 맨 아래처럼도 가능
  • 클래스 형식 지정에 대한 다른 모든 규칙이 적용됨 (중괄호 필수 등)
 private enum Answer {
  YES {
    @Override public String toString() {
      return "yes";
    }
  },

  NO,
  MAYBE
}

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

 

변수선언

  • 선언 당 하나의 변수
    • int a, b; 이런거 쓰지 말자~
    • 예외: for 루프 헤더는 여러 변수 선언이 허용됨
  • 필요할 때 선언
    • 지역변수는 포함 블록or블록 유사 구조 시작부분에서 습관적으로 선언 되지 않음
    • 대신 지역변수 범위 최소화 -> 처음 사용되는 지점에 가깝게 선언
    • 지역 변수 선언 -> 일반적으로 이니셜라이저 있거나 선언 직후 초기화됨
int count = 0;
for (int i=0; i<10; i++) {
  count++;
}

int count2 = 0;
for (int i=0; i<10; i++) {
  count2++;
}

 

배열

  • 배열 이니셜 라이저 = block-like
    • 모든 배열 이니셜 라이저는 block-like construct 인 것 처럼 형식화될 수 있다
    • 다음 경우 모두 가능
int arr[] = new int[] {
  0,1,2,3
};

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

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

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

(나는 1이랑 2를 많이 쓸 것 같다)

 

  • C스타일 배열 선언 x
    • 대괄호는 변수가 아니라 type이라고 생각합시다! //String[] args

 

Switch문

  • 스위치 블록의 중괄호 안에는 하나 이상의 구문 그룹이 있음
  • 각 구문 그룹: switch 라벨(case FOO:)과 하나 이상의 명령문으로 구성
  • 스위치 블록 내용은 +2 들여쓰기 
  • Fall-through: 주석
    • Switch블록 내 각 구문 그룹 중 하나가 돌연 종료되거나, 다음 구문으로 넘어가게 적을 수 있음
    • 이 경우 //fall through 라는 주석을 달 수 있음 (스위치 블록 마지막 명령문에는 필요x)
    • 아래 예시 case1 뒤에는 주석 필요x
  • default 코드가 없어도 default문 그룹이 포함됨
    • enum 유형에 대한 switch문에서 가능한 모든 경우를 포함하는 명시적 케이스를 처리한 경우 -> 명령문 그룹 생략가능
    • (IDE나 기타 정적 분석 도구는 누락 된 사례가 있는 경우 경고발행 가능)
 switch (input) {
  case 1:
  case 2:
    prepareOneOrTwo();
    // fall through
  case 3:
    handleOneTwoOrThree();
    break;
  default:
    handleLargeNumber(input);
}

 

Annotations

  • 클래스, 메서드 생성자에 적용되는 어노테이션은 document block 바로 뒤에 나타남
  • 한 줄에 하나의 어노테이션(각 어노테이션은 자체줄에 나열)
  • 파라미터 없는 단일 어노테이션은 한 줄 맨 처음 가능 //@Override public int method() {}
  • 필드에 적용되는 어노테이션도 document block 바로 뒤에 나타나지만, 이 경우 여러 개가 같은 줄 나열 가능
  • 파라미터, 지역 변수 또는 타입에 대한 형식화 특정 규칙은 없음
@Override
@Nullable
public String getNameIfPresent() { ... }

@Override public int hashCode() {}

@Partial @Mock DataLoader loader;

 

주석

  • 줄 바꿈 앞에는 임의의 공백과 구현 주석이 올 수 ㅇ -> 이 경우행을 공백이 아닌 것으로 렌더링함
  • 블록 주석 스타일
    • 주변 코드와 동일한 수준에서 들여쓰기 됨
    • /* ... */주석의 경우 후속 줄은 이전 줄에 *정렬 된 것으로 시작해야함
/*
 * This is                     
 * okay.                      
 */
 
// And so
// is this.

/* Or you can
 * even do this. */
  • 주석은 별포 또는 기타 문자로 그려진 박스에 포함되지 않음

 

Modifiers(접근 제한자)

  • 클래서 및 멤버 Modifiers는 java언어 사양에서 권장하는 순서로 나타냄
public abstract default static final transient volatile synchronized native strictfp
protected ...
private ...

 

숫자 리터럴

  • long값을 갖는 정수 리터럴 L은 대문자 쓰기 //300000000L
  • 1(일) 이랑 혼돈을 피하기 위함

 

 

5. Naming

모든 식별자 공통규칙

  • ASCII 문자 + 숫자 + _
  • 각 유효한 식별자 이름은 \w+정규식과 일치
  • 특수 접두사 or 접미사 사용 ㄴㄴ

 

식별자 유형별 규칙

  • 패키지 이름
    • 모두 소문자
    • 연속된 단어는 단순연결, 밑줄 없음, camelCase x
com.example.deepspacenot //o
com.example.deepSpace //x
com.example.deep_space //x

 

  • 클래스이름
    • UpperCamelCase
    • 명사 or 명사 구
    • 인터페이스 이름은 형용사 or 형용사 구 가능 //Readable 
    • 어노테이션 이름은 특정 규칙 x
    • 테스트 클래스 이름의 경우 끝에 Test 붙이기 //HashTest
  • 메서드 이름
    • lowerCamelCase
    • 동사 or 동사 구
    • JUnit 테스트 메서드 이름에 밑줄 표시되어 이름의 논리적 구성 요소 구분가능, 각 구성요소는 lowerCamelCase
      • <methodUnderTest>_<state>pop_emptyStack
    • 테스트 방법의 이름 정하는 규칙 x
  • Constant 이름
    • 상수 이름은 CONSTANT_CASE 사용
// Constants
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 }

// 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"};

 

  • 상수가 아닌 필드 이름 (정적 or 기타): lowerCamelCase
    • 명사 or 명사 구
  • 파라미터 이름: lowerCamelCase
    • 공용 메소드에서 한 문자 파라미터 이름 피하기
  • 지역 변수 이름: lowerCamelCase
    • final 이나 불변인 경우에도 지역 변수는 상수로 간주되지 않음 -> 상수 스타일 x
  • Type 변수 이름
    • 두 가지 스타일 중 하나
    • (1) 단일 대문자, 혹은 단일 숫자가 따라올 수 ㅇ //E, T2
    • (2) 클래스에 사용되는 형식의 이름 + 대문자 T //RequestT

 

카멜 케이스 만들기

  • 두문자어 또는 IPv6 또는 IOS와 같은 비정상적인 구조가 있는 경우 영어 구를 camelcase로 변환하는 합리적인 방법
  • 예측 가능성을 높이기 위해 Google스타일은 다음과 같은 (거의) 결정론적 체계를 지정함
    1. 산문 형식 이름으로 시작
    2. 구를 일단 ASCII로 변환, ' 제거 //Muller's book -> Mullers book
    3. 이 결과를 단어로 나누고 공백과 나머지 구두점(하이픈)으로 분리함 
    4. 모든 것을 lowerCase로 만들고 다음의 첫 번째 문자만 대문자로 표시
    5. 모든 단어를 단일 식별자로 결합 (원래 단어의 대소문자 거의 무시됨)
  • checkNoneempty 가능함

 

 

6. 프로그래밍 실습

 

@Override: 항상 사용

  • 부모 메서드가 @Deprecated인 경우 @Override 생략 가능

 

Caught exception: 무시되지 않음

  • Caught excaptions에 응답으로 아무것도 하지 않는 거 드뭄
  • catch블록에서 아무 조치 취하지 않을 경우 -> 꼭 주석으로 설명
try {
  int i = Integer.parseInt(response);
  return handleNumericResponse(i);
} catch (NumberFormatException ok) {
  // it's not numeric; that's fine, just continue
}
return handleTextResponse(response);

 

  • 테스트에서 포착된 예외는 excepted이름이거나 이걸로 시작하면 주석없이 무시가능
try {
  emptyStack.pop();
  fail();
} catch (NoSuchElementException expected) {
}

 

Static member: 클래스를 사용하여 정규화

  • 정적 클래스 멤버에 대한 참조가 정규화되어야하는 경우 해당 클래스의 type의 참조 또는 식이 아닌 해당 클래스의 이름으로 정규화됨
  • static 멤버 사용시 클래스 이름으로 쓰자. 변수명 xxxx
Foo aFoo = ...;
Foo.aStaticMethod(); // good
aFoo.aStaticMethod(); // bad
somethingThatYieldsAFoo().aStaticMethod(); // very bad

 

+) Finalizers는 사용되지 않음. 하지마십시오! -> 하지말자!

 

 

 

7. Javadoc

  • javadoc은 뭔지 몰라서 정리하진 않았다
  • 다음에 공부한 후에 추가할 생각.. 궁금하신 분은 위 링크 참고해주세요

 

+) 조금 더 조사한 정보

https://google.github.io/styleguide/javaguide.html

  • + 연산자 양쪽에 공백이 와도 된다

 

 

 

원래는 간단하게 보면서 필요한 것만 정리하려고 했지만, 코드를 막 짰던 지난 코딩세월이 생각나서 반성하는 겸 상세히 적었다. 

한 번 쭉 정리해보니 얼추 느낌을 이해했다! 여러 번 반복해서 읽어보고 많이 사용해보면서 익숙해져야겠다.

728x90