[Java] Java Code Convention

어정윤·2021년 1월 14일
0

Java 스터디

목록 보기
2/12
post-thumbnail

[Java] Java Code Convention

Code Convention은 여러가지 이유에서 프로그래머에게 중요하다.

  • 소프트웨어를 개발하는 일련의 모든 과정에 들어가는 비용 중 80%가 유지보수에 쓰여진다.
  • 소프트웨어의 직접 개발한 개발자가 그 소프트웨어의 유지보수를 담당하는 경우는 거의 보기 힘들다.
  • Code Convention을 지키면 가독성이 높아져 다른 개발자가 소스 코드를 처음 보더라도 더 빠르고 완벽하게 이해할 수 있게 된다.
  • 소스 코드를 제품으로 팔려고 한다면, 다른 소스 코드들과 잘 어울리도록 패키지를 적절하게 구성할 필요가 있다.

1. 이름(Naming)

1-1. 식별자에는 영문/숫자/언더스코어만 허용

변수명, 클래스명, 메소드명 등에는 영어와 숫자만을 사용한다.
상수에는 단어 사이의 구분을 위해 언더스코어(_)를 사용한다.

1-2. 한국어 발음대로의 표기 금지

식별자의 이름을 한글 발음을 영어로 옮겨서 표기하지 않는다. 한국어 고유명사는 예외이다.

  • 좋은 예: intangibleAssets (무형자산)
  • 나쁜 예: moohyungJasan (무형자산)

1-3. 대문자로 표기할 약어 명시

클래스명, 변수명에 쓰일 단어 중 모든 글자를 대문자로 표기할 약어의 목록을 프로젝트별로 명시적으로 정의한다.

약어의 대소문자 표기는 JDK의 클래스나 라이브러리들 사이에서도 일관된 규칙이 없다. 그러나 단일 프로젝트에서 규칙이 명확하지 않으면 같은 단어의 조합을 다른 이름으로 표기할 수 있어서 혼동을 유발한다.

그래서 기본 정책으로는 약어의 중간단어를 소문자로 표기하고 프로젝트별로 모두 대문자로 표기할 약어의 목록을 명시하는 방식이 가독성을 높이고 규칙을 단순화하는데 유리하다.

  • 좋은 예
    HTTP + API + URL의 클래스 이름의 경우
    • 대문자로 표기할 약어의 목록을 정의하지 않는 경우: HttpApiUrl
    • API만 대문자로 표기할 약어의 목록에 있을 경우: HttpAPIUrl
    • HTTP, API, URL이 대문자로 표기할 약어의 목록에 있을 경우: HTTPAPIURL

1-4. 패키지 이름은 소문자로 구성

패키지 이름은 소문자를 사용하여 작성한다.
단어별 구문을 위해 언더스코어(_)나 대문자를 섞지 않는다.

  • 좋은 예
package com.javastudy.thirdassignment
  • 나쁜 예
package com.javastudy.thirdAssignment
package com.javastudy.third_assignment

1-5. 클래스/인터페이스 이름에 대문자 카멜표기법 적용

클래스 이름은 단어의 첫 글자를 대문자로 시작하는 대문자 카멜표기법(Upper camel case)을 사용한다. 파스칼표기법(Pascal case)으로도 불린다.

  • 좋은 예
public class Reservation

public class AccessToken
  • 나쁜 예
public class reservation

public class Accesstoken

1-6. 클래스 이름에 명사 사용

클래스 이름은 명사나 명사절로 짓는다.

1-7. 인터페이스 이름에 명사/형용사 사용

인터페이스의 이름은 명사/명사절로 혹은 형용사/형용사절로 짓는다.

  • 좋은 예
public interface RowMapper {

public interface AutoClosable {

1-8. 테스트 클래스는 'Test'로 끝남

JUnit 등으로 작성한 테스트 코드를 담은 클래스는 'Test'을 마지막에 붙인다.

  • 좋은 예
public class WatcherTest {

1-9. 메소드 이름에 소문자 카멜표기법 적용

메소드의 이름에는 첫 번째 단어를 소문자로 작성하고, 이어지는 단어의 첫 글자를 대문자로 작성하는 소문자 카멜표기법(Lower camel case)를 사용한다.
테스트 클래스의 메소드 이름에서는 언더스코어(_)를 허용한다.

1-10. 메소드 이름은 동사/전치사로 시작

메소드명은 기본적으로는 동사로 시작한다. 다른 타입으로 전환하는 메소드나 빌더 패턴을 구현한 클래스의 메소드에는 전치사를 쓸 수 있다.

