본문 바로가기

BackEnd/Java

[java] 이것이 자바다 ch16 람다식(rambda)

728x90

1. 람다식

   ▷ 함수형 프로그래밍 : 함수를 정의하고 이 함수를 데이터 처리부로 보내 데이터를 처리하는 기법

   ▷ 데이터 처리부는 제공된 함수의 입력값으로 데이터를 넣고 함수에 정의된 처리 내용을 실행

   ▷ 람다식 : 데이터 처리부에 제공되는 함수 역할을 하는 매개변수를 가진 중괄호 블록이다.

   ▷ 자바는 람다식을 익명 구현 객체로 변환

 

람다식 : (매개변수, ...) -> { 처리 내용 }

public interface Calculable{
	// 추상 메소드
    void calculate(int x, int y);
}​

action( (x,y) -> {
	int result = x + y;
    System.out.println(result);
});​

 

◎ 함수형 인터페이스

   ▷ 인터페이스가 단 하나의 추상 메소드를 가지는 것

   ▷ 인터페이스가 함수형 인터페이스임을 보장하기 위해서는 @FunctionalInterface 어노테이션을 붙임

   ▷ @FunctionalInterface : 컴파일 과정에서 추상 메소드가 하나인지 검사해 정확한 함수형 인터페이스를 작성할 수 있게 도와주는 역할

 

1. 인터페이스
public interface Runnable {
   void run();
}

@FunctionalInterface
public interface Calculable {
   void calculate(int x, int y);
}

 

2. 람다식
( ) -> { ... }

( x, y ) -> { ... }

 

 함수형 인터페이스 예시

1. Calculable 인터페이스
@FunctionalInterface
public interface Calculable {
	// 추상 메소드
	void calculate(int x, int y);
}​

2. LamdaExample 메인 클래스
public class LamdaExample {

	public static void main(String[] args) {
		action((x,y) -> {
			int result = x + y;
			System.out.println("result : " + result);
		});
		
		action((x,y) -> {
			int result = x - y;
			System.out.println("result : " + result);
		});
	}
	
	public static void action(Calculable calculable) {
		// 데이터
		int x = 10;
		int y = 4;
		// 데이터 처리
		calculable.calculate(x, y);
	}
}

//	출력 : 
//	result : 14
//	result : 6​

 

 

2. 매개변수가 없는 람다식

   ▷ 함수형 인터페이스의 추상 메소드에 매개변수가 없을 경우 람다식 작성하기

   ▷ 실행문이 두 개 이상일 경우에는 중괄호를 생략할 수 없고, 하나일 경우에만 생략할 수 있음

 

◎ 매개변수가 없는 람다식 예시

1. Workable 인터페이스
@FunctionalInterface
public interface Workable {
	void work();
}​

 

2. Person 클래스
public class Person {
	public void action(Workable workable) {
		workable.work();
	}
}​

 

3. LambdaExample 메인 클래스
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("퇴근합니다."));
	}
}

//	출력 : 
//	출근을 합니다.
//	프로그래밍을 합니다.
//	퇴근합니다.​

 

 

3. 매개변수가 있는 람다식

   ▷ 함수형 인터페이스의 추상 메소드에 매개변수가 있을 경우 람다식 작성하기

   ▷ 매개변수를 선언할 때 타입은 생략할 수 있고, 구체적인 타입 대신에 var를 사용할 수 있습니다.

       ▶ 추상 메소드가 이미 타입에 대한 부분을 정의해놓았기 때문에 생략해도 됩니다.

   ▷ 매개변수가 하나일 경우에는 괄호를 생략 가능합니다. 이때는 타입 또는 var를 붙일 수 없습니다.

 

1. Workable 인터페이스
@FunctionalInterface
public interface Workable {
	void work(String name, String job);
}​


2. Speakable 인터페이스
@FunctionalInterface
public interface Speakable {
	void speak(String content);
}​


3. Person 클래스

public class Person {
	public void action1(Workable workable) {
		workable.work("홍길동", "프로그래밍");
	}
	
	public void action2(Speakable speakable) {
		speakable.speak("안녕하세요");
	}
}​


4. LambdaExample 메인 클래스

public class LambdaExample {
	public static void main(String[] args) {
		Person person = new Person();
		
		// 매개변수가 두 개일 경우
		person.action1((name, job) -> {
			System.out.print(name + "이 ");
			System.out.println(job + "을 합니다.");
		});
		
		person.action1((name, job) -> System.out.println(name + "이 " + 
								job + "을 하지 않습니다."));
		
		// 매개변수가 한 개일 경우
		person.action2(word -> {
			System.out.print("\"" + word + "\"");
			System.out.println("라고 말합니다.");
		});
		
		person.action2(word -> System.out.println("\"" + word + "\"라고 외칩니다."));
		
	}
}

//	출력 : 
//	홍길동이 프로그래밍을 합니다.
//	홍길동이 프로그래밍을 하지 않습니다.
//	"안녕하세요"라고 말합니다.
//	"안녕하세요"라고 외칩니다.

 

 

