일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- spring Batch
- Design Pattern
- CQRS
- spring
- 패스트캠퍼스
- Template Method Pattern
- spring boot
- 자바의 신
- Java8 in action
- Stream
- SERVLET
- domain
- jsp
- 디자인 패턴
- 자바
- head first
- Java8
- 자바8인액션
- 스트림
- Clean Code
- facade pattern
- 자바8
- Was
- Java in action
- web
- Java 8 in action
- 클린코드
- ddd
- Java
- AWS101
- Today
- Total
주난v 개발 성장기
[자바 8인 액션] 3장. 람다 표현식 본문
람다 표현식
- 익명함수를 단순화한 것
람다 표현식에는 이름이 없지만, 파라미터 리스트, 바디, 반환 형식, 예외 리스트는 가질 수 있다.
-
익명 : 메소드 이름이 없다.
-
함수 : 람다 표현식은 특정 클래스에 종속되지 않으므로 함수라고 한다.
함수처럼 파라미터 리스트, 바디, 반환 형식, 예외 리스트를 가진다.
-
전달 : 람다 표현식을 메서드 인수로 전달하거나 변수로 저장할 수 있다.
-
간결성 : 자질 구레한 코드가 필요 없다.
Comparator<Apple> byWeight = new Comparator<Apple>() {
public int compare(Apple apple1, Apple apple2) {
return apple1.getWeight().compareTo(apple2.getWeight());
}
};
(Apple apple1, Apple apple2) // 람다 파라미터
-> // 화살표 (파라미터 리스트와 바디를 구분)
apple1.getWeight().compareTo(apple2.getWeight()); // 람다 바디
(parameters) -> expression 표현식
(String s) -> "Iron man"
() -> "Raoul"
(parameters) -> {statements;} 구문
() -> "Raoul"
(Integer i) -> {return "Alan" + i;}
(String s) -> {return "Iron man";}
람다를 어디에 어떻게 사용할까?
함수형 인터페이스에서 사용이 가능하다.
함수형 인터페이스
- Predicate<T>가 함수형 인터페이스다. 오직 하나의 추상 메서드만 지정한다.
@FunctionalInterface
함수형 인터페이스는 "정확히 하나의 추상 메서드를 지정하는 인터페이스"
많은 디폴트 메서드가 존재하더라도 추상 메서드가 오직 하나면 함수형 인터페이스다.
함수 디스크립터
- 함수형 인터페이스의 추상 메서드 시그니처는 람다 표현식의 시그니처를 가리킨다.
람다 표현식의 시그니처를 서술하는 메서드를 "함수 디스크립터"
람다 활용 : 실행 어라운드 패턴
설정 - 처리 - 정리 과정
public String processFile() throws IOException {
try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) {
return br.readLine();
}
}
---------------------------------------------------------------------------------------
//함수형 인터페이스
public interface BufferedReaderProcessor {
String process(BufferedReader b) throws IOException;
}
public String processFile(BufferedReaderProcessor processor) throws IOException {
...
}
---------------------------------------------------------------------------------------
//동작 실행
public String processFile(BufferedReaderProcessor processor) throws IOException {
try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) {
return processor.process();
}
}
---------------------------------------------------------------------------------------
//람다 적용
String oneLine = processFile((BufferedReader br) -> br.readLine());
String oneLine = processFile((BufferedReader br) -> br.readLine() + br.readLine());
함수형 인터페이스는 오직 하나의 추상 메서드 지정
함수형 인터페이스의 추상 메서드 시그니처를 "함수 디스크립터"라고 한다.
(ex, Comparable, Runnable, Callable 등의 다양한 함수형 인터페이스를 포함)
- Predicate
- test 추상 메서드 정의
- test는 제네릭 형식 T의 객체를 인수로 받아 불린을 반환
- 함수 디스크립터 T -> boolean
- Consumer
- accept 추상 메서드 정의
- 제네릭 형식 T의 객체를 인수로 받아, void로 반환
- 함수 디스크립터 T -> void
- Function
- apply 추상 메서드 정의
- 제네릭 형식 T를 인수로 받아서, 제네릭 형식 R 객체를 변환
- 함수 디스크립터 T -> R
Predicate<T>, Consumer<T>, Function<T,R>
박싱 / 언박싱
- 비용 소모
- 박싱한 값은 기본형을 감싸는 Wrapper며, Heap에 저장
- 박싱한 값은 메모리를 더 소비, 기본형을 가져올때도 메모리를 탐색하는 과정이 필요하다.
형식 검사
- 람다가 사용되는 컨텍스트를 이용해서 람다의 형식을 추론할 수 있다.
다이아몬드 연산자 <>로 컨텍스트에 제네릭 형식을 추론할 수 있다.
특별한 void 호환 규칙
람다의 바디에 일반 표현식이 있으면, void를 반환하는 함수 디스크립터와 호환된다.
List의 add 메서드는 Consumer 콘텍스트(T -> void)가 기대하는 void 대신 boolean을 반환하지만, 유효한 코드다.
Predicate<String> predicate = s -> list.add(s);
형식 추론
상황에 따라 명시적으로 포함하는 것이 좋을 때도 있고, 배제하는 것이 가독성을 향상 시킬 때도 있다.
제약
지역 변수 사용
지금까지의 람다 표현식은 인수를 자신의 바디 안에서만 사용
현실에서는 자유 변수(외부 변수)를 활용할 수 있다. 이와 같은 동작을 람다 캡처링이라고 부른다.
인스턴스 변수, 정적 변수는 자유롭게 캡처할 수 있다.
지역 변수는 명시적으로 final이 선언되어 있어야 하거나 실질적으로 final 처럼 사용이 되어야 한다.
지역 변수의 제약
- 내부적으로 인스턴스 변수는 힙 메모리에 저장, 지역 변수는 스택에 위치
클로저 : 함수의 비지역 변수를 자유롭게 참조할 수 있는 함수의 인스턴스
메서드 레퍼런스
- 기존의 메서드 정의를 재활용해서 람다처럼 전달할 수 있다.때로는 람다 표현식보다 메서드 레퍼런스를 사용하는 것이 좋을 때도 있다.
inventory.sort((Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()));
inventory.sort(comparing(Apple::getWeight));
메서드명 앞에 구분자(::)를 이용해서 메서드 레퍼런스를 활용할 수 있다.
메서드 레퍼런스를 만드는 방법
1. 정적 메서드 레퍼런스 Integer :: parseInt
2. 다양한 형식의 인스턴스 메서드 레퍼런스 String :: length
3. 기존 객체의 인스턴스 메서드 레퍼런스 (클래스 :: 메서드)
생성자 레퍼런스
Apple:: new
람다, 메서드 레퍼런스 활용하기
//1. 코드 전달
public class AppleComparator implements Comparator<Apple> {
public int compare(Apple a1, Apple a2) {
return a1.getWeight().compareTo(a2.getWeight());
}
}
inventory.sort(new AppleComparator());
// 2. 익명 클래스 사용
inventory.sort(new AppleComparator<Apple>() {
public int compare(Apple a1, Apple a2) {
return a1.getWeight().compareTo(a2.getWeight());
}
});
// 3. 람다 표현식 사용
//자바 컴파일러는 람다 표현식이 사용된 콘텍스트를 활용해서 람다의 파라미터 형식을 추론한다.
inventory.sort((Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight());
or
inventory.sort((a1, a2) -> a1.getWeight().compareTo(a2.getWeight());
// 4. 메소드 레퍼런스
inventory.sort(comparing(Apple::getWeight));
'개발 성장기 > JAVA' 카테고리의 다른 글
[자바 8인 액션] 5장. 스트림 활용 (0) | 2020.07.15 |
---|---|
[자바 8인 액션] 4장. 스트림 소개 (0) | 2020.07.05 |
[자바 8 인 액션] 2장. 동작 파라미터화 코드 전달 (0) | 2020.06.17 |
[자바 8 인 액션] 1장. 자바 8을 눈여겨봐야 하는 이유 (0) | 2020.06.13 |
[자바의 신] 1 ~ 13장 (0) | 2019.12.08 |