[Java] 35. 코딩 스타일 설정(Google Standard coding style)


Study/Java  2020. 6. 16. 11:57

안녕하세요. 명월입니다.

 

이 글은 Java에서 코딩 규약 설정(Google Standard coding style)에 대한 글입니다.

 

프로그램 프로젝트를 진행하다 보면 여러가지 룰과 규칙을 만들어야 할 때가 많습니다. 프로젝트를 혼자 진행하고 운영하다 보면 상관없을 지 모르겠지만, 프로그램 프로젝트는 혼자하는 경우는 적기 때문에 여러 사람들간에 코딩 룰을 정하는 게 중요하다고 할 수 있습니다.

예를 들면 변수명을 「abcde」라고 작성하면 작성한 사람은 무슨 변수일 지 알 수 있을 지 모르겠지만 다른 사람이 보면 참조 추적을 하지 않는 이상 변수의 의미를 알 수가 없습니다. 그러나 「avg」라는 변수명을 사용하면 정확히는 모르지만 대충 평균에 관한 변수구나 정도는 인식할 수 있습니다.

즉, 코딩 규약은 프로그램의 성능이나 최적화에는 크게 영향이 가는 것이 없고 클래스 이름만 봐도 무슨 클래스인지, 변수명과 함수명만 봐도 어떤 함수인지 변수인지 알 수 있게 간결하고 이해하기 쉽게 작성하는 것입니다.

 

코딩 규약은 여러 종류가 있습니다만 Java의 경우는 Google의 코딩 규약을 많이 사용합니다.

링크 - 구글 자바 스타일(Google java Style)

 

1. 소스 파일 기본 사항

1.1. 소스 파일 이름이 포함된 최상위 클래스의 대소문자로 구분 이름을 명명한다. 확장자는 .java로 지정한다.

    예) ExampleSource.java

1.2. 파일의 인코딩은 UTF-8로 지정한다.

1.3. 공백문자는 소스 파일에서 아무렇게나 쓸 수 있는 유일한 문자이다.

