[JAVA] Emum, Annotation, Lambda

zirryo·2022년 7월 18일
0

⚡️ STUDY

목록 보기
9/15
post-thumbnail
week 4 / 22.07.18

Enumerated type

💿 열거형

서로 연관된 상수들의 집합
상수란 변하지 않는 값을 의미하며, final 키워드를 통해 선언가능.
열거형을 사용하면 아래의 3가지 문제에 대해 자유로움.
⠀⠀⠀⠀

열거형을 사용하지 않고 상수를 선언하는 경우

  1. 상수명 중복 : public static final int 를 이용하여 정수 값을 할당할 때, 같은 상수명을 사용할 경우 컴파일 에러발생.
  2. 타입 안정성 문제 : 같은 상수명을 사용하는 상수를 인터페이스를 이용하여 분류해도, == 연산자를 사용하면 의미적으로 다른 개념을 가지는 경우에도 에러가 발생하지 않음.
  3. 사용자 정의 타입 : 각각을 별도의 객체로 생성하면, 위의 두 문제를 해결할 수 있으나 코드가 길어지고, switch문에서 사용할 수 없음.
    • User Defined datatypes
      : 클래스와 인터페이스와 같이 유저가 직접 타입을 설정한 것을 말함.
    • Primitive datatypes
      : 위와 상반되는 개념으로 자바에서 제공하는 기본 타입
      byte, short, int, long, float, double, char, boolean
    • switch문의 조건에서 사용 가능한 타입
      : char, byte, short, int, Character, Byte, Short, Integer, String, enum

⠀⠀⠀⠀

  • enum을 활용한 상수 정의
    • 상수는 대소문자 모두 가능하나, 관례적으로 대문자 작성.
    • 따로 값을 지정하지 않아도 순서대로 0, 1, 2, ... 의 정수값이 할당되어 각각의 상수값을 지칭함.
    • 아래의 코드에서 Meal 열거형은 3개의 열거 객체를 포함하고 있음.
    • 열거형이름.상수명 을 통해서 열거형으로 선언된 상수에 접근 가능.
      enum 열거형이름 { 상수명1, 상수명2, 상수형3, ...}
       enum Meal { BREAKFAST, LUNCH, DINNER }
       ⠀⠀⠀⠀
       enum Meal { BREAKFAST,  // 정수값 0 할당
       LUNCH,                  // 정수값 1 할당
       DINNER                  // 정수값 2 할당
       }
  • enum의 활용
    enum Meal {
      BREAKFAST, // 0
      LUNCH, // 1
      DINNER // 2
    }
    ⠀⠀⠀
    public class Main {
      public static void main(String[] args) {
        Meal meal = Meal.DINNER;
    ⠀⠀⠀
        switch(meal) {
          case BREAKFAST:
            System.out.println("아침");
            break;
          case LUNCH:
             System.out.println("점심");
            break;
          case DINNER:
            System.out.println("저녁");
            break;
        }
      }
    }
    //  출력  
    //  DINNER
  • 열거형의 메서드
    열거형의 조상 java.lang.Enum 에 정의되어 있음.
    리턴타입메소드(매개변수)기능
    Stringname()열거객체가 가지고 있는 문자열 리턴
    intordianl()열거객체의 순번 리턴
    intcompareTo(비교값)매개값과의 순번 차이 리턴
    열거타입valueOf(String name)문자열의 열거객체 리턴
    열거배열values()모든 열거 객체를 배열로 리턴
    enum Meal { BREAKFAST, LUNCH, DINNER }
      ⠀⠀⠀
    public class EnumTest {
        public static void main(String[] args) {
            Meal meal = Meal.LUNCH;
    		Meal[] allMeal = Meal.values();  // 모든 열거 객체 배열로 리턴
            for(Meal m : allMeal) {
                System.out.printf("%s=%d%n", m.name(), m.ordinal()); 
            } // 열거 객체가 가지고 있는 문자열 리턴 + 순번 리턴
    ⠀⠀⠀
            System.out.println(meal.compareTo(Meal.DINNER));
            Meal findMeal = Meal.valueOf("DINNER"); 
            System.out.println(findMeal); 
            System.out.println(meal == Meal.valueOf("LUNCH"));
        }  // 문자열의 열거객체 리턴
    }
     // 출력
     // BREAKFAST=0
     // LUNCH=1
     // DINNER=2
     // -1 ( 2 - 3 = -1)
     // DINNER
     // true
  • 🔗 참고
    ⠀⠀⠀
    ⠀⠀⠀

