Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
Tags
- 자바의 정석 기초편 ch14
- 스프링 db1 - 스프링과 문제 해결
- 자바의 정석 기초편 ch4
- 스프링 mvc2 - 검증
- 스프링 mvc2 - 로그인 처리
- jpa 활용2 - api 개발 고급
- 자바의 정석 기초편 ch1
- 자바의 정석 기초편 ch13
- 스프링 mvc1 - 서블릿
- 스프링 입문(무료)
- 자바의 정석 기초편 ch11
- 자바의 정석 기초편 ch3
- @Aspect
- jpa - 객체지향 쿼리 언어
- 스프링 mvc1 - 스프링 mvc
- 스프링 mvc2 - 타임리프
- 스프링 고급 - 스프링 aop
- 스프링 db2 - 데이터 접근 기술
- 자바의 정석 기초편 ch9
- 코드로 시작하는 자바 첫걸음
- 자바의 정석 기초편 ch12
- 2024 정보처리기사 시나공 필기
- 2024 정보처리기사 수제비 실기
- 자바의 정석 기초편 ch5
- 자바의 정석 기초편 ch7
- 자바의 정석 기초편 ch8
- 자바의 정석 기초편 ch2
- 게시글 목록 api
- 자바의 정석 기초편 ch6
- 타임리프 - 기본기능
Archives
- Today
- Total
나구리의 개발공부기록
자바의 정석 기초편 ch14 - 1 ~ 6 [람다식이란?, 람다식 작성하기, 함수형 인터페이스] 본문
유튜브 공부/JAVA의 정석 기초편(유튜브)
자바의 정석 기초편 ch14 - 1 ~ 6 [람다식이란?, 람다식 작성하기, 함수형 인터페이스]
소소한나구리 2023. 12. 19. 15:46** 참고
- 자바는 JDK 1.8부터 함수형 언어의 기능을 탑재하여 객체지향과 함수형을 동시에 지원함
- 빅데이터가 뜨면서 함수형 언어가 각광 받기 시작하여 OOP언어들도 함수형 언어의 기능을 탑재하기 시작함 (Haskell,Erlang,Scala등등)
1) 람다식(Lambda Expression)
- 함수(메서드)를 간단한 '식(expression)'으로 표현하는 방법이며 코드의 간결성과 가독성을 높임
- 람다식은 익명 함수(이름이 없는 함수,anonymous function) 중 하나임
(1) 람다식 작성하기
- 메서드의 이름과 반환타입을 제거 후 '->'를 블록 { } 앞에 추가
- 반환값이 있는 경우, 식이나 값만 적고 return을 생략할 수 있으며 문장 끝에 세미콜론을 안적음
- 매개변수의 타입이 추론이 가능하면 생략 가능(대부분 생략 가능함)
// 원래 메서드
int max(int a, int b) {
return a > b ? a : b;
}
// 1. 메서드이름을 제거하고 매개변수를 -> 로 가리킴
(int a, int b) -> {
return a > b ? a : b;
}
// 2. return과 중괄호, 세미콜론을 생략
(int a, int b) -> a > b ? a : b
// 3. 매개변수 타입을 생략
(a, b) -> a > b ? a : b
(2) 람다식 작성시 주의사항
- 매개변수가 하나인 경우 괄호()를 생략할 수 있으며 타입도 생략해야함
- 블록 안의 문장이 하나뿐 일 때 중괄호 {}를 생략할 수 있고 문장의 끝에 세미콜론을 제외
- 단, 하나뿐인 문장이 return문이면 return까지 생략해야 중괄호를 생략할 수 있음
// 매개변수가 하나인 경우는 ()를 생략할 수 있음(타입도 생략해야함)
a -> a * a // OK
int a -> a * a // 에러
// 블록 안의 문장이 하나뿐일 때, 괄호 {} 생략 가능 (권장)
// 단, 하나뿐인 문장이 return문이면 괄호 {}필수 -> 보통은 return을 생략함
(int i) -> System.out.println(i)
// 삼항 연산자 사용 예시
(int a, int b) -> { return a > b ? a : b; } // OK
(int a, int b) -> return a > b ? a : b // 에러
(3) 람다식 예제
// 메서드
int max(int a, int b) {
return a > b ? a : b;
}
// 람다식
(a , b) -> a > b ? a : b
// 메서드
void printVar(String name, int i) {
System.out.println(name+"="+i);
}
// 람다식
(name, i) -> System.out.println(name+"="+i)
// 메서드
int square(int x) {
return x * x;
}
// 람다식
x -> x * x
// 메서드
int roll() {
return (int)(Math.random()*6);
}
// 람다식
() -> (int)(Math.random()*6)
(4) 정리
- 자바에서의 람다식은 익명클래스와 동일함
- 익명 클래스를 간결하게 람다식으로 표현할 수 있음
// 람다식
(a, b) -> a > b ? a : b
// 익명클래스
new Object() {
int max(int a, int b) {
return a > b ? a : b;
}
}
- 람다식이나 익명 클래스를 다루기 위해서는 참조변수가 필요함
- Object타입의 참조변수로 생성하여 람다식을 참조하면 기존에 익명클래스로 정의하였던 max()를 사용할 수 없음
- 람다식과 익명클래스에는 타입이 없고, 참조변수의 타입인 Object는 max가 정의되어있지 않기 때문에 조상타입의 참조변수로는 자손의 max()를 사용할 수가 없음
- 이것이 함수형 인터페이스가 필요한 이유임
// 익명클래스를 Object 타입의 참조변수에 저장
Object obj = new Object() {
int max(int a, int b) {
return a > b ? a : b;
}
};
// 람다식을 Object 타입의 참조변수에 저장
Object obj = (a, b) -> a > b ? a : b;
// 에러. Object클래스에는 max()가 없기 때문에 Object 타입의 참조변수로 max()를 호출할 수 없음
int value = obj.max(3,5);
2) 함수형 인터페이스
- 단 하나의 추상 메서드만 선언된 인터페이스 (@FunctionalInterface 애노테이션 작성도 함께 하는 것을 권장)
- 람다식을 다루기 위함이며 함수형 인터페이스 타입의 참조변수로 람다식을 참조할 수 있음
- 단, 함수형 인터페이스의 추상메서드와 람다식의 매개변수 개수, 반환타입이 일치해야 함
// 함수형 인터페이스
interface MyFunction {
public abstract int max(int a, int b);
}
// 익명클래스를 참조형 인터페이스 타입의 참조변수에 저장
MyFunction f = new MyFunction() {
public int max(int a, int b) {
return a > b ? a : b;
}
};
int value = f.max(3,5); // OK. MyFunction에 max()가 있음
// 람다식을 참조형 인터페이스 타입의 참조변수에 저장
MyFunction f = (a, b) -> a > b ? a : b;
int value = f.max(3,5); // OK. MyFunction에 추상메서드인 max()를 람다식이 구현하여 값을 반환
(1) 예제
public class Ex14_0 {
public static void main(String[] args) {
// Object타입 참조변수를 가진 람다식(익명 객체)
// Object obj = (a, b) -> a > b ? a : b;
// Object타입 참조변수가 obj인 익명클래스,
Object obj = new Object() {
int max(int a, int b) {
return a > b ? a : b;
}
};
int value = obj.max(3, 4); // 에러 발생함
// 참조변수의 타입을 함수형 인터페이스로 변경
MyFunction2 f2 = new MyFunction2() {
// 오버라이딩 규칙 - 접근제어자는 좁게 못바꿈, public 붙혀야 함
public int max(int a, int b) {
return a > b ? a : b;
}
};
// 함수형 인터페이스 타입 참조변수에 람다식의 참조를 저장(대입문이라서 ;을 붙혀야함)
MyFunction2 f3 = (a,b) -> a > b ? a : b;
// 함수형 인터페이스 타입인 참조변수 f2, f3으로 max()를 호출
int value1 = f2.max(3,5);
int value2 = f3.max(3,5);
System.out.println(value1);
System.out.println(value2);
}
}
// 애노테이션 작성(함수형 인터페이스는 하나의 추상 메서드만 가져야 함)
@FunctionalInterface
interface MyFunction2 {
// 모든 인터페이스의 메서드는 예외 없이 public, abstract이기 때문에 생략 가능함
// public abstract int max(int a, int b);
int max(int a, int b);
}
3) 함수형 인터페이스의 예시들
(1) 익명 객체를 람다식으로 대체
- Collections클래스의 sort()가 실제로 구현된 예시
- 메서드의 두번째 파라미터가 익명클래스로 구현되어 있기 때문에 sort함수를 호출할 때 람다식으로 정렬 기준을 입력할 수 있음
Collections.sort(list, new Comparator<String>() {
public int compare(String s1, String s2) {
return s2.compareTo(s1);
}
});
List<String> list = Arrays.asList("abc", "aaa", "bbb", "ddd", "aaa");
Collections.sort(list, (s1, s2)-> s2.compareTo(s1)); // 람다식으로 정렬
(2) 함수형 인터페이스 타입의 매개변수, 반환타입
- 메서드의 매개변수로 함수형 인터페이스 타입의 매개변수를 입력하면 람다식에 이름을 붙이고 람다식을 호출할 수 있음
- 함수형 인터페이스 타입의 반환타입인 메서드는 람다식을 반환한다는 뜻과 동일함
// 함수형 인터페이스 정의
@FunctionalInterface
interface MyFunction {
void myMethod();
}
// 메서드의 파라미터를 함수형 인터페이스로 정의 -> 해당 메서드를 호출하면 함수형인터페이스의 메서드를 호출
void aMethod(MyFunction f) {
f.myMethod(); // MyFunction에 정의된 메서드 호출
}
// 람다식의 반환값을 함수형인터페이스 타입 참조변수에 저장하고 aMethod(f)로 호출
MyFunction f = () -> System.out.println("myMethod()");
aMethod(f);
// 위의 2줄을 람다식에 이름을 붙혀서 한줄로 편하게 할 수 있음
aMethod(() -> System.out.println("myMethod()"));
// 반환타입이 함수형 인터페이스
MyFunction myMethod() {
MyFunction f = () -> {};
return f;
}
// return문을 람다식으로 할 수 있음
MyFunction myMethod() {
return () -> {};
}
(3) 예제
- 다양한 방식으로 참조형 인터페이스에 선언된 추상 메서드를 구현하여 실행
- 익명클래스, 람다식, 매개변수의 타입이 참조형 인터페이스인 메서드, 반환타입이 참조형 인터페이스인 메서드
@FunctionalInterface
interface MyFunction { // 함수형 인터페이스 선언
void run(); // public abstract void run();
}
class Ex14_1 {
static void execute(MyFunction f) { // 매개변수의 타입이 MyFunction인 메서드
// 람다식을 매개변수로 받아서 run()메서드를 호출
f.run();
}
static MyFunction getMyFunction() { // 반환 타입이 MyFunction인 메서드
// MyFunction f = () -> System.out.println("f3.run()");
// return f;
return () -> System.out.println("f3.run()"); // 위의 2줄을 한줄로 작성
}
public static void main(String[] args) {
// 람다식으로 MyFunction의 run()을 구현
MyFunction f1 = ()-> System.out.println("f1.run()");
MyFunction f2 = new MyFunction() { // 익명클래스로 run()을 구현
public void run() { // public을 반드시 붙여야 함
System.out.println("f2.run()");
}
};
MyFunction f3 = getMyFunction();
// 각 참조변수가 가리키는 run()메서드 호출
f1.run();
f2.run();
f3.run();
// 참조변수 f1이 가리키는 람다식을 매개변수로 받아 execute()메서드 호출
execute(f1);
// 람다식을 직접 구현하여 메서드 호출
execute(()-> System.out.println("run()"));
}
}
** 출처 : 남궁성의 정석코딩_자바의정석_기초편 유튜브