1.4. 모든 특수 문자를 사용할 때 이스케이프 시퀀스(예를 들어 \b , \t , \n , \f , \r , \" , \' 와 \\ )를 사용한다.

    그러나 그 문자의 진수(\012 ). 유니코드 (예 : \u000a ) 는 사용하지 않는다.

1.5. 코드 가독성이 좋다면 비 ASCII문자(\u221e)를 사용해도 무방하다.

String unitAbbrev = "μs";
String unitAbbrev = "\u03bcs"; // "μs"
String unitAbbrev = "\u03bcs"; // Greek letter mu, "s"
String unitAbbrev = "\u03bcs";
return '\ufeff' + content; // byte order mark

※위 예제는 상수 변수를 선언할 때의 예제입니다. 가장 좋은 것은 주석없이 알아보기 쉬운 값을 넣는 것이고, 인코딩상 그것이 힘들다면 유니코드를 사용하고 주석으로 설명하는 것도 나쁘지 않습니다.

2. 소스 파일 구조

소스 파일의 구조의 순서는 다음과 같다

1. 라이센스 또는 저작권 정보, 존재하는 경우.

2. 패키지 문

3. 가져오기 문

4. 정확히 하나의 최상위 클래스

/*
 * Copyright (c) 1997, 2014, 저작권
 */
package 패키지;
import 참조 클래스;
public class 클래스명 {
}

3. 서식

3.1. 중괄호

- 여는 중괄호 전에는 줄 바꿈이 없다.

- 여는 중괄호 후에는 줄 바꿈이다.

- 닫는 중괄호 전에는 줄 바꿈이다.

- 줄에 닫는 중괄호만 있는 경우는 메소드, 생성자, 클래스가 종료될 때이다.

- 빈 블록 : 중괄호 사이에 아무 문자가 없으면 즉시 닫을 수 있다. ({})

// 여는 중괄호 전에는 줄 바꿈이 없다.
return new MyClass() {
  @Override public void method() {
    if (condition()) {
      try {
        something();
      } catch (ProblemException e) {
        recover();
      // 닫는 중괄호 전에는 줄바꿈이다.
      }
      // 중괄호 사이에 아무 문자가 없으면 즉시 닫을 수 있다.
      finally{}
    }
  }
};

3.2. 블록 들여쓰기 : +2 공간

새로운 블록과 같은 구조는 두 개의 공백으로 들여쓰기가 열린다. 문의 종료 시 이전 쓰기 수준으로 들여쓰기는 돌아간다

// +2 단위로 들여쓰기
public class ExClass {
  public ExClass() {
    int a = 0;
    for (int i = 0 ; i < 10; i++) {
      if (i == 9) {
        break;
      }
    }
  }
}

※개인적으로 들여쓰기 +2는 조금 빡빡해 보이기 때문에 +4던가 tab을 사용할 때도 많습니다.

 

3.3. 열 제한 : 80

프로젝트 중 80 또는 100문자의 열 제한을 한다.

 

3.4. Line-wrapping

정해진 규칙은 없고, 일반적으로 열 제한을 방지하기 위해 적용한다.

  3.4.1. 열이 바뀌는 지점

  - 일반 연산자 앞에서 줄 바꿈이 일어난다.

  - 대입 연산자의 경우는 뒤에서 줄 바꿈이 일어난다.

  - 메소드, 생성자의 이름에는 괄호「(」를 부착한 상태로 유지한다.

  - 쉼표는 앞에 토큰에 연결된 상태를 유지한다.

 

  3.4.2. 들여쓰기는 적어도 +4 공간

// 대입 연산자의 경우는 뒤에서 줄 바꿈이 일어난다.
Class cls =
    new Class();
// 쉼표는 앞에 토큰에 연결된 상태를 유지한다.
cls.method("a" ,
    "b");
// 메소드, 생성자의 이름에는 괄호「(」를 부착한 상태로 유지한다.
cls.method(
    "aaa"
//일반 연산자 앞에서 줄바꿈이 일어난다.
    + "bbb");

3.5. 공백

  3.5.1. 수직 공백

  - 필드, 생성자, 중첩 메소드, 클래스 사이

  - 여러 줄의 빈 줄은 허용하지만, 추천하지 않는다.

 

  3.5.2. 수평 공백

  - if, for, catch와 그다음에 오는 '(' 사이에 공백문자

  - else, catch와 그 이전에 오는 '}' 사이에 공백문자

  - ',', ':', ';'의 다음이나 타입 캐스트시의 ')' 다음에 공백문자

  - 연산자 앞뒤로는 공백문자 삽입

  - 연산자와 비슷한 심볼에서도 앞뒤로 공백문자 삽입

public class MyClass {
  int a;
  int b;
  // 수직공백
  public MyClass() {
    // if, for, catch 와 그 다음에 오는 '(' 사이에 공백문자
    // 연산자 앞 뒤로는 공백문자 삽입
    for ( int i = 0; i < 10; i++) {
        //',', ':', ';'의 다음 이나 타입 캐스트시의 ')'  다음에 공백문자
        if ( i < 10 ) {
        //else, catch와 그 이전에 오는 '}' 사이에 공백문자
        } else {
        }
    }
  }
  // 수직공백
  public void run() {
  }
}

3.6. 그룹화 권장

소스의 그룹화를 통해 가독성을 높일 수 있습니다.

public class MyClass {
  // 수직공백
  public void run() {
    int a = 0;
    int b = 0;
    // 그룹화
    {
      a += 10;
      a -= 5;
      System.out.println(a);
    }
    // 그룹화
    {
      b += 62;
      b -= 3;
      System.out.println(b);
    }
  }
}

3.7. 특정 구조

  3.7.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}

  3.7.2 변수 선언

  - 모든 변수 선언(맴버 또는 지역)은 하나의 라인에서 선언하지 않는다.

  - 맴버 변수는 클래스 상단에 사용한다.

  - 지역 변수는 일반적으로 초기화를 하거나 선언 후 즉시 초기화합니다.

public class ExText() {
  // 맴버 변수는 클래스 상단에 사용한다.
  private String item;
  public void test() {
    int c, d; // 모든 변수 선언(맴버 또는 지역)은 하나의 라인에서 선언하지 않는다.
    // 지역 변수는 일반적으로 초기화를 하거나 선언 후 즉시 초기화합니다.
    String item2 = "테스트2",
           item = "테스트";
    System.our.println(item + item2);
  }
}

  3.7.3. C 스타일 배열 선언

  String[] args로 선언한다.(C스타일인 String args[]가 아니다)

 

  3.7.4. Switch

    3.7.4.1. 들여쓰기

    - 스위치문 뒤에 열린 중괄호를 두고 줄 바꿈이 일어난다.

    - 줄 바꿈 후에는 +2 들여쓰기가 일어난다. 중괄호가 종료되면 이전 들여쓰기 수준으로 돌아간다.

    - case, default 뒤 줄바꿈이 일어난다. 줄 바꿈이 일어나면 블록이 열려있는 것처럼 +2 들여쓰기가 일어난다.

    - case, default 블록이 종료되면 이전 들여쓰기 수준으로 돌아간다.

 

    3.7.4.2. 통과주석

    - Switch ~ case는 기본적으로 break, return, throw로 switch의 블록 구분을 나타낸다.

    - 다음 case 계속된 실행을 나타낼 때는 /*계속 진행*/ 이라는 주석을 남긴다.

switch (input) {
  case 1:
  case 2:
    prepareOneOrTwo();
    // 계속 진행
  case 3:
    handleOneTwoOrThree();
    break;
  default:
    handleLargeNumber(input);
}

  3.7.5. 어노테이션

  - 하나의 라인에 어노테이션을 사용한다. 들여쓰기는 증가하지 않는다.

@Override
@Nullable
public String getNameIfPresent() { ... }

  3.7.6. 주석

  - 주석은 주변 코드와 같은 수준의 들여쓰기를 사용한다.

/*
 * 안녕하세요. 명월일지입니다.
 */
// 명월일지입니다.

  3.7.7. 숫자 리터럴

  - long 타입의 리터럴은 대문자로 사용 L (숫자와의 혼동을 피하기 위해서)

4. 네이밍

4.1. 패키지 이름

- 패키지 이름은 단순히 함께 연결된 연속 단어, 모두 소문자로 되어있다. com.example.deepspace

 

4.2. 클래스 이름

- 클래스 이름은 명사 또는 명사구입니다. 인터페이스 이름은 명사 또는 명사구, 형용사구이다. (형용사 + 명사)

- 클래스의 단어 구분은 대문자로 구분한다.

- Unit 테스트 클래스는 test로 시작합니다.

 

4.3. 메소드 이름

- 메소드 이름은 동사나 동사구이다. (동사 + 명사)

- 메소드의 단어의 구분은 대문자로 구분한다.

- Unit 테스트 클래스는 test로 시작한다.

 

4.4. 상수 이름

- 상수 이름은 모두 대문자로 밑줄로 단어 구분이 된다.

 

4.5. 맴버 변수 이름

- 일반적으로 명사 또는 명사구이다.

 

4.6. 지역 변수 이름

- 일반적으로 명사 또는 명사구이다.

- 지역변수는 단어를 자유롭게 단축할 수 있다.

/*
 * Copyright (c) 1997, 2014, 저작권
 */
// 패키지 이름은 모두 소문자입니다.
package com.example.deepspace;

// 클래스 이름은 형용사구(형용사 + 명사) 또는 명사구(명사 + 명사)로 이루어져 있으며 구분은 대문자로 한다.
public class CodingTestClass {
  // 상수는 모두 대문자로 표시되며 구분자는 밑줄로 구분한다.
  public final static String KEY_NUMBER1 = "1";
  // 맴버변수는 명사구(명사 + 명사)로 구분된다.
  private String key = "abcde";
  // 메소드는 동사구(동사 + 명사) 또는 명사구(명사 + 명사)로 구분된다.
  public String convertKey(String keyType) {
    // 지역변수는 자유롭게 단축이 가능하다. returnVal -> retVal
    String retVal = this.key + keyType;
      return retVal;
  }
}

5. 그외 규칙

5.1. @Override

- 인터페이스 방법을 구현하는 방법 또는 재정의하는 매소드의 경우는 @Override를 반드시 사용한다.

 

5.2 예외 규칙을 무시하지 않기

- try ~catch를 사용하는 경우 catch문안에 아무런 내용이 없으면 안 된다.

 

5.3. 정적의 참조

- 직접적인 참조로 사용한다.

public class CodingTestClass extends CodingParentsClass {
  //상속 받는 메소드는 반드시 Override를 선언한다.
  @Override
  public String transData(String data) {
    data += "trans";
    return data;
  }
  public static String getTransData() {
    return "exam";
  }
  public CodingTestClass() {
    //정적 메소드는 반드시 직접 참조를 한다.
    // CodingTestClass codingTest
    // codingTest.getTransData() // 이렇게 변수를 통해서 정적 메소를 참조하면 안된다.
    try {
      // 클래스 명으로 직접 참조한다.
      String temp = transData(CodingTestClass.getTransData());
    } catch (Exception e) {
      // catch 안에 아무런 내용이 없으면 안된다.
      e.printStackTrace();
    }
  }
}

6. 자바독

6.1 서식

  6.1.1 일반적인 양식

/**
 * 자바독에 대한 예제입니다.
 * 일반 적인 서식은 이런 형태입니다.
 */
public int method(String p1) { ... }

  6.1.2 단락

  - 한 줄의 빈 라인입니다.

 

  6.1.3 절

  - @param , @return , @throws , @deprecated의 네 가지 유형은 반드시 설명이 있어야 한다.

 

  6.1.4 내용

  - 반드시 하나의 문장으로 완성해야 합니다.

/**
 * 자바독에 대한 예제입니다.
 * 일반 적인 서식은 이런 형태입니다.
 *
 * 단락은 빈라인으로 표시됩니다.
 * 주석의 절은 반드시 하나의 문장으로 표시합니다.
 * @param p1 테스트 데이터를 입력합니다.
 * @return  테스트 데이터를 1 가산한 값으로 반환합니다.
 * @throws String을 1의 정수로 변환시에 수가 아닌 값이 문자열에 존재하면 에러를 발생합니다.
 * @deprecated Java 1.7 이전 버전에서는 사용하지 않습니다.
 */
public int method(String p1) { ... }

만약 eclipse를 사용하는 유저라면 IDE 툴에 style을 설정하여 자동으로 코딩 규약에 맞게 소스를 작성할 수 있습니다.

링크 - https://github.com/google/styleguide/blob/gh-pages/eclipse-java-google-style.xml

 

이거를 이클립스에 적용해 보겠습니다.

여기까지 이클립스에 스타일이 적용되었습니다.

 

Java 소스를 작성하고 포멧을 적용하겠습니다.

적용이 잘 됩니다.

 

여기까지 Java에서 코딩 스타일 설정(Google Standard coding style)에 대한 글이었습니다.

 

궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.