Annotation

📀 애너테이션

다른 프로그램에게 유용한 정보를 제공하기 위해 만들어진 수단

에너테이션의 역할

  • 컴파일러 : 문법 에러 체크 정보 제공
  • 프로그램 빌드 : 코드를 자동 생성할 수 있도록 정보 제공
  • 런타임 : 특정 기능 실행하도록 정보 제공
    ⠀⠀⠀

표준 애너테이션 ⠀자바에서 기본적으로 제공

  • @Override
    • 메서드 앞에만 붙일 수 있는 애너테이션.
    • 선언한 메서드가 상위 클래스의 메서드를 오버라이딩하는 메서드라는 것을 컴파일러에게 알려주는 역할
    • 개발자의 오버라이딩 실수를 바로 잡아주는 역할
  • @Deprecated
    • 애너테이션이 붙은 대상이 새로운 것으로 대체되었으니 기존의 것을 사용하지 않을 것을 권장할 때 사용
    • 즉, 기존 메서드를 하위 버전 호환성 문제로 삭제하기 곤란해서 남겨두어야 하지만 더 이상 사용하지 않는 것을 권장하는 경우에 사용.
  • @SuppressWarnings
    • 컴파일 경고 메세지가 나타나지 않도록 함.
    • 경고가 발생할 것이 예상되는 상황에 이를 무시하기 위해 사용.
    • @SuppressWarnings 뒤에 괄호를 붙이고 억제하고 싶은 경고메세지를 지정할 수 있음.
      // 경고 메세지의 종류 @SuppressWarings(”message”)
      ”all”	         모든 경고를 억제
      ”deprecation”	 Deprecated 메서드를 사용한 경우 나오는 경고 억제
      ”fallthrough”	 switch문에서 break 구문이 없을 때 경고 억제
      ”finallyfinally 관련 경고 억제
      ”nullnull 관련 경고 억제
      ”unchecked”	     검증되지 않은 연산자 관련 경고 억제
      ”unused”	     사용하지 않는 코드 관련 경고 억제
    • 괄호 안에 배열형으로 작성하여 여러 경고를 묵인할 수도 있음.
      @SuppressWarnings({"unused", "null"})
  • @FunctionalInterface
    • 컴파일러가 함수형 인터페이스의 선언이 바르게 선언되었는 지 확인하도록 함.
    • 바르게 선언되지 않은 경우 에러 발생.
      @FunctionalInterface
      public interface Runnable {
      	public abstract void run (); 
      }              // 하나의 추상 메서드
    • 제약 조건 : 단 하나의 추상메서드 만을 가짐.
      ⠀⠀⠀

