코드스테이츠 BE 18일차 - Java 심화

coding infant·2022년 7월 18일

코드스테이츠BE

목록 보기
18/48

열거형(enum)

서로 연관된 상수들의 집합 (상수 : final. 변하지 않는 값)
보다 편리하게 선언
Switch에서 사용 가능
상수명 중복 피함. 타입에 대한 안정성 보장.

enum 열거형이름 {상수명1, 상수명2, 상수명3, ... }   // 상수명 대문자로 작성. 정수값 0부터 자동 할당

[java.lang.Enum]

String : name() - 열거 객체가 가지고 있는 문자열 리턴. 상수 이름
int : ordinal() - 열거 객체의 순번(0부터 시작)을 리턴
int : compareTo(비교값) - 주어진 매개값과 비교해서 순번 차이를 리턴
열거타입 : valueOf(StringName) - 주어진 문자열의 열거 객체를 리턴
열거배열 : values() - 모든 열거 객체들을 배열로 리턴

enum Level {
    LOW,
    MEDIUM,
    HIGH
}

public class EnumTest {
    public static void main(String[] args) {
        Level level = Level.MEDIUM;

        Level[] allLevels = Level.values();         // values() : 모든 상수 배열로 반환
        for(Level x : allLevels) {
            System.out.printf("%s=%d%n", x.name(), x.ordinal());            // LOW=0
                                                                            // MEDIUM=1
                                                                            // HIGH=2
        }
        Level findLevel = Level.valueOf("LOW");
        System.out.println(findLevel);                                      // LOW
        System.out.println(Level.LOW == Level.valueOf("LOW"));       // true
        switch(level) {                     // vlaueOf() : 열거형과 이름 일치하는 열거형 상수 반환, 불리언값으로 확인
            case LOW:
                System.out.println("낮은 레벨");
                break;
            case MEDIUM:
                System.out.println("중간 레벨");
                break;
            case HIGH:
                System.out.println("높은 레벨");
                break;

        }
    }
}

애터네이션

주석과 비슷
정보를 전달하는 대상이 누구인가? (주석은 사람에게, 애너테이션은 프로그램에게 정보 전달)
컴파일러에 문법 에러 체크하도록 정보 제공.
프로그램 빌드시 코드 자동 생성.
런타임에 특정 기능 실행하도록.
해당 테스트 수행하는 프로그램 외의 다른 프로그램에는 영향 미치지 않음

[애너테이션 종류]

표준 애너테이션 : 자바에서 기본적으로 제공
메타 애너테이션 : 애너테이션을 정의하는데 사용
사용자 정의 애너테이션 : 사용자가 직접 정의하는 애너테이션

[표준 애너테이션]

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

  • @Override
class Super {
    void run() {
}
class Sub extends Super {
    void rnu() {}     // 컴파일 에러 발생, 오타가 난 것을 발견할 수 있음
}
  • @Deprecated
class OldClass {
    @Deprecated
    int oldField;

    @Deprecated
    int getOldField() {return oldField;};
}
  • @SuppressWarnings

컴파일 경고메세지가 나타나지 않도록 함
@SuppressWarnings("all") : 모든 경고를 억제
@SuppressWarnings("deprecation") : Deprecation 메서드를 사용한 경우 나오는 경고 억제
@SuppressWarnings("fallthrough") : switch문에서 break 구문이 없을 때 경고 억제
@SuppressWarnings("finally") : finally 관련 경고 억제
@SuppressWarnings("null") : null 관련 경고 억제
@SuppressWarnings("unchecked") : 검증되지 않은 연산자 관련 경고 억제
@SuppressWarnings("unused") : 사용하지 않는 코드 관련 경고 억제
@SuppressWarnings({"deprecation", "unsued", "null"}) // 둘 이상의 경고 한번에 묵인 가능

