JAVA Code Convention

포모·2020년 11월 25일
1

Clean Code

목록 보기
1/6
post-custom-banner

💡 Coding Convetion이란?

코딩을 하는 프로그래머 사이의 규칙을 의미합니다.
코딩 규칙을 지킨다면 다른 개발자가 개발한 소스코드를 처음 보았을 때 더 빠른 시간 안에 완벽하게 이해할 수 있도록 도와주기 때문에,소프트웨어의 가독성이 높아진다고 합니다.


📝 Google Java Style Guide

구글의 자바 코딩 규약을 알아보겠습니다!

세상에 전부 영어라니..😱 파파고+구글링의 도움을 얻어 도전..!


🎯 Source file Basics

1. File name

원본 파일 이름은 .java 확장자에 포함된 최상위 클래스의 대소문자 구분 이름과 .java 확장자로 구성됩니다.

파일 형태확장자
자바 소스.java
자바 바이트코드.class

2. File encoding : UTF-8

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

UTF-8은 유니코드를 인코딩(encoding)하는 방식이다. 전세계에서 사용하는 약속이다.

자세한 내용은 [Unicode와 UTF-8]을 참조하시면 됩니다.

3. Special characters

  • Whitespace characters (공백 문자)

    공백 문자는 '스페이스키'만 허용한다. (ASCII 0x20) 탭은 사용하지 않습니다.

    1. 문자열 및 문자 리터럴의 다른 모든 공백 문자는 이스케이프됩니다.
    2. 탭 문자는 들여쓰기에 사용되지 않습니다.
  • Special escape sequences (이스케이프 시퀀스)

    • 특수 문자를 표현할 때 '\b', '\n', '\' 등을 사용한다.
    • 8진법(\012), 유니코드 표현 등을 사용하지 않습니다.

🎯 Source file structure (소스 파일 구조)

  1. 라이선스나 저작권 정보
  2. 패키지문
  3. import문
  4. 최상위 클래스

각 섹션 사이에 공백 라인 하나가 반드시 존재합니다.

  • package 문의 경우 아무리 길어도 한 문장으로 써야합니다.
  • import 문에는 *를 쓰지 않는다. package 문과 동일하게 한 문장에 작성합니다.
  • import 문은 그룹핑 하여 순서에 맞춰 작성합니다. 다른 그룹간 공백 라인을 한 줄 추가합니다.
  • 클래스 멤버의 순서는 절대적이지 않지만 이들의 순서가 논리적이어야 합니다.
  • 멤버 순서에 대해 하나의 제약 사항이 있는데 동일한 메소드명 (생성자, 오버라이딩된 메소드들)은 한 곳에 모아두어야 합니다.

  • 자바 소스 파일 구조 예시

  • 시작 주석

/* 
* 클래스 이름 
* 
* 버전 정보
* 
* 날짜 
* 
* 저작권 주의 
*/

🎯 Formating

Braces (중괄호)

본문이 비어있고 단일문만 포함되는 경우에도 반복문, 조건문과 함께 사용됩니다.

K&R Style

  • K&R 스타일은 여는 궁괄호 앞에 줄 바꿈이 없으면 그 다음에 줄 바꿈이 있습니다. 다만 닫는 중괄호는 줄 바꿈을 합니다.
  • 닫는 중괄호가 수행을 종료하는 메소드나 생성자나 클래스면, 중괄호가 닫힐 때 줄을 바꾸나, else나 쉼표가 뒤따라오면 줄 바꿈이 없습니다.

Empty blocks (들여쓰기)

  • 새로운 블록이나 같은 범위의 블록이 열릴 때마다 공백이 두 칸 증가합니다.

Column limit (열 제한)

자바 코드의 열 제한은 100자입니다.

One statement per line

각각의 명령줄은 한 줄에 하나의 명령줄을 가집니다.

Line-wrapping

코드의 길이가 페이지 넓이를 넘어갈 때, 하나의 문장을 두 문장 이상으로 나눠서 표현하는데 이런 행위를 Line-wrapping이라고 합니다.
절대적인 법칙은 없고 상황에 따라 적절하게 사용하면 된다고 하네요.