  • 좋은 예
    • 동사 사용: renderHtml()
    • 전환메소드의 전치사: toString()
    • Builder 패턴 적용한 클래스의 메소드의 전치사: withUserId(String id)

반환값이 고정되어있는 메소드명

  1. is~ : boolean 타입 리턴
  2. has~ : boolean 타입 리턴
  3. contain~ : boolean 타입 리턴
  4. validate~ : 리턴값 없음

1-11. 상수는 대문자와 언더스코어로 구성

상태를 가지지 않는 자료형이면서 static final로 선언되어 있는 필드일 때를 상수로 간주한다.
상수 이름은 대문자로 작성하며, 복합어는 언더스코어(_)를 사용하여 구분한다.

  • 좋은 예
public final int UNLIMITED = -1;
public final String POSTAL_CODE_EXPRESSION = "POST";

1-12. 변수에 소문자 카멜표기법 적용

상수가 아닌 클래스의 멤버변수/지역변수/메소드 파라미터에는 소문자 카멜표기법(Lower camel case)을 사용한다.

  • 좋은 예
private boolean authorized;
private int accessToken;
  • 나쁜 예
private boolean Authorized;
private int AccessToken;

1-13. 임시 변수 외에는 1 글자 이름 사용 금지

메소드 블럭 범위 이상의 생명 주기를 가지는 변수에는 1글자로 된 이름을 쓰지 않는다.
반복문의 인덱스나 람다 표현식의 파라미터 등 짧은 범위의 임시 변수에는 관례적으로 1글자 변수명을 사용할 수 있다.

  • 좋은 예
HtmlParser parser = new HtmlParser();
  • 나쁜 예
HtmlParser p = new HtmlParser();

2. 선언(Declarations)

2-1. 소스파일당 1개의 탑레벨 클래스 담기

탑레벨 클래스는 소스파일에 1개만 존재해야 한다.
굳이 한 파일 안에 선언해야 한다면 내부 클래스로 선언한다.

2-2. static import에만 와일드 카드 허용

클래스를 import할 때는 와일드카드(*)없이 모든 클래스명을 다 쓴다.
static import에서는 와일드카드를 허용한다.

2-3. 제한자 선언의 순서

클래스/메소드/멤버변수의 제한자는 Java Language Specification에서 명시한 아래의 순서로 쓴다.
public protected private abstract static final transient volatile synchronized native strictfp

2-4. 애너테이션 선언 후 새줄 사용

클래스, 인터페이스, 메소드, 생성자에 붙는 애너테이션은 선언 후 새줄을 사용한다. 이 위치에서도 파라미터가 없는 애너테이션 1개는 같은 줄에 선언할 수 있다.

  • 좋은 예
@RequestMapping("/guests")
public void findGuests() {}
  • 좋은 예
@Override public void destroy() {}

2-5. 한 줄에 한 문장

문장이 끝나는 ; 뒤에는 새 줄을 삽입한다.

2-6. 하나의 선언문에는 하나의 변수만

변수 선언문은 한 문장에서 하나의 변수만을 다룬다.

2-7. 배열에서 대괄호는 타입 뒤에 선언

배열 선언에 오는 대괄호([])는 타입의 바로 뒤에 붙인다. 변수명 뒤에 붙이지 않는다.

2-8. 'long'형 값의 마지막에 'L' 붙이기

long형의 숫자에는 마지막에 대문자'L'을 붙인다.

2-9. 특수 문자의 전용 선언 방식을 활용

\b, \f, \n, \r, \t, \, \\와 같이 특별히 정의된 선언 방식이 있는 특수 문자가 있다. 이런 문자들은 숫자를 이용한 \008이나 \u008와 같은 숫자를 넣은 선언보다 전용 방식을 활용한다.

