ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [TIL #16-1][JAVA]Effective : enum, annotation
    CodeStates_Backend/TIL (Today I Learned) 2022. 6. 3. 20:18

    코드스테이츠 백엔드 부트캠프 39기 25~26일차, 05/19~20

     

     

     

    JAVA Effective

    자바에서 효율적인 프로그래밍을 위한 다양한 심화 기술들을 Effective 라고 한다. 몰라도 구현은 가능하지만, 알면 전문가가 되는 느낌..? (근데 결국 알아야 될 듯함ㅋ...ㅋ)

    [권장도서] Effective JAVA (3년차 때 권장)

     

    enum

    enumerate 의 줄임말로 '열거하다' 의 의미이다. Enum 클래스로 정의되어 있다. 마치 데이터 타입처럼, enum 타입(=열거체)으로 사용한다. 서로 연관된 상수들을 열거하여 집합을 만든다. 다음과 같이 선언한다. 

    enum 열거형이름 { 상수명1, 상수명2, 상수명3, ...}

    블록 내의 각각의 상수들은 '열거 상수'라고 부른다. 위와 같이 별다른 초기화가 없이 정의된 상수들의 값은, 첫 번째부터 0, 1, 2, ... 이런식으로 0부터 1씩 증가하는 값으로 자동초기화 된다. 만약 다른 값으로 초기화하고 싶다면 생성자를 이용하는 방식으로 가능하다.

     

    enum도 클래스이므로 객체로 생성하여 사용한다. 이 때 객체를 '열거 객체'라고 한다. enum 클래스의 메소드들(=열거 객체가 사용가능한)은 아래와 같다.

    리턴 타입 메소드 설명
    String name() 열거 객체가 가지고 있는 문자열을 리턴하며, 리턴되는 문자열은 열거타입을 정의할 때 사용한 상수 이름과 동일합니다.
    int ordinal() 열거 객체의 순번(0부터 시작)을 리턴합니다.
    int compareTo(비교값) 주어진 매개값과 비교해서 순번 차이를 리턴합니다.
    열거 타입 valueOf(String name) 주어진 문자열의 열거 객체를 리턴합니다.
    열거 배열 values() 모든 열거 객체들을 배열로 리턴합니다.

     

    enum의 사용 예제는 다음과 같다.

    enum Level {
      LOW,
      MEDIUM,
      HIGH
    }
    
    public class Main {
      public static void main(String[] args) {
        Level level = Level.MEDIUM;
    
        switch(level) {
          case LOW:
            System.out.println("Low level");
            break;
          case MEDIUM:
             System.out.println("Medium level");
            break;
          case HIGH:
            System.out.println("High level");
            break;
        }
      }
    }

    switch의 조건으로는 'char, byte, short, int, Character, Byte, Short, Integer, String 또는 enum'타입만 가능하므로, switch 문에서 유용하게 사용할 수 있다.

     

    🧲 enum에 대해 아래 링크를 통해 학습하는 것을 매우 매우 권장한다.

    https://www.nextree.co.kr/p11686/    -> enum 의 뿌리부터 상세한 내용(권장)

     

    Java: enum의 뿌리를 찾아서...

    이번 글에서는 자바 1.5버전부터 새롭게 추가된 열거형 상수인 enum(enumeration)에 대해 알아보겠습니다. 열거형은 서로 연관된 상수들의 집합입니다. 이번 글은 enum 정의와 enum 사용방법, 그리고 enum

    www.nextree.co.kr

     

     

     

    Annotation

    사전적의미로도 '주석'이며 실제 주석과 같은 기능이다. 단, "누구에게 정보를 제공하는가?" 에서 주석과 차이점이 있다.

    • 주석은 소스 코드를 읽는 사람에게 정보를 제공한다.
    • 애너테이션(Annotation)은 프로그램에게 정보를 제공한다.

     

    애너테이션은 코드 사이에 주석처럼 프로그래밍 언어에 영향을 미치지 않으면서 다른 프로그램에게 유용한 정보를 제공하는 역할을 한다. 구체적으로 살펴보면 아래와 같다.

    • 컴파일러에게 문법 에러를 체크하도록 정보를 제공한다.
    • 프로그램을 빌드나 배치할 때 코드를 자동으로 생성할 수 있도록 정보를 제공한다.
    • 런타임에 특정 기능을 실행하도록 정보를 제공한다.

     

    🧲 애너테이션 종류

    1️⃣ 표준 애너테이션 : 자바에서 기본적으로 제공하는 애너테이션.

     

    @Override 컴파일러에게 메서드를 오버라이딩하는 것이라고 알림
    @Deprecated 앞으로 사용하지 않을 대상을 알릴 때 사용
    @FunctionalInterface 함수형 인터페이스라는 것을 알
    @SuppressWarning 컴파일러가 경고메세지를 나타내지 않음

    👉 @Override는 메서드 앞에만 붙일 수 있는 애너테이션으로, 선언한 메서드가 상위 클래스의 메서드를 오버라이딩하는 메서드라는 것을 컴파일러에게 알려준다. 만약 상위 클래스(또는 인터페이스)에서 @Override가 붙어있는 메서드명과 동일한 이름의 메서드를 찾을 수 없다면 컴파일러가 컴파일 에러를 발생시킨다. 즉, @Override는 컴파일러에게 “컴파일러야, 이 메서드는 상위 클래스의 메서드를 오버라이딩하는 메서드인데, 만약에 내가 실수해서 오버라이딩이 잘 안되면 에러를 발생시켜서 나에게 알려줄래?”라고 부탁하는 것과 같다.

     

    👉 @Deprecated는 새로운 버전의 JDK에서 어떤 기능이 추가되는 등의 이유로, 더 이상 사용하지 않는 필드나 메서드가 생겼을 때, 그러한 필드 및 메서드에 사용하여 해당 메서드 및 필드를 더 이상 사용하지 않음을 표시한다. 즉, 기존 메서드를 하위 버전 호환성 문제로 삭제하기 곤란해 남겨두지만, 사용하는 것을 권장하지 않을 때 @Deprecated를 사용한다. @Deprecated가 붙은 대상을 사용하는 코드를 작성하면 컴파일할 때 warning 메시지가 발생한다.

     

    👉 @SuppressWarnings는 선언한 곳의 컴파일 경고를 나타나지 않도록 한다. 경우에 따라서 경고가 발생할 것을 알면서도 묵인해야 할 때 사용한다. 아래와 같이 @SuppressWarnings 뒤에 괄호를 붙이고 그 안에 억제하고자 하는 경고메세지를 지정해줄 수 있다.

    @SuppressWarings(”all”) 모든 경고를 억제
    @SuppressWarings(”deprecation”) Deprecated 메서드를 사용한 경우 나오는 경고 억제
    @SuppressWarings(”fallthrough”) switch문에서 break 구문이 없을 때 경고 억제
    @SuppressWarings(”finally”) finally 관련 경고 억제
    @SuppressWarings(”null”) null 관련 경고 억제
    @SuppressWarings(”uncheched”) 검증되지 않은 연산자 관련 경고 억제
    @SuppressWarings(”unused”) 사용하지 않는 코드 관련 경고 억제

    👉 @FunctionalInterface함수형 인터페이스를 선언할 때, 올바르게 선언했는지 확인해준다. @FunctionalInterface 애너테이션을 붙이지 않아도 함수형 인터페이스를 선언할 수는 있지만, 코드 작성과정에서 실수를 방지하기 위한 확인용 애너테이션이다. 함수형 인터페이스는 하나의 추상메서드만 있어야 하는데 추상메서드가 2개 이상인 경우 에러를 발생시킨다.

     


    2️⃣ 메타 애너테이션 : 애너테이션에 붙이는 애너테이션으로, 애너테이션을 정의하는 데에 사용된다.

     

    @Target 애너테이션을 정의할 때 적용 대상을 지정하는데 사용한다.
    @Documented 애너테이션 정보를 javadoc으로 작성된 문서에 포함시킨다.
    @Inherited 애너테이션이 하위 클래스에 상속되도록 한다.
    @Retention 애너테이션이 유지되는 기간을 정하는데 사용한다.
    @Repeatable 애너테이션을 반복해서 적용할 수 있게 한다.

    👉 @Target 애너테이션으로 애너테이션의 적용 범위를 설정할 수 있다. 아래 표의 값들을 이용해 설정할 수 있으며, 값들은 열거형으로 java.lang.annotation.ElementType에 정의되어 있다.

     

    대상 타입 적용 범위
    ANNOTATION_TYPE 애너테이션
    CONSTRUCTOR 생성자
    FIELD 필드(멤버변수, 열거형 상수)
    LOCAL_VARIABLE 지역변수
    METHOD 메서드
    PACKAGE 패키지
    PARAMETER 매개변수
    TYPE 타입(클래스, 인터페이스, 열거형)
    TYPE_PARAMETER 타입 매개변수
    TYPE_USE 타입이 사용되는 모든 대상

    아래는 @Target의 사용 예제 이다.

    import static java.lang.annotation.ElementType.*; 
    //import문을 이용하여 ElementType.TYPE 대신 TYPE과 같이 간단히 작성할 수 있습니다.
    
    @Target({FIELD, TYPE, TYPE_USE})	// 적용대상이 FIELD, TYPE
    public @interface CustomAnnotation { }	// CustomAnnotation을 정의
    
    @CustomAnnotation	// 적용대상이 TYPE인 경우
    class Main {
        @CustomAnnotation	// 적용대상이 FIELD인 경우
        int i;
    }

     

    👉 @Documented는 애너테이션에 대한 정보가 javadoc 문서에 표기된다.

    javadoc 이란? - Oracle 공식 문서에서 확인
    자바 소스파일에 대한 API documentation을 HTML 페이지로 생성하는 명령어이다. 

     

    👉 @Inherited는 하위 클래스가 애너테이션도 상속받도록 한다. @Inherited를 상위 클래스에 작성하면, 하위 클래스도 상위 클래스의 애너테이션들이 적용된다.

    @Inherited // @SuperAnnotation이 하위 클래까지 영향 미치게 함
    @interface SuperAnnotation{ }
    
    @SuperAnnotation
    class Super { }
    
    class Sub extends Super{ } // Sub에 애너테이션이 붙은 것으로 인식

     

    👉@Retention은 애너테이션이 유지되는 기간을 지정한다. '유지 정책(RetentionPolicy)' 속성을 이용하여 지정한다.

     

    유지 정책 설명
    SOURCE .java 소스 파일까지는 애노테이션이 존재, 컴파일 되어 클래스 파일이 되면 사라짐
    CLASS .class 파일까지는 애노테이션이 존재, 런타임에서 사라짐
    RUNTIME 런타임 실행시까지 애노테이션이 남아있음
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.SOURCE) 
    //오버라이딩이 제대로 되었는지 컴파일러가 확인하는 용도 
    //클래스 파일에 남길 필요 없이 컴파일시에만 확인하고 사라짐
    public @interface Override(){ }

     

    👉@Repeatable애너테이션이 붙은 애너테이션은 여러 번 작성이 가능하다.

    @Repeatable(ToDos.class) // ToDo 애너테이션을 여러 번 반복해서 쓸 수 있게 한다.  
    @interface ToDo{  
        String value();  
    }
    @ToDo("update test codes.")  
    @ToDo("override test methods")  
    class Main{  
    
    }

    일반적인 애너테이션과 달리 같은 이름의 애너테이션이 여러번 적용될 수 있기 때문에, 이 애너테이션들을 하나로 묶어주는 애너테이션도 별도로 작성해야 한다.

    @interface ToDos {  // 여러개의 ToDo애너테이션을 담을 컨테이너 애너테이션 ToDos
        ToDo[] value(); // ToDo애너테이션 배열 타입의 요소를 선언. 이름이 반드시 value여야 함  
    }

     


    3️⃣ 사용자 정의 애너테이션 : 사용자가 직접 정의하는 애너테이션

     

    사용자 정의 애너테이션을 정의하는 방법은 인터페이스를 정의하는 것과 비슷하다. 애너테이션은 java.lang.annotation 인터페이스를 상속받으며 다른 클래스나 인터페이스를 상속 받을 수 없다.

    @interface 애너테이션명 { // 인터페이스 앞에 @기호만 붙이면 애너테이션을 정의할 수 있습니다. 
    	타입 요소명(); // 애너테이션 요소를 선언
    }

    아래는 사용자 정의 애너테이션의 예제이다. 백엔드 프레임워크를 지정해주는 역할의 애너테이션을 정의한다.

    import java.lang.annotation.*;
    
    @Target(ElementType.FIELD)//애너테이션이 적용 가능한 대상을 FIELD로 정해줍니다.
    @Retention(RetentionPolicy.RUNTIME)//코드 실행시 까지 애너테이션이 유지되게 정해줍니다.
    @Documented //애너테이션 정보를 javadoc으로 작성된 문서에 포함시킨다.
    public @interface BackendFramework { //백엔드 프레임워크를 지정해주는 애너테이션을 작성합니다.
        enum Frameworks {SPRING, DJANGO, EXPRESS}
    
        Frameworks backendFramework() default Frameworks.DJANGO;
    }

    아래는 위에서 작성한 사용자 정의 애너테이션을 사용하는 예제이다.

    public class KimCoding {
    	@BackendFramework(backendFramework = BackendFramework.Frameworks.SPRING)
    	private String KimCodingBackend;
    }

     


    📌 추가 학습 자료
    https://www.nextree.co.kr/p11686/    -> enum 의 뿌리부터 상세한 내용(권장)
    📌 참고 및 출처
    https://seeminglyjs.tistory.com/257

     

Designed by Tistory.