가끔은 Line-Wrapping보다 리팩토링을 실시하는 것이 더 올바른 선택일 수도 있습니다.
public void onAttachFragment(Fragment fragment) {
   ... 중략 ...

        final FragmentTransaction transaction =
                getFragmentManager().beginTransaction();
   ... 중략 ...
}   

위와 같이 과도한 들여쓰기로 발생하는 코드의 경우 멤버 변수화 시킴으로써 해결할 수도 있습니다.

final FragmentTransaction mTransaction = getFragmentManager().beginTransaction();

public void onAttachFragment(Fragment fragment) {
    ... 중략 ...
}   

Line-wrapping된 문장은 기본적으로 2번 이상의 들여쓰기를 해야한다. (4개의 스페이스 이상)


🌈 어디서 다음 문장으로 내릴까?

  1. 대연산자가 아닌 곳에서 잘라야 할 경우 심볼 앞에서 내립니다.
this.someString = new StringBuffer()
    		  .append("Humans ")
    		  .append("are ")
    		  .append("intelligent ")
    		  .append("apes.");
  1. 대입 연산자에서 잘라야할 경우 대입 연산자 뒤에서 문장을 내립니다.
private final OnPhoneNumberPickerActionListener mPhoneNumberPickerActionListener =
    new OnPhoneNumberPickerActionListener() {  
  1. 함수 호출의 경우 '('는 첫 문장에 두고 나머지를 다음 문장으로 내립니다.
addContactOptionMenuItem.setIntent(
    new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI));
  1. 콤마(',')의 경우 앞의 식별자와 동일한 단어로 취급합니다.
