| 일 | 월 | 화 | 수 | 목 | 금 | 토 | 
|---|---|---|---|---|---|---|
| 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 | 
                            Tags
                            
                        
                          
                          - LG
 - 분류
 - deep learning
 - LG Aimers 4th
 - LG Aimers
 - 머신러닝
 - 해커톤
 - PCA
 - GPT-4
 - Classification
 - 딥러닝
 - supervised learning
 - 오블완
 - OpenAI
 - LLM
 - Machine Learning
 - AI
 - 티스토리챌린지
 - ChatGPT
 - 회귀
 - gpt
 - 지도학습
 - regression
 
                            Archives
                            
                        
                          
                          - Today
 
- Total
 
SYDev
[이것이 자바다] Chapter 16. 람다식 본문
1. 람다식이란?
- functional programming: 함수를 정의하고, 이 함수를 데이터 처리부로 보내 데이터를 처리하는 기법
 - 데이터 처리부는 데이터만 가지고 있으며, 처리 방법이 정해져 있지 않아 외부에서 제공된 함수에 의존
 

- 동일한 데이터라도 어떤 함수를 제공하는지에 따라, 처리하는 결과가 다를 수 있음 -> 데이터 처리의 다형성이라고도 볼 수 있음
 
람다식: (매개변수, ...) -> { 처리 내용 }
- Java는 람다식을 익명 구현 객체로 변환
 
예를 들어, 다음과 같은 인터페이스가 존재할 때
public interface Calculable {
    // abstract method
    void calculate(int x, int y);
}
해당 interface의 익명 구현 객체는 다음과 같이 생성 가능
new Caculable() {
    @Override
    public void calcuate(int x, int y) { 처리내용 }
};
이를 람다식으로 표현하면 아래 형태 - 람다식은 인터페이스의 익명 구현 객체 -> 인터페이스 타입의 매개변수에 대입 가능
(x, y) -> { 처리내용 };
다음과 같은 Caculable 매개변수를 가진 action() method에 대입 가능
public void action(Calculable calculable) {
    int x = 10;
    int y = 4;
    calculable.calculate(x, y);    // 데이터를 제공하고 추상 메소드를 호출
}
// action method 호출
action( (x, y) -> {
    int result = x + y;
    System.out.println(result);
});
- 인터페이스의 익명 구현 객체를 람다식으로 표현하려면, 인터페이스가 단 하나의 abstract method만 가져야 함
 - functional interface: 단 하나의 abstract method만 가지는 interface
 - @FunctionalInterface: 인터페이스가 함수형 인터페이스임을 보장 -> abstract method가 하나인지 검사
 

2. 매개변수가 없는 람다식
() -> {
    실행문;
    실행문;
}
() -> 실행문    // 실행문이 하나일 경우에만 중괄호 생략 가능
- 예제 1
package ch16.sec2.exam1;
@FunctionalInterface
public interface Workable {
	void work();
}
package ch16.sec2.exam1;
public class Person {
	public void action(Workable workable) {
		workable.work();
	}
}
package ch16.sec2.exam1;
public class LambdaExample {
	public static void main(String[] args) {
		Person person = new Person();
		
		// 실행문이 두 개 이상인 경우 중괄호 필요
		person.action(() -> {
			System.out.println("출근을 합니다.");
			System.out.println("프로그래밍을 합니다.");
		});
		
		// 실행문이 한 개일 경우 중괄요 생략 가능 
		person.action(() -> System.out.println("퇴근합니다."));
	}
}
- 예제 2
package ch16.sec2.exam2;
public class Button {
	// static member interface
	@FunctionalInterface
	public static interface ClickListener {
		// abstract method
		void onClick();
	}
	
	// field
	private ClickListener clickListener;
	
	// method
	public void setClickListener(ClickListener clickListener) {
		this.clickListener = clickListener;
	}
	
	public void click() {
		this.clickListener.onClick();
	}
}
package ch16.sec2.exam2;
public class ButtonExample {
	public static void main(String[] args) {
		// OK 버튼 객체 생성
		Button btnOk = new Button();
		
		// OK 버튼 객체에 람다식(ClickListener 익명 구현 객체) 주입
		btnOk.setClickListener(() -> {
			System.out.println("OK 버튼을 클릭했습니다.");
		});
		
		// OK 버튼 클릭하기
		btnOk.click();
		
		// Cancel 버튼 객체 생성
		Button btnCancel = new Button();
		
		btnCancel.setClickListener(() -> {
			System.out.println("Cancel 버튼을 클릭했습니다.");
		});
		
		// Cancel 버튼 클릭하기
		btnCancel.click();
	}
}

3. 매개변수가 있는 람다식
- 타입을 생략하고 작성하는 것이 일반적
 - 구체적 타입 대신에 var 사용 가능
 
// 타입 작성
(타입 매개변수, ...) -> {
    실행문;
    실행문;
}
(타입 매개변수, ...) -> 실행문
// var
(var 매개변수, ...) -> {
    실행문;
    실행문;
}
(var 매개변수, ...) -> 실행문
// 타입 생략
(매개변수, ...) -> {
    실행문;
    실행문;
}
(매개변수, ...) -> 실행문
- 매개변수가 하나일 경우 괄호 생략 가능, 이때 타입 또는 var 붙일 수 없음
 