  • @FunctionalInterface

함수형 인터페이스 선언할 때 컴파일러가 함수형 인터페이스의 선언 바르게 되었는지 확인. 하나의 추상 메서드만을 가져야 함.
코드 작성과정에서 실수를 방지하기 위한 확인용 애너테이션

@FunctionalInterface
public interface Runnable { 
    public abstract void run ();    // 하나의 추상 메서드
}

[메타 애너테이션]

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

  • @Target

애너테이션 적용할 대상 지정하는데 사용

(ANNOTATION_TYPE, CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE, TYPE_PARAMETER, TYPE_USE)

import static java.lang.annotation.ElementType.*;
// import문 이용하여 ElementType.TYPE 대신 TYPE과 같이 간단히 작성 가능

@Target({FIELD, TYPE, TYPE_USE})       // 적용대상이 FIELD, TYPE
public @interface CustomAnnotation { } // CustomAnnotation을 정의

// interface 사용시 @Target 사용해 사용자가 정의한 애너테이션 적용 범위 설정

@CustomAnnotation                      // 적용대상이 TYPE인 경우
class Main {
         @CustomAnnotation             // 적용대상이 FIELD인 경우
    int i;
}
  • @Documented

@Override와 @SuppressWarnigs 제외하고 모두 @Documented 적용

  • @ Inherited

하위 클래스가 애너테이션을 상속
상위 클래스에 @Inherited 붙이면 하위 클래스도 상위 클래스에 붙은 애너테이션들 동일하게 적용

-@ Repeatable
애너테이션 여러 번 붙일 수 있도록 허용한다

@interface Works {           // 여러 개의 ToDo 애너태이션을 담을 컨테이너 애너테이션 ToDos
    Work[] value();
}

@Repeatable(Works.class)    // ToDo 애너테이션 여러 번 반복해서 쓸 수 있게 한다. 컨테이너 애너테이션 지정
@interface Work{
    String value();
}

[사용자 정의 애너테이션]

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

애너테이션은 java.lang.annotation 인터페이스 상속받기에 다른 클래스나 인터페이스 상속받을 수 없다.

람다

메서드를 간략하게 식(expression)으로 표현하기 위한 것
익명 객체
함수형 인터페이스를 지원
Stream 사용에 활용

void sayhello(){
    System.out.println("HELLO!")
}
// 람다식으로 표현시
() -> System.out.println("HELLO!")

반환타입과 이름 생략 가능 (익명 함수)

int sum(int num1, int num2) {
    return num1 + num2;
}

// 람다식으로 표현시

(int num1, int num2) -> {     // 반환타입과 메서드명 제거, 코드 블럭 사이에 화살표 추가
    return num1 + num2        // 반환값 있는 메서드는 return 문과 문장 뒤 세미콜론 생략 가능
}
void example() {
    System.out.println(5);
}
// 람다식
() -> {System.out.println(5);}
int example2() {
    return 10;
}
// 람다식
() -> {return 10;}
void example3(String str) {
    System.out.println(str);
}
// 람다식
(String str) -> {System.out.println(str);}
int sum(int num1, int num2) {
    return num1 + num2;
}
// 람다식
(int num1, int num2) -> {
    num1 + num2
}
// 메서드 바디에 문장이 실행문 하나만 존재할 때 중괄호 생략 가능
(int num1, int num2) -> num1 + num2

// 매개변수 타입을 쉽게 유추할 수 있는 경우 매개변수의 타입 생략 가능
(num1, num2) -> num1 + num2

실행문 한 줄일 때 중괄호 생략 가능

매개변수 하나일 때는 소괄호 생략 가능

[함수형 인터페이스]

익명 클래스 : 객체의 선언과 생성을 동시에 하여 오직 하나의 객체를 생성하고, 단 한번만 사용되는 일회용 클래스. 생성과 선언 한번에 가능

하나의 추상 메서드만 선언. 람다식과 인터페이스의 메서드가 1:1로 매칭되어야

new Object() {
    int sum(int num1, int num2) {
        return num1 + num1;
    }
}
package Lamda;

public class LamdaExample1 {
    public static void main(String[] args) {
		   /* Object obj = new Object() {
            int sum(int num1, int num2) {
                return num1 + num1;
            }
        };
			*/
        ExampleFunction exampleFunction = (num1, num2) -> num1 + num2;
        System.out.println(exampleFunction.sum(10,15));                         // 25 출력
}