메타 애너테이션 ⠀에너테이션을 정의하는 데 사용. 애너테이션에 붙임.

  • @Target
    • 애너테이션을 적용할 대상을 지정하는 데 사용.
    • java.lang.annotation.ElementType 에 정의되어 있음.
    • 🔗 대상 타입 알아 보기
  • @Documented
    • 애너테이션에 대한 정보가 javadoc으로 작성한 문서에 포함되도록 하는 애너테이션 설정.
    • @Override@SuppressWarnings를 제외하고 모두 @Documented 적용되어 있음.
      @Documented
       @Target(ElementType.Type)
       public @interface CustomAnnotation { }
  • @Inherited
    • 하위 클래스가 애네테이션을 상속받도록 함.
    • @Inherited 애너테이션을 상위 클래스에 붙이면, 하위 클래스에도 상위 클래스의 애너테이션이 동일하게 적용됨.
      @Inherited // @SuperAnnotation이 하위 클래스까지 적용
       @interface SuperAnnotation{ }@SuperAnnotation
       class Super { }class Sub extends Super{ } // Sub에 애너테이션 적용
  • @Retention
    • 애너테이션의 지속 시간 결정.
    • 3가지 유지 정책(유지 기간)을 가짐.
      유지 정책설명
      SOURCE소스파일에 존재, 클래스 파일에는 존재 X
      CLASS클래스 파일에 존재, 실행시 사용 X, 기본값
      RUNTIME클래스 파일에 존재, 실행시 사용 O
      @Target(ElementType.METHOD)
       @Retention(RetentionPolicy.SOURCE) 
       //오버라이딩이 제대로 되었는지 컴파일러가 확인하는 용도 
       //클래스 파일에 남길 필요 없이 컴파일시에만 확인하고 사라짐
       public @interface Override(){ }
  • @Repeatable
    • 애너테이션을 여러 번 붙일 수 있도록 허용.
    • 일반적인 애너테이션과 달리 같은 이름의 애너테이션이 여러번 적용될 수 있기 때문에, 애너테이션을 하나로 묶어주는 애너테이션의 별도 작성 필요.

사용자 정의 애너테이션 ⠀사용자가 직접 에너테이션을 정의해서 사용.

  • 사용자 정의 에너테이션 생성
    • 인터페이스를 정의하는 방식과 비슷함.
    • java.lang.annotation 인터페이스를 상속받기 때문에 다른 클래스나 인터페이스를 상속 받을 수 없음.
      @interface 애너테이션명 { // 인터페이스 앞에 @기호만 붙여 애너테이션을 정의
      	타입 요소명(); // 애너테이션 요소를 선언
      }

Lambda

💿 람다

함수형 프로그래밍을 지원하는 자바의 문법 요소
식(expression)을 표현한 것으로, 코드를 매우 간결하고 명확하게 표현함.

람다식의 기본 문법

  • 기본적으로 반환 타입과 이름을 생략할 수 있음.
  • 이로 인해 이름이 없는 함수, 익명 함수(Anonymous function) 이라고 부르기도 함.
  • 람다식을 만드는 과정
    // 일반적인 메서드의 형태
    int sum(int num1, int num2) {
    	return num1 + num2;
    }// 반환타입과 메서드명 제거 + 화살표 추가
    (int num1, int num2) -> { 
    	return num1 + num2;
    }// 반환값이 있는 경우에는 return과 세미콜론 생략 가능
    (int num1, int num2) -> {
    	num1 + num2
    }
  • 추가적인 축약이 가능한 경우
    // (1) 실행문이 하나인 경우는 중괄호 생략 가능
    (int num1, int num2) -> num1 + num2
    ⠀⠀
    // (2) 매개변수 타입을 쉽게 유추할 수 있는 경우, 매개변수 타입 생략 가능
    (num1, num2) -> num1 + num2