4. 리턴값이 있는 람다식
(매개변수, ...) -> {
    실행문;
    return 값;
}
// return 키워드 생략
(매개변수, ...) -> 값
- 예제
package ch16.sec4;
public class Person {
	public void action(Calculable calculable) {
		double result = calculable.calc(10, 4);
		System.out.println("결과: " + result);
	}
}
package ch16.sec4;
@FunctionalInterface
public interface Calculable {
	double calc(double x, double y);
}
package ch16.sec4;
public class LambdaExample {
	public static void main(String[] args) {
		Person person = new Person();
		
		// 실행문이 두 개 이상일 경우
		person.action((x, y) -> {
			double result = x + y;
			return result;
		});
		
		// 리턴문이 하나만 있을 경우(연산식)
		person.action((x, y) -> (x + y));
		
		// 리턴문이 하나만 있을 경우(메소드 호출)
		person.action((x, y) -> sum(x, y));
	}
		
	public static double sum(double x, double y) {
		return (x + y);
	}
}
5. 메소드 참조
- 메소드 참조는 메소드를 참조해서 매개변수의 정보 및 리턴 타입을 알아내 람다식에서 불필요한 매개변수를 제거하는 목적
 - ex) 두 개의 값을 받아 큰 수를 리턴하는 Math 클래스의 max() static method를 호출하는 람다식
 
(left, right) -> Math.max(left, right);
위 람다식을 다음과 같이 메소드 참조로 표현 가능
Math :: max;
5.1. 정적 메소드와 인스턴스 메소드 참조
클래스 :: 메소드   // static method
참조변수 :: 메소드  // instance method
5.2. 매개변수의 메소드 참조
- 람다식에서 제공되는 a 매개변수의 메소드를 호출해서, b 매개변수값을 매개값으로 사용하는 경우 존재
 
(a, b) -> { a.instanceMethod(b); }
위 람다식을 다음과 같이 표현 가능
클래스 :: instanceMethod
-> 작성 방법은 static method 참조와 동일, but a의 instance method가 사용된다는 점에서 차이 존재
- 예제
package ch16.sec5.exam2;
public interface Comparable {
	int compare(String a, String b);
}
package ch16.sec5.exam2;
public class Person {
	public void ordering(Comparable comaprable) {
		String a = "홍길동";
		String b = "김길동";
		
		int result = comaprable.compare(a, b);
		
		if(result < 0) {
			System.out.println(a + "은 " + b + "보다 앞에 옵니다.");
		} else if(result == 0) {
			System.out.println(a + "은 " + b + "과 같습니다.");
		} else {
			System.out.println(a + "은 " + b + "보다 뒤에 옵니다.");
		}
	}
}
package ch16.sec5.exam2;
public class MethodReferenceExample {
	public static void main(String[] args) {
		Person person = new Person();
		// (a, b) -> a.compareToIgnoreCase(b)
		person.ordering( String :: compareToIgnoreCase );
	}
}

6. 생성자 참조
- 생성자 참조 -> 객체를 생성하는 것을 의미
 - 람다식이 단순히 객체를 생성하고 리턴하도록 구성 -> 람다식을 생성자 참조로 대치 가능
 
(a, b) -> { return new 클래스(a, b); }
위 람다식을 다음과 같이 표현 가능
클래스 :: new
- 생성자가 오버로딩되어 여러 개 존재하는 경우
- 컴파일러는 functional interface의 abstract method와 동일한 매개변수 타입과 개수를 가지고 있는 생성자를 찾아 실행
 - 해당 생성자가 존재하지 않으면 컴파일 오류 발생
 
 
- 예제
package ch16.sec5.exam3;
@FunctionalInterface
public interface Creatable1 {
	public Member create(String id);
}
package ch16.sec5.exam3;
@FunctionalInterface
public interface Creatable2 {
	public Member create(String id, String name);
}
package ch16.sec5.exam3;
public class Member {
	private String id;
	private String name;
	
	public Member(String id) {
		this.id = id;
		System.out.println("Member(String id)");
	}
	
	public Member(String id, String name) {
		this.id = id;
		this.name = name;
		System.out.println("Member(String id, String name)");
	}
	
	@Override
	public String toString() {
		String info = "{ id: " + id + ", name: " + name + " }";
		return info;
	}
}
package ch16.sec5.exam3;
public class Person {
	public Member getMember1(Creatable1 creatable) {
		String id = "winter";
		Member member = creatable.create(id);
		return member;
	}
	
	public Member getMember2(Creatable2 creatable) {
		String id = "winter";
		String name = "한겨울";
		Member member = creatable.create(id, name);
		return member;
	}
}
package ch16.sec5.exam3;
public class ConstructorReferenceExample {
	public static void main(String[] args) {
		Person person = new Person();
		
		Member m1 = person.getMember1( Member :: new );
		System.out.println(m1);
		System.out.println();
		
		Member m2 = person.getMember2( Member :: new );
		System.out.println(m2);
	}
}

참고자료
728x90
    
    
  반응형
    
    
    
  'Programming Lang > Java' 카테고리의 다른 글
| [이것이 자바다] Chapter 18. 데이터 입출력 (1) | 2025.02.06 | 
|---|---|
| [이것이 자바다] Chapter 17. 스트림 요소 처리 (0) | 2025.02.03 | 
| [이것이 자바다] Chapter 15. 컬렉션 자료구조 (0) | 2025.02.02 | 
| [이것이 자바다] Chapter 14. 멀티 스레드 (1) | 2025.02.01 | 
| [이것이 자바다] Chapter 13. 제네릭 (0) | 2025.01.31 |