    @FunctionalInterface // 컴파일러가 인터페이스가 바르게 정의되었는 지 확인할 수 있도록
interface ExampleFunction {
        public abstract int sum(int num1, int num2);
    }
}

[매개변수와 리턴값 없는 람다식]

example = () -> {...};          // example.accept();

public class MyFunctionalInterfaceExample {
	public static void main(String[] args) throws Exception {
		MyFunctionalInterface example;
		example = () -> {
			String str = "첫 번째 메서드 호출!";
			System.out.println(str);
		};
		example.accept();

		example = () -> System.out.println("두 번째 메서드 호출!");
		//실행문이 하나라면 중괄호 { }는 생략 가능
		example.accept();
	}
}

// 출력값
첫 번째 메서드 호출!
두 번째 메서드 호출!

[매개변수 있는 람다식]

public class MyFunctionalInterfaceExample {
    public static void main(String[] args) throws Exception {
        MyFunctionalInterface example;
        example = (x) -> {
            int result = x * 5;
            System.out.println(result);
        };
        example.accept(2);

        example = (x) -> System.out.println(x * 5);
        example.accept(2);
    }
}

// 출력값
10
10

[리턴값이 있는 람다식]

public class MyFunctionalInterfaceExample {
    public static void main(String[] args) throws Exception {
        MyFunctionalInterface example;
        example = (x, y) -> {
            int result = x + y;
            return result;
        };
        int result1 = example.accept(2, 5);
        System.out.println(result1);
        

        example = (x, y) -> { return x + y; };
        int result2 = example.accept(2, 5);
        System.out.println(result2);
       

	      example = (x, y) ->  x + y;
				// 실행문이 한 줄인 경우, 중괄호 {}와 return문 생략가능
        int result3 = example.accept(2, 5);
        System.out.println(result3);
       

        example = (x, y) -> sum(x, y);
				// 실행문이 한 줄인 경우, 중괄호 {}와 return문 생략가능
        int result4 = example.accept(2, 5);
        System.out.println(result4);
 
    }

    public static int sum(int x, int y){
        return x + y;
    }
}

//출력값
7
7
7
7

accept() 매개변수 두 개 가짐

accept() 리턴 타입 있기 때문에 중괄호{} 에는 return문 있어야

참고사이트

https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html

[메서드 레퍼런스]

// 클래스 이름 :: 메서드이름
Math :: max;   // 메서드 참조

인터페이스 추상 메서드가 어떤 매개 변수를 가지고, 리턴 타입 무엇인가에 따라 달라짐

클래스 :: 메서드     // 정적 메서드 참조시
참조변수 :: 메서드   // 인스턴스 메서드 참조시

import java.util.function.IntBinaryOperator;

public class MethodReferences {
  public static void main(String[] args) throws Exception {
    IntBinaryOperator operator;

    /*정적 메서드
		클래스이름::메서드이름
		*/
    operator = Calculator::staticMethod;
    System.out.println("정적메서드 결과 : " + operator.applyAsInt(3, 5));

    /*인스턴스 메서드
		인스턴스명::메서드명
		*/
		
    Calculator calculator = new Calculator();
    operator = calculator::instanceMethod;
    System.out.println("인스턴스 메서드 결과 : "+ operator.applyAsInt(3, 5));
  }
}
/*
정적메서드 결과 : 8
인스턴스 메서드 결과 : 15
*/

[생성자 참조]

클래스 :: new

생성자가 오버로딩 되어 여러개 있는 경우 함수형 인터페이스의 추상 메서드와 동일한 매개 변수 타입과 개수를 가지고 있는 생성자를 찾아 실행

//Member.java
public class Member {
  private String name;
  private String id;