public void onLayoutChange(View v, int left, int top, int right, int bottom,
    int oldTop, int oldRight, int oldBottom) {  

Variable declarations (변수 선언)

  • 모든 변수 선언은 하나의 변수만 선언합니다.
  • int a, b;와 같이 작성하지 않습니다.
  • 변수 선언은 함수 처음에 하지 않습니다. 최대한 변수가 사용되는 위치 근처에서 선언하여 변수의 스코프를 최소화시킵니다.

Switch statements

  • 스위치문은 2칸 들여쓰기를 합니다. (스위치문 내에서도 마찬가지)
  • default는 무조건 있어야 합니다.
switch (input) {
  case 1:
  case 2:
    prepareOneOrTwo();
    // fall through -- 이런 식으로 주석을 달아줍니다.
  case 3:
    handleOneTwoOrThree();
    break;
  default:
    handleLargeNumber(input);
}

Comments (주석)

클래스, 메소드 또는 생성자에 적용되는 주석은 문서 블록의 바로 뒤에 작성됩니다.
매개 변수나 지역 변수에 대한 서식의 특정 규칙은 없습니다.

/*
 * This is          // And so           /* Or you can
 * okay.            // is this.          * even do this. */
*/

Numeric Literals (숫자 리터럴)

long 값의 정수 리터럴은 대문자 L을 사용합니다. (ex. 30L)


🎯 Naming

Rules common to all identifiers (공통 네이밍)

  • 식별자는 ASCII 문자와 숫자만 사용합니다.
  • 식별자에 prefix나 suffixes는 사용하지 않습니다.
   name_ (x)
   mName (x)
   s_name (x)
   kName (x)

Rules by identifier type (Type 명에 대한 규칙)

  1. package 명

    패키지 이름은 모두 소문자로 하며 연속 단어들은 연결됩니다.

    • com.example.deepspace (O)
    • com.example.deepSpace (X)
    • com.example.deep_space (X)
  2. Class 명

    클래스 이름은 UpperCamelClass입니다.
    대문자로 시작하고 단어가 바뀔 때마다 다시 대문자로 표시하는 것을 의미합니다.
    만약 테스트 클래스라면 이름 끝에 Test를 붙입니다.

  3. Method 명

    메소드 이름은 lowerCamerlCase를 사용합니다.
    소문자로 시작해서 단어가 바뀔 때마다 다시 대문자로 표시하는 방식을 의미합니다.
    메소드 명의 경우 동사이거나 동사구이다.

    테스트 클래스 내의 테스트 메소드인 경우 test<test 메소드 명>_<상태>와 같은 방식으로 작성한다.
    (ex. testPop_emptyStack)
    그러나 절대적인 방식은 아닙니다.

  4. 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"};
  1. Non-constant field 명

    필드는 다른 말로 멤버변수나 전역변수라고 불립니다.
    lower camel case이며, 일반적으로 명사로 이루어져 있습니다.

  2. Parameter 명

    lower camel case이며, 한 문자 매개변수명은 피합니다.

  3. Local variable 명

    lower camel case이며, 상수로 지정되지 않습니다.


🎯 Programming Practices (프로그래밍 관례)

@Override는 필수

오버라이딩이 된 모든 경우 @Override는 필수로 기입합니다.
부모 클래스의 메소드를 재정의 하거나 인터페이스를 구현했을 때도 마찬가지입니다.
다만 부모 쪽에서 @Deprecated를 선언했을 경우 자식 쪽에서 @Override를 생략할 수 있다.

Caught exceptions (예외 처리)

모든 예외는 무시하지 말고 처리합니다.
만약 예외 처리하지 않을 거면 그 이유에 대해 명확히 주석을 달아주어야합니다.

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

Static members

반드시 클래스 명으로 접근해야합니다.

  • Foo aFoo = new Foo();
  • Foo.aStaticMethod(); // 좋은 예
  • aFoo.aStaticMethod(); // 나쁜 예 : 객체로 접근하고 있다.

Finalizers

finalizers는 객체가 소멸될 때 호출되기로 약속한 메서드라고 합니다.
밑에 내용을 이유로 finalizer를 사용하지 않는다고 합니다.

  • 언제 실행될 지 알 수 없습니다. 일반적으로 가비지 콜랙터에 의해서 호출이 되기 때문에 임의의 시점에 실행된다. 따라서 실행 시간이 중요한 코드는 finalizer에 두지 않습니다.
  • finalizer의 실행 주기는 전적으로 JVM 구현에 달려있어 JVM마다 다른 양상을 띕니다.
  • 자바 언어 명세에서 반드시 실행될 것인지도 보장되지 않습니다.
  • finalizer 수행 중 예외 발생 시 예외가 무시됩니다.
  • 엄청난 성능 저하를 일으킵니다. 객체 소멸이 약 430배 느려진다고 주장합니다.

대신 각 인스턴스에서 자신의 종료 여부를 유지 관리해야 합니다.
예를 들어, InputStream이나 OutputStream과 같은 클래스들은 close라는 메소드를 별도로 제공합니다.


🎯 Javadoc

Java 소스에 문서화를 하는 방법으로, 클래스나 메소드에 주석으로 기술한 내용을 javadoc 명령어나 또는 이를 이용한 빌드 툴 (maven의 pharse 등)을 사용하여 문서화 할 수 있습니다.
/*로 시작해 */로 끝나고, 특별한 키워드는 @keyword 형식으로 작성됩니다.

javadoc의 기본 형태는 다음과 같습니다.

/**
* JavaDoc 테스트 클래스입니다. 
* 
* @author Je 
*/ 
public class JavaDoc {
    /** 
    * 곱셈을 합니다. 
    * 
    * @param a 
    * @param b 
    * @return int 
    */ 
    public int multiply(int a, int b){ 
    	return a * b; 
    } 
}
  • /** 다음엔 공백이 옵니다.
  • 문단과 문단 사이에 공백 라인이 들어가고 @ 시작하기 전에도 공백 라인이 들어갑니다.
  • @param, @return, @throws, @deprecated 순으로 사용합니다. 설명은 무조건 기술해야하며 한 문장을 넘어가면 4개 이상의 스페이스로 들여쓰기합니다.
  • 최소한 public class의 public 혹은 protected 멤버에는 javadoc을 기술하는 것이 좋습니다.
  • 그리고 주석의 경우 모두 javadoc 타입으로 다는 것을 추천합니다.

🛴 마무리

이렇게 자바 코드 컨벤션에 대해 알아보았습니다!! 👏👏👏
규칙이 너무 많고... 한번에 이해하기에 쉽지많은 않네요 😂

익숙해질 때까지 여러번 읽어봐야겠습니다..ㅎㅎ

참고

post-custom-banner

0개의 댓글