  • 좋은 예
System.out.println("---\n---");
  • 나쁜 예
System.out.println("---\012---");

3. 들여쓰기(Indentation)

3-1. 하드탭 사용

탭(tab) 문자를 사용하여 들여쓴다. 탭 대신 스페이스를 사용하지 않는다.

3-2. 탭의 크기는 4개의 스페이스

1개의 탭의 크기는 스페이스 4개와 같도록 에디터에서 설정한다.

3-3. 블록 들여쓰기

클래스, 메소드, 제어문 등의 코드 블록이 생길 때마다 1단계를 더 들여쓴다.

4. 중괄호(Braces)

4-1. K&R 스타일로 중괄호 선언

클래스 선언, 메소드 선언, 조건/반복문 등의 코드 블록을 감싸는 중괄호에 적용되는 규칙이다. 중괄호 선언은 K&R 스타일(Kernighan and Ritchie style)을 따른다.
줄의 마지막에서 시작 중괄호 '{'를 쓰고 열고 새 줄을 삽입한다. 블록을 마친 후에는 새 줄 삽입 후 중괄호를 닫는다.

4-2. 닫는 중괄호와 같은 줄에 else, catch, finally, while 선언

아래의 키워드는 닫는 중괄호 (})와 같은 줄에 쓴다.

  • else
  • catch, finally
  • do-while 문에서의 while

4-3. 빈 블록에 새 줄 없이 중괄호 닫기 허용

내용이 없는 블록을 선언할 때에는 같은 줄에서 중괄호 닫는 것을 허용한다.

4-4. 조건/반복문에는 중괄호 필수 사용

조건, 반복문이 한 줄로 끝나더라도 중괄호를 활용한다.

5. 줄바꿈(Line-wrapping)

5-1. 최대 줄 너비는 120

최대 줄 사용 너비는 120자까지 가능하다.

5-2. package, import 선언문은 한 줄로

package, ìmport 선언문 중간에서는 줄을 바꾸지 않는다. 최대 줄 수를 초과하더라도 한 줄로 쓴다.

5-3. 줄바꿈 후 추가 들여쓰기

줄바꿈 이후 이어지는 줄에서는 최초 시작한 줄에서보다 적어도 1단계의 들여쓰기를 더 추가한다.

  • 좋은 예
AbstractAggregateRootTest.AggregateRoot proxyAggregateRoot =
        em.getReference(AbstractAggregateRootTest.AggregateRoot.class, aggregateRoot.getId());

5-4. 줄바꿈 허용 위치

가독성을 위해 줄을 바꾸는 위치는 다음 중 하나로 한다.

  • extend 선언 후
  • implements 선언 후
  • throws 선언 후
  • 시작 소괄호(()) 선언 후
  • 콤마(,) 후
  • 마침표(.) 전
  • 연산자 전
    • +, -, *, /, %
    • ==, !=, >=, >, <=, <, &&, ||
    • &, |, ^, >>>, >>, <<, ?
    • instanceof

6. 빈줄(Blank lines)

6-1. package 선언 후 빈 줄 삽입

package를 선언한 후 빈 줄을 삽입한다.

6-2. import 선언의 순서와 빈 줄 삽입

import 구절은 아래와 같은 순서로 그룹을 묶어서 선언한다.

  1. static imports
  2. java.
  3. javax.
  4. org.
  5. net.
  6. 8~10을 제외한 com.*
  7. 1~6, 8~10을 제외한 패키지에 있는 클래스
  8. com.nhncorp.
  9. com.navrcorp.
  10. com.naver.

각 그룹 사이에는 빈 줄을 삽입한다.
각 그룹 내에서는 알파벳 순으로 정렬한다.

