[모던 자바 인 액션] chap03. 람다 표현식(1)
2023. 2. 21. 22:42ㆍJava
람다 표현식 - 메서드로 전달할 수 있는 익명 함수를 단순화한 것
람다의 특징
- 익명
- 함수 - 람다는 메서드처럼 특정 클래스에 종속되지 않으므로 함수라고 부른다. 하지만 메서드처럼 파라미터 리스트, 바디, 반환 형식, 가능한 예외 리스트를 포함한다.
- 전달 - 람다 표현식은 메서드 인수로 전달하거나 변수로 저장할 수 있다.
- 간결성
// 기존에 사용하던 코드
Comparator<Apple> byWeight = new Comparator<Apple>() {
@Override
public int compare(Apple o1, Apple o2) {
return o1.getWeight().compareTo(a2.getWeight());
}
}
// 람다를 사용하면 간편해진다.
Comparator<Apple> byWeight = (o1, o2) -> o1.getWeight().compareTo(a2.getWeight());
람다 표현식은 파라미터, 화살표, 바디로 이루어진다.
(Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight());
람다 파라미터 바디
자바 8에서 지원하는 람다 표현식 예제
(String s) -> s.length() // String 형식의 파라미터를 하나 가지며, int를 반환
(Apple a) -> a.getWeight() > 150 // boolean을 반환, return값을 명시할 필요는 없다.
(int x, int y) -> {
System.out.println("Result: ");
System.out.println(x + y);
} // return값이 없음. 여러 행의 문장을 포함할 수 있다는 표현
() -> 42 // 파라미터가 없으며 int 42를 반환한다.
(Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight())
// a1, a2의 비교 결과를 반환
책의 람다 사용 예제
불리언 표현식 | (List list) -> list.isEmpty() |
객체 생성 | () -> new Apple(10) |
객체에서 소비 | (Apple a) -> { System.out.println(a.getWeight()); } |
객체에서 선택/추출 | (String s) -> s.length() |
두 값을 조합 | (int a, int b) -> a * b |
두 객체 비교 | (Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()); |
함수형 인터페이스 - 하나의 추상 메서드를 지정하는 인터페이스.
자바 API의 함수형 인터페이스로는 Comparator, Runnable 등이 있다.
* 인터페이스는 디폴트 메서드를 포함할 수 있다. 많은 디폴트 메서드가 있더라도
추상 메서드가 오직 하나면 함수형 인터페이스다.
함수 디스크립터
함수 디스크립터 - 함수형 인터페이스의 추상 메서드의 시그니처
시그니처 - 메서드 명, 파라미터의 순서, 타입, 개수 ex) compare(Apple o1, Apple o2)
실행 어라운드 패턴 - 실제 자원을 처리하는 코드를 설정과 정리 두 과정이 둘러싸는 형태를 갖는 형식의 코드
public String processFile() throws IOException {
try (BufferedReader br =
new BufferedReader(new FileReader("data.txt"))) {
return br.readLine(); // 실제 작업을 필요로 하는 행
}
}
String result = processFile((BufferedReader br) ->
br.readLine() + br.readLine());
// processFile 메서드를 동작 파라미터화한 람다식
함수형 인터페이스를 이용해 동작 전달
@FunctionalInterface
public interface BufferedReaderProcessor {
String process(BufferedReader b) throws IOException;
}
// 정의한 인터페이스를 processFile 메서드의 인수로 전달할 수 있다.
public String processFile(BufferedReaderProcessor p) throws
IOException {
try (BufferedReader br =
new BufferedREader(new FileReader("data.txt"))) {
return p.process(br);
}
}
// 한 행을 처리하는 경우
String oneLine = processFile((BufferedReader br) -> br.readLine());
// 두 행을 처리하는 경우
String twoLine = processFile((BufferedReader br) -> br.readLine() + br.readLine());
함수형 인터페이스의 종류
- Predicate - test라는 추상 메서드를 정의한다. 제네릭 형식 T의 객체를 인수로 받아 불리언을 반환한다. T 형식 객체를 사용하는 불리언 표현식이 필요한 상황에서 Predicate 인터페이스를 사용할 수 있다.
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
public <T> List<T> filter(List<T> list, Predicate<T> p) {
List<T> results = new ArrayList<>();
for(T t : list) {
if(p.test(t)) {
result.add(t);
}
}
return results;
}
Predicate<String> nonEmptyStringPredicate = (String s) -> !s.isEmpty();
List<String> nonEmpty = filter(listOfThings, nonEmptyStringPreidcate);
- Consumer - 제네릭 T 형식의 객체를 받아 void를 반환하는 accept라는 추상 메서드를 정의한다. T 형식의 객체를 인수로 받아서 어떤 동작을 수행하고 싶을 때 Consumer 인터페이스를 사용할 수 있다.
@FunctionalInterface
public interface Consumer<T> {
void accpet(T t);
}
public <T> void forEach(List<T> list, Consumer<t> c) {
for(T t : list){
c.accept(t);
}
}
forEach(Arrays.asList(1, 2, 3, 4, 5),
(Integer i) -> System.out.println(i)
);
- Function - 제네릭 형식 T를 인수로 받아서 제네릭 형식 R 객체를 반환하는 추상 메서드 apply를 정의한다. 입력을 출력으로 매핑하는 람다를 정의할 때 활용할 수 있다.
@FunctionalInterface
public interface Fuction<T, R> {
R apply(T t, R r);
}
public <T, R> List<R> map(List<T> list, Function<T, R> f) {
List<R> result = new ArrayList<>();
for(T t : list) {
result.add(f.apply(t));
}
}
List<Integer> l = map(Arrays.asList("lambdas", "in", "action"),
(String s) -> s.length()
);
// result == [7, 2, 6]
등등 많은 것들이 있다.
람다와 함수형 인터페이스 예제
불리언 표현 | (List<String> list) -> list.isEmpty() | Predicate<List<String>> |
객체 생성 | () -> new Apple(10) | Supplier<Apple> |
객체에서 소비 | (Apple a) -> System.out.println(a.getWeight()) |
Consumer<apple> |
객체에서 선택/추출 | (String s) -> s.length() | Function<String, Integer> 또는 ToIntFunction<String> |
두 값 조합 | (int a, int b) -> a * b | IntBinaryOperator |
두 객체 비교 | (Apple a1, Apple a2) -> a1.getWeight() .compareTo(a2.getWeight()) |
Comparator<Apple> 또는 BiFunction<Apple, Apple, Integer> 또는 ToIntBiFunction<Apple, Apple> |
108장부터. 3.2로 다시 정리
'Java' 카테고리의 다른 글
[모던 자바 인 액션] chap05. 스트림 활용 (0) | 2023.03.05 |
---|---|
[모던 자바 인 액션] chap04. 스트림이란? (0) | 2023.03.01 |
[모던 자바 인 액션] chap03. 람다 표현식(2) (0) | 2023.02.24 |
[모던 자바 인 액션] chap02. 동적 파라미터화 코드 전달하기 (0) | 2023.02.18 |
[모던 자바 인 액션] chap01. 자바 8에 무슨 일이..? (0) | 2023.02.13 |