구조
// 익명 구현 객체
new 클래스명() {
@Override
메소드명();
};
// 람다식
(매개변수) -> { 처리내용 };
인터페이스가 단 하나의 추상메소드를 발생해주는 것
인터페이스가 함수형 인터페이스임을 보장하기 위해서는 @FunctionalInterface 어노테이션을 붙여줘야함
@FunctionalInterface
-> 컴파일 과정에서 해당 인터페이스를 람다 구문으로 사용할 수 있는지 체크하는 어노테이션
-> 함수가 두 개이면 오류가 발생함
package ch16.sec01;
@FunctionalInterface
// @FunctionalInterface : 람다식으로 사용할 수 있는 인터페이스인지 확인하는 어노테이션
// 메소드가 두 개 이상일 경우 오류 발생
public interface Calculable {
void calculate(int x, int y);
}
package ch16.sec01;
public class LamdaExample {
public static void main(String[] args) {
// 람다식 형태 (매개변수) -> {실행문};
// 익명 클래스의 형태를 조금 더 간략하게 표현한 구문
action((x,y) -> {
int result = x + y;
System.out.println(result);
});
action((x,y) -> {
int result = x-y;
System.out.println(result);
});
}
// 정적 메소드 action 선언
public static void action(Calculable calculable) {
int x = 10;
int y = 4;
// Calculable 인터페이스에서 정의된 메소드를 사용
// 실행은 람다식에서 선언하기 때문에 매개변수만 선언해줘도 됨
calculable.calculate(x, y);
}
}
package ch16.sec02.exam01;
// @FunctionalInterface : 해당 인터페이스가 람다식으로 사용이 가능한지 컴파일러가 판단
@FunctionalInterface
public interface Workable {
void work();
}
package ch16.sec02.exam01;
public class Person {
// Workable을 메소드로 가지는 action 메소드
// 소유권은 나에게 없음
public void action(Workable workable) {
workable.work();
}
}
package ch16.sec02.exam01;
public class LamdaExample {
public static void main(String[] args) {
Person person = new Person();
// 구조 : (() -> { 실행문 });
// 실행문이 두 개 이상일 경우 중괄호를 꼭 붙여줘야함
person.action(() -> {
System.out.println("출근");
System.out.println("프로그래밍");
});
// 실행문이 하나일 경우 중괄호 생략 가능
// 해당 실행문에는 세미콜론 붙이지 않기!
person.action(() -> System.out.println("퇴근"));
}
}
package ch16.sec02.exam02;
public class Button {
// 정적 멤버 인터페이스 선언
@FunctionalInterface
public static interface ClickListener {
// 추상 메소드
void onClick();
}
// 위의 인터페이스를 필드로 사용
private ClickListener clickListener;
// 외부에서 인터페이스 구현 객체를 받아
// 이를 인터페이스 필드에 대입시키는 것
public void setClickListener(ClickListener clickListener) {
this.clickListener = clickListener;
}
// 위의 인터페이스를 동작하기 위한 메소드
public void click() {
this.clickListener.onClick();
}
}
package ch16.sec02.exam02;
public class ButtonExample {
public static void main(String[] args) {
// 버튼 객체 생성 및 OK 버튼 사용
Button btnOk = new Button();
// 해당 메소드에 람다식을 이용해 매개값을 전달함
btnOk.setClickListener(() -> {
System.out.println("OK 버튼을 클릭했습니다");
});
// OK 버튼 클릭
btnOk.click();
// 버튼 객체 생성 및 Cancel 버튼 사용
Button btnCancel = new Button();
// 해당 메소드에 람다식을 이용해 매개값을 전달
btnCancel.setClickListener(() -> {
System.out.println("Cancel 버튼을 클릭했습니다.");
});
// Cancel 버튼 클릭
btnCancel.click();
}
}
package ch16.sec03;
@FunctionalInterface
public interface Workable {
// 인자를 2개 가지는 추상 메소드
void work(String name, String job);
}
package ch16.sec03;
@FunctionalInterface
public interface Speakable {
// 인자를 하나 가지는 추상 메소드
void speak(String content);
}
package ch16.sec03;
public class Person {
public void action1(Workable workable) {
// 매개변수를 두 개 가지고 있는 메소드이므로 인자를 두 개 입력함
workable.work("홍길동", "프로그래밍");
}
public void action2(Speakable speakable) {
// 매개변수를 한 개 가지고 있는 메소드이므로 인자를 한 개 입력함
speakable.speak("안녕하세요");
}
}
package ch16.sec03;
import java.util.jar.Attributes.Name;
public class LamdaExmaple {
public static void main(String[] args) {
Person person = new Person();
// 매개변수가 두 개일 경우
// 람다식에서는 타입을 신경쓰지 않기 때문에
// 인자의 갯수만 맞춰서 매개변수를 적어주기만 해도 됨
// 매개변수가 두 개 이상일 경우 매개변수를 괄호에 감싸서 표기해줘야 함!
person.action1((name, job) -> {
System.out.println(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 + "\" 라고 외칩니다."));
}
}
package ch16.sec04;
@FunctionalInterface
public interface Calculable {
// double 형태의 리턴값을 가지는 추상 메소드
double calc(double x, double y);
}
package ch16.sec04;
public class Person {
// 외부에서 인터페이스 구현 객체를 매개변수로 받아
// 이를 인터페이스 필드에 대입시킴
public void action(Calculable calculable) {
double result = calculable.calc(10, 4);
System.out.println("결과: " + result);
}
}
package ch16.sec04;
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) -> x - y);
// 정적 메소드를 사용하고, 실행문이 하나인 경우
person.action((x, y) -> sum(x,y));
}
public static double sum(double x, double y) {
return x+y;
}
}
package ch16.sec05.exam01;
//@FunctionalInterface : 람다식으로 사용할 수 있는 인터페이스인지 판단
@FunctionalInterface
public interface Calculable {
// double 타입 추상 메소드 선언
double calc(double x, double y);
}
package ch16.sec05.exam01;
public class Person {
// Calculable 인터페이스를 구현할 객체를 매개변수로 사용
public void action(Calculable calculable) {
// Calculable 인터페이스의 calc 메소드 실행!
double result = calculable.calc(10, 4);
System.out.println("결과: " + result);
}
}
package ch16.sec05.exam01;
public class Computer {
// 정적 기본타입 메소드
public static double staticMethod(double x, double y) {
return x + y;
}
// 인스턴스 기본타입 메소드
public double instanceMethod(double x, double y) {
return x * y;
}
}
package ch16.sec05.exam01;
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);
}
}
// 구조
(a, b) -> { a.instanceMethod(b); }
package ch16.sec05.exam02;
@FunctionalInterface
public interface Comparable {
int compare(String a, String b);
}
package ch16.sec05.exam02;
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 + "보다 뒤에 옵니다.");
}
}
}
package ch16.sec05.exam02;
// 소유권은 본인 거
public class MethodReferenceExample {
public static void main(String[] args) {
Person person = new Person();
// a의 멤버함수가 b를 매개변수로 가지는 람다식
// 인자가 모두 사용되었을 경우 인자를 모두 생략이 가능
person.ordering((a,b) -> a.compareToIgnoreCase(b));
// compareToIgnoreCase : 대소문자 구분하지 않음
// compareTo : 두 인자의 크기 비교 여부를 확인
// compareToIgnoreCase : 대소문자 구분하지 않고 두 인자의 크기 비교 여부를 확인
// 참조 메소드 해석을 위해서는 해당 메소드로 이동해보기
// 위의 구문과 동일함
person.ordering(String :: compareToIgnoreCase);
}
}
객체를 생성하는 것
람다식이 단순히 객체를 생성하고 리턴하도록 구성하면 람다식을 생성자 참조로 대치가 가능함
구조 : 클래스명 :: new
생성자가 오버로딩 되어 여러 개가 있을 경우
-> 컴파일러는 함수형 인터페이스의 추상 메소드와 동일한 매개변수 타입과 개수를 가지고 있는 생성자를 찾아 실행함
-> 해당 생성자가 존재하지 않으면 컴파일 오류 발생
package ch16.sec05.exam03;
@FunctionalInterface
public interface Creatable1 {
public Member create(String id);
}
package ch16.sec05.exam03;
@FunctionalInterface
public interface Creatable2 {
public Member create(String id, String name);
}
package ch16.sec05.exam03;
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.sec05.exam03;
public class Person {
public Member getMember1(Creatable1 creatable) {
// 인터페이스 등록 및 Creatable1 객체 사용
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.sec05.exam03;
public class ConstructorReferenceExample {
public static void main(String[] args) {
Person person = new Person();
// id 인자를 사용하여 Member 객체를 생성하여 리턴한다
Member m11 = person.getMember1(id -> new Member(id));
// 위의 코드와 같음
// 인자가 동일하기 때문에 생략이 가능
Member m1 = person.getMember1( Member :: new );
System.out.println(m1);
System.out.println();
Member m21 = person.getMember2((id, name) -> new Member(id, name));
// id 인자와 name 인자를 사용하여 Member 객체를 생성하여 리턴함
Member m2 = person.getMember2( Member :: new );
System.out.println(m2);
}
}