  • 좋은 예
import java.util.Date;
import java.util.List;

import javax.naming.NamingException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;

import com.google.common.base.Function;

import com.naver.lucy.util.AnnotationUtils;

6-3. 메소드 사이에 빈 줄 삽입

메소드의 선언이 끝난 후 메소드 선언이 시작되기 전에 빈 줄을 삽입한다.

7. 공백(Whitespace)

7-1. 공백으로 줄을 끝내지 않음

빈 줄을 포함하여 모든 줄은 탭이나 공백으로 끝내지 않는다.

7-2. 대괄호 뒤에 공백 삽입

닫는 대괄호(]) 뒤에 ';'으로 문장이 끝나지 않고 다른 선언이 올 경우 공백을 삽입한다.

7-3. 중괄호의 시작 전, 종료 후에 공백 삽입

여는 중괄호({) 앞에는 공백을 삽입한다.
닫는 중괄호(}) 뒤에 else, catch 등의 키워드가 있을 경우 중괄호와 키워드 사이에 공백을 삽입한다.

7-4. 제어문 키워드와 여는 소괄호 사이에 공백 삽입

if, for, while, catch, synchronized, switch와 같은 제어문 키워드의 뒤에 소괄호(())를 선언하는 경우, 시작 소괄호 앞에 공백을 삽입한다.

7-5. 식별자와 여는 소괄호 사이에 공백 미삽입

식별자와 여는 소괄호(() 사이에는 공백을 삽입하지 않는다. 생성자와 메소드의 선언, 호출, 애너테이션 선언 뒤에 쓰이는 소괄호가 그에 해당한다.

  • 좋은 예
public StringProcessor() {}	// 생성자

@Cached("local")
public String removeEndingDot(String original) {
    assertNotNull(original);
    ...
}
  • 나쁜 예
public StringProcessor () {}	// 생성자

@Cached ("local")
public String removeEndingDot (String original) {
    assertNotNull (original);
    ...
}

7-6. 타입 캐스팅에 쓰이는 소괄호 내부 공백 미삽입

타입캐스팅을 위해 선언한 소괄호의 내부에는 공백을 삽입하지 않는다.

7-7. 제네릭스 산괄호의 공백 규칙

제네릭스(Generics) 선언에 쓰이는 산괄호(<>) 주위의 공백은 다음과 같이 처리한다.

  • 제네릭스 메소드 선언일 때만 < 앞에 공백을 삽입한다.
  • < 뒤에 공백을 삽입하지 않는다.
  • > 앞에 공백을 삽입하지 않는다.
  • 아래의 경우를 제외하고는 > 뒤에 공백을 삽입한다.
    • 메소드 레퍼런스가 바로 이어질 때
    • 여는 소괄호(()가 바로 이어질 때
    • 메소드 이름이 바로 이어질 때
  • 좋은 예
public static <A extends Annotation> A find(AnnotatedElement elem, Class<A> type) { // 제네릭스 메서드 선언
    List<Integer> l1 = new ArrayList<>(); // '(' 가 바로 이어질때
    List<String> l2 = ImmutableList.Builder<String>::new; // 메서드 레퍼런스가 바로 이어질 때
    int diff = Util.<Integer, String>compare(l1, l2); // 메서드 이름이 바로 이어질 때
}

7-8. 콤마/구분자 세미콜론의 뒤에만 공백 삽입

콤마(,), 반복문(while, for)의 구분자로 쓰이는 세미콜론(;) 뒤에만 공백을 삽입한다.

7-9. 콜론의 앞 뒤에 공백 삽입

반복문과 삼항연산자에서는 콜론(:)의 앞 뒤에는 공백을 삽입한다. 라벨 선언 뒤에는 아무런 문자열이 없으므로 앞에만 공백을 삽입한다.

  • 좋은 예
for (Customer customer : visitedCustomers) {
    AccessPattern pattern = isAbnormal(accessLog) ? AccessPattern.ABUSE : AccessPattern.NORMAL;
    int grade = evaluate(customer, pattern);

    switch (grade) {
        case GOLD :
            sendSms(customer);
        case SILVER :
            sendEmail(customer);
        default :
            inreasePoint(customer)
    }
}

7-10. 이항/삼항 연산자의 앞 뒤에 공백 삽입

이항/삼항 연산자의 앞 뒤에는 공백을 삽입한다.

  • 좋은 예
f (pattern == Access.ABNORMAL) {
    return 0;
}

finalScore += weight * rawScore - absentCount;

if (finalScore > MAX_LIMIT) {
    return MAX_LIMIT;
}

7-11. 단항 연산자와 연산 대상 사이에 공백을 미삽입

단항 연산자와 연산 대상의 사이에는 공백을 삽입하지 않는다.

  • 전위 연산자 : 연산자 뒤에 공백을 삽입하지 않는다.
    • 전위 증가/감소 연산자 : ++, --
    • 부호로 쓰이는 +, -
    • NOT 연산자 : ~, !
  • 후위 연산자 : 연산자 앞에 공백을 삽입하지 않는다.
    • 후위 증가/감가 연산자 : ++, --

7-12. 주석문 기호 전후의 공백 삽입

주석의 전후에는 아래와 같이 공백을 삽입한다.

  • 명령문과 같은 줄에 주석을 붙일 때 //
  • 주석 시작 기호 //
  • 주석 시작 기호 /*
  • 블록 주석을 한 줄로 작성시 종료 기호 */




참고 : 캠퍼스 핵데이 Java 코딩 컨벤션

profile
성장ing

0개의 댓글