함수형 인터페이스
- 추상메서드가 하나만 있는 경우, 두개 이상은 불가능(다른형태의 메서드가 여러개 있는건 상관 없음 오로지 추상메서드만 한개 있어야함), @FuncionalInterface 로 선언하여 사용
Java8 에서 인터페이스 - static 메서드 정의 가능, default 메서드 정의 가능
함수형 인터페이스는 순수한 함수여야 한다.
- 항상 같은 값에는 같은 결과값을 리턴해야한다. (=멱등해야한다.),
- 외부에 있는 값을 변경하면 안된다.
자바에서 제공하는 주요 함수형 인터페이스 종류
Function<T, R>
- T 타입을 받아서 R 타입을 리턴하는 힘수 인터페이스
- 함수 조합용 메소드
- andThen -> A.andThen(B) B 실행 결과값을 가지고 A를 수행
- compose -> Acompose(B) A 실행 결과값을 가지고 B를 수행
BiFunction<T, U, R>
- 두 개의 값(T, U)를 받아서 R 타입을 리턴하는 함수 인터페이스
- R apply(T t, U u)
Consumer<T>
- T 타입을 받아서 아무값도 리턴하지 않는 함수 인터페이스
- Void Accept(T t)
- 함수 조합용 메소드
- andThen
Supplier<T>
- T 타입의 값을 제공하는 함수 인터페이스
- T get()
Predicate<T>
- T 타입을 받아서 boolean을 리턴하는 함수 인터페이스
- boolean test(T t)
- 함수 조합용 메소드
- And -> 함수들의 결과를 and 연산하여 결과를 리턴함
- Or -> 함수들의 결과를 or 연산하여 결과를 리턴함
- Negate -> 결과를 not 연산하여 결과를 리턴함
UnaryOperator<T>
- Function<T, R>의 특수한 형태로, 입력값 하나를 받아서 동일한 타입을 리턴하는 함수 인터페이스
BinaryOperator<T>
- BiFunction<T, U, R>의 특수한 형태로, 동일한 타입의 입력값 두개를 받아 리턴하는 함수 인터페이스
람다 표현식
- (인자리스트) -> {바디} 형태로 구현 할 수 있다.
인자리스트
- 인자가 없을 경우 (), 한개일 경우(arg) 또는 arg, 여러개일 경우 (arg1, arg2, arg2, …)
- 인자의 타입은 생략가능하다.
바디
- 여러 줄인 경우에 {} 로 묶어서 사용한다.
- 한 줄인 경우에는 {}를 생략해도 된다. return도 생략할 수 있다.
메소드 레퍼런스
- Lambda 표현식을 좀 더 간결하게 표현하는 방식
인터페이스 기본 메서드(Default Methods)
- 인터페이스에 메서드 선언이 아니라 구현체를 제공하는 방법
- 해당 인터페이스를 구현한 클래스를 깨트리지 않고 새 기능을 추가 할 수 있다.
- 기본 메서드는 구현체가 모르게 추가 된 기능인 만큼 리스크가 있다.(구현이 안 될 수 있다.)
- 컴파일 에러는 아니지만 구현체에 따라 런타임 에러가 발생할 수 있다.
- 반드시 문서화 하는 것이 중요하다(@implSpec 자바독 태그 사용)
- Object가 제공하는 기능(equals, hasCode)는 기본 메서드로 제공 할 수 없다.
- 구현체가 재정의 해서 사용해야 함
- 여러개를 인터페이스를 다중상속을 통해 구현했을 때, 기본 메서드(Default Mehtods)가 충돌하는 경우 직접 재정의해서 사용해야 함(자바에서는 이를 커파일 에러로 구분해버리기 때문)
- 수정할 수 있는 인터페이스에만 기본 메소드를 제공할 수 있다.
인터페이스 스태틱 메서드(Static Method)
- 유틸리티나 헬터 메서드를 제공할 때 사용 함
위의 인터페이스로 인해 API개발의 변화가 일어남
Java8 이전의 방식(클래스 상속을 이용)
- 인터페이스를 상속하는 추상클래스를 만들고, 이 추상클래스를 상속받는 클래스에서 인터페이스의 메서드를 각각 구현시켜서 사용
- 단점 : 상속은 하나만 가능하기 때문에 한계가 있다
Java8에서 사용
- 인터페이스를 구현하여 implements 해서 사용
- 장점 : 상속이 강제되지 않는다(비 침투성), 코드가 간결해짐
- Spring 에서는 상속을 강제하지 않는 방식을 선호함
Stream
- 연속 된 자원을 병렬적으로 처리하는 방법
- 하나의 컨베이어 벨트가 진행되며 상품이 만들어지는 방식과 유사
- 스트림이 처리하는 데이터 소스를 변경하지 않는다
- 스트림으로 처리하는 데이터는 오직 한번반 처리한다
- 중개 오퍼레이션은 근본적으로 lazy 하다 -> 종료 오퍼레이션이 오기전까지 중개 오퍼레이션은 처리하지 않는다.
- 손쉽게 병렬 처리를 할 수 있다.
중개 오퍼레이션
- Stream을 리턴
- Stateless / Stateful 오퍼레이션으로 더 상세하게 구분 할 수도 있다.( 대부분은 Stateless지만, distinct나 sorted 처럼 이전 이전 소스 데이터를 참조해야 하는 오퍼레이션은 Stateful 오퍼레이션이다.)
- 종류 : filter, map, limit, skip, sorted, …
종료 오퍼레이션
- Stream을 리턴 X
- 종류 : collect, allMatch, count, forEach, min, max …
Optional
- 오직 값 한개가 들어있을 수도 없을 수도 있는 컨테이너
- NullPointException 예외가 발생하는 원인을 해결하기 위해서 주로 사용(null 체크를 해서 해결 해도 되지만 깜빡하는 경우가 많기 때문에)
- 사용시 주의사항
- 리턴 값으로 만 사용하길 권장 함
- Optional을 리턴하는 메서드에서 null을 리턴하지 말자
- 프리미티브 타입용 Optional이 따로 있다. Ex) OptionalInt, OptionalLong, …
- Collection, Map, Stream Array, Optional은 Optional 로 감싸면 안된다.
'Study > Java&Spring' 카테고리의 다른 글
JPA Flush(플러시) (0) | 2022.01.17 |
---|---|
JPA Fetch Join 튜닝 (0) | 2022.01.15 |
SpringBoot 조회 API (0) | 2022.01.04 |
@Transactional Annotation 과 AOP 그리고 CGLib 와 Dynamic Proxy(JDK Proxy) (0) | 2022.01.03 |
JPA 정의와 사용 (0) | 2021.12.30 |