함수형 인터페이스
람다식은 객체이다. 이름이 없는 익명 클래스의 형태.

  • 익명클래스
    : 객체의 선언과 생선을 동시에 하여 오직 하나의 객체를 생성하고, 단 1회만 사용됨.
    • 아래의 코드에서 Object 클래스에는 sum 메서드가 없기 때문에, 참조변수에 담아도 메서드를 사용할 수 없음.
      public class LamdaExample1 {
          public static void main(String[] args) {
      		   Object obj = new Object() {
                  int sum(int num1, int num2) {
                      return num1 + num1;
                  }
              };
      } // 람다식 Object obj = (num1, num2) -> num1 + num2 로 대체 가능
    • 위와 같은 문제를 해결하기 위해 함수형 인터페이스 사용.
      ⠀⠀
  • 함수형 인터페이스의 특징
    • 기존의 인터페이스 문법을 활용하여 람다식을 다루는 것이다.
    • 람다식도 하나의 객체이기 때문에 인터페이스에 정의된 추상메서드를 구현할 수 있기 때문.
    • 단 하나의 추상 메서드만이 선언될 수 있다. 람다식과 인터페이스 메서드가 1:1로 매칭되어야 하기 때문.
      public class Main {
          public static void main(String[] args) {
      		LambdaEx l = (num1, num2) -> num1 + num2
      ⠀⠀		System.out.println(l.sum(10,15))
      }
      @FunctionalInterface // 함수형 인터페이스가 바르게 정의되었는 지 확인하는 애너테이션
      interface LambdaEx {
      		public abstract int sum(int num1, int num2);
      }
  • 매개변수와 리턴값이 없는 람다식
    @FunctionalInterface
    public interface L1 {
        public void play();
    }
    // 아래와 같은 형태로 람다식을 작성해야 함.
    L1 example = () -> { ... };
    // example.play(); 로 play() 호출.
    public class Main {
    	public static void main(String[] args) throws Exception {
    		L1 example;
    		example = () -> {
    			String str = "첫 번째 메서드";
    			System.out.println(str);
    		};
    		example.play();
    ⠀⠀
    		example = () -> System.out.println("두 번째 메서드");
    		//실행문이 하나라면 중괄호 { }는 생략 가능
    		example.play();
    	}
    }
    // 출력값
    첫 번째 메서드
    두 번째 메서드
  • 매개변수가 있고, 리턴값이 없는 람다식
    @FunctionalInterface
    public interface L2 {
        public void play(int x);
    }
    public class Main {
        public static void main(String[] args) throws Exception {
            L2 example;
            example = (x) -> {
                int result = x + 3;
                System.out.println(result);
            };
            example.play(2);
    ⠀⠀
            example = (x) -> System.out.println(x * 5);
            example.play(3);
        }
    }
    // 출력값
    5
    15
  • 리턴값이 있는 람다식
    @FunctionalInterface
    public interface L3 {
        public play(int x, int y);
    }
    public class Main {
        public static void main(String[] args) throws Exception {
            L3 example;
            example = (x, y) -> {
                int result = x + y;
                return result;
            };
            int result1 = example.play(6, 3);
            System.out.println(result1);  // 9
    ⠀⠀        
    		example = (x, y) -> { return x - y; };
            int result2 = example.play(7, 4);
            System.out.println(result2);  // 3
     ⠀⠀       
            example = (x, y) ->  x * y;
    		// 실행문이 한 줄인 경우, 중괄호와 return문 생략
            int result3 = example.play(9, 1);
            System.out.println(result3);  // 9
  • 자바에서 기본적으로 제공하는 함수형 메서드
    🔗 API DOC
    🔗 더 알아보기
    ⠀⠀

메서드 레퍼런스
불필요한 매개변수를 제거할 때 사용.

  • 메서드 참조 ::

    // 단순히 메서드를 참조하는 경우, 람다식을 메서드 참조로 대치
    // 정적(static) 메서드 참조
    클래스명 :: 메서드
    // 인스턴스 메서드 참조 ( 객체 생성 후 참조 가능)
    참조 변수 :: 메서드
  • 생성자 참조 ::

    // 단순히 객체를 생성하고 리턴하는 경우, 람다식을 생성자 참조로 대치
    (a,b) -> {return new 클래스(a,b);};
    // 생성자 참조
    클래스명 :: new
    • 생성자가 오버로딩 되어있을 경우, 함수형 인터페이스의 추상메서드와 동일한 매개 변수 타입과 개수를 가지고 있는 생성자 실행.
    • 생성자가 존재하지 않을 경우, 컴파일 오류 발생.

0개의 댓글