  public Member() {
    System.out.println("Member() 실행");
  }

  public Member(String id) {
    System.out.println("Member(String id) 실행");
    this.id = id;
  }

  public Member(String name, String id) {
    System.out.println("Member(String name, String id) 실행");
    this.id = id;
    this.name = name;
  }

  public String getName() {
    return name;
  }

public String getId() {
    return id;
  }
}
import java.util.function.BiFunction;
import java.util.function.Function;

public class ConstructorRef {
  public static void main(String[] args) throws Exception {
    Function<String, Member> function1 = Member::new;
    Member member1 = function1.apply("kimcoding");

    BiFunction<String, String, Member> function2 = Member::new;
    Member member2 = function2.apply("kimcoding", "김코딩");
  }
}

/*
Member(String id) 실행
Member(String name, String id) 실행
*/

[메서드 이용해서 객체 생성]

//Member.java
public class Member {
  private String name;
  private String id;

  public Member() {
    System.out.println("Member() 실행");
  }

  public Member(String id) {
    System.out.println("Member(String id) 실행");
    this.id = id;
  }

  public Member(String name, String id) {
    System.out.println("Member(String name, String id) 실행");
    this.id = id;
    this.name = name;
  }

  public String getName() {
    return name;
  }

public String getId() {
    return id;
  }
}

생성자 참조는 두 방법 모두 동일하지만, 실행되는 Member 생성자가 다름

스트림

다양한 데이터 소스(컬렉션/배열)를 표준화하여 다루는 방법
통합된 방식으로 데이터 핸들링
스트림 만들기 / 중간연산 / 최종 연산 세 단계로 구성 (최종 연산은 단 한 번 수행)
선언형으로 데이터소스 처리

[스트림 특징]

선언형 프로그래밍 방식
원본을 변경하지 않음(read-only)
일회용(one-time only)
지연된 연산 (filter 사용하여 여러 연산 가능하게)
병렬 스트림 사용 가능(내부 반복자 사용)

[선언형으로 데이터 소스 처리]

import java.util.List;

public class ImperativeProgrammingExample {
    public static void main(String[] args){
        // List에 있는 숫자들 중에서 4보다 큰 짝수의 합계 구하기
        List<Integer> numbers = List.of(1, 3, 6, 7, 8, 11);
        int sum = 0;

        for(int number : numbers){
            if(number > 4 && (number % 2 == 0)){
                sum += number;
            }
        }

        System.out.println("# 명령형 프로그래밍 : " + sum);
    }
}

// Stream으로 변경시
import java.util.List;

public class DeclarativeProgramingExample {
    public static void main(String[] args){
        // List에 있는 숫자들 중에서 4보다 큰 짝수의 합계 구하기
        List<Integer> numbers = List.of(1, 3, 6, 7, 8, 11);

        int sum =
                numbers.stream()
                        .filter(number -> number > 4 && (number % 2 == 0))
                        .mapToInt(number -> number)
                        .sum();

        System.out.println("# 선언형 프로그래밍: " + sum);
    }
}

stream 사용시 단순하고 가독성 높음

[람다식으로 요소 처리 코드 제공]

[stream 생성, 중간 연산, 최종 연산]

스트림 생성 steam()

배열의 원소를 소스로 하는 스트림 생성 Stream.of("".""); // 가변인자

range() 함수 사용 for문 대체 IntStream.range(,);

중간연산 : 여러번 가능

최종연산 : 한 번만 가능

Stream
.of(1,2,3,4) 데이터 소스
.filter(n-> 중간 연산
. 최종 연산
참고 사이트

https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html

0개의 댓글