4. 리턴값이 있는 람다식

   ▷ 함수형 인터페이스의 추상 메소드에 리턴값이 있을 경우 람다식 작성하기

   ▷ return문 하나만 있을 경우에는 중괄호와 함께 return 키워드를 생략 가능

   ▷ 리턴값은 연산식 또는 리턴값 있는 메소드 호출로 대체 가능

 

1. Calcuable 인스턴스
@FunctionalInterface
public interface Calcuable {
	// 추상 메소드
	double calc(double x, double y);
}​

 

2. Person 클래스
public class Person {
	public void action(Calcuable calcuable) {
		double result = calcuable.calc(10, 4);
		System.out.println("결과 : " + result);
	}
}​


3. LambdaExample 메인 클래스

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) -> {
		// return (x+y);
		// });
		person.action((x,y) -> (x + y));
		
		// 리턴문이 하나만 있을 경우 (메소드 호출)
		// person.action((x,y) -> {
		// return sum(x+y);
		// });
		person.action((x,y) -> sum(x, y));
	}
	
	public static double sum(double x, double y) {
		return (x+y);
	}
}

//	출력 : 
//	결과 : 14.0
//	결과 : 14.0
//	결과 : 14.0

 

 

5. 메소드 참조

   ▷ 메소드를 참조해 매개변수의 정보 및 리턴 타입을 알아내 람다식에서 불필요한 매개변수를 제거

 

◎ 정적 메소드와 인스턴스 메소드 참조

   ▷ 정적 메소드를 참조시 클래스 이름 뒤에 :: 기호를 붙이고 정적 메소드 이름을 기술

   ▷ 인스턴스 메소드일 경우에는 객체를 생성한 다음 참조 변수 뒤에 :: 기호를 붙이고 인스턴스 메소드 이름을 기술

 

1. Calcuable 인스턴스
@FunctionalInterface
public interface Calcuable {
	// 추상 메소드
	double calc(double x, double y);
}​

 

2. Person 클래스
public class Person {
	public void action(Calcuable calcuable) {
		double result = calcuable.calc(10, 4);
		System.out.println("결과 : " + result);
	}
}​

 

3. Computer 클래스
public class Computer {
	public static double staticMethod(double x, double y) {
		return x+y;
	}
	
	public double instanceMethod(double x, double y) {
		return x*y;
	}
}

 

4.  MethodReferenceExample
public class MethodReferenceExample {

	public static void main(String[] args) {
		Person person = new Person();
		
		// 정적 메소드일 경우
		// 람다식
		// person.action((x,y) -> Computer.staticMethod(x,y));
		// 메소드 참조
		person.action(Computer :: staticMethod);
		
		// 인스턴스 메소드일 경우
		Computer com = new Computer();
		// 람다식
		// person.action((x,y) -> com.instanceMethod(x,y));
		// 메소드 참조
		person.action(com :: instanceMethod);
	}
}

//	출력 : 
//	결과 : 14.0
//	결과 : 40.0

 

◎ 매개변수의 메소드 참조

   ▷ 람다식에서 제공되는 a 매개변수의 메소드를 호출해서 b 매개변수를 매개값으로 사용

   ▷ a의 클래스 이름 뒤에 :: 기호를 붙이고 메소드 이름을 기술

 

1. Comparable 인터페이스
@FunctionalInterface
public interface Comparable {
	int compare(String a, String b);
}​

 

2. Person 클래스
public class Person {
	public void ordering(Comparable comparable) {
		String a = "홍길동";
		String b = "김길동";
		
		int result = comparable.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 + "보다 뒤에 옵니다.");			
		}
	}
}​

 

3. MethodReferenceExample 메인 클래스
public class MethodReferenceExample {

	public static void main(String[] args) {
		Person person = new Person();
		person.ordering(String :: compareToIgnoreCase);
	}
}

//	출력 :
//	홍길동은 김길동보다 뒤에 옵니다.​

 

 

6. 생성자 참조

   ▷ 객체를 생성하는 것. 람다식이 단순히 객체를 생성하고 리턴하도록 구성되면 람다식을 생성자 참조로 대치 가능

   ▷ 클래스 이름 뒤에 :: 기호를 붙이고 new 연산자를 기술

   ▷ 생성자가 오버로딩되어 여러 개가 있을 경우, 컴파일러는 함수형 인터페이스의 추상 메소드와 동일한 매개변수 타입과 개수를 가지고 있는 생성자를 찾아 실행

   ▷ 해당 생성자가 존재하지 않으면 컴파일 오류 발생

 

1. Creatable1 인터페이스
public interface Creatable1 {
	public Member create(String id);
}​

 

2. Creatable2 인터페이스
public interface Creatable2 {
	public Member create(String id, String name);
}​


3. Member 클래스

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;
	}
}


4. Person 클래스

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;
	}
}

 

5. ConstructorReferenceExample 메인 클래스
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);
	}
}

//	출력 : 
//	Member(String id)
//	{ id: winter, name: null}
//	
//	Member(String id, String name)
//	{ id: winter, name: 한겨울}​

 

람다식은 함수를 좀 더 간단하게 나타낼 수 있습니다.

아직 사용방법에 대해서는 자세하게 모르겠어서 문제를 풀어보면서 익혀야겠어요!!

 

 

많은 분들의 피드백은 언제나 환영합니다! 많은 댓글 부탁드려요~~

 

728x90