람다식은 함수형프로그래밍 기법을 지원하는 자바의 문법요소이다.
//기존 메소드 표현 방식
void sayHello(){
System.out.println("Hello")
}
//위의 코드를 람다식으로 표현한 식
() -> System.out.println("Hello")
이렇게 반환타입이나 이름을 생략할수 있다. 따라서 익명 함수라고 부르기도 한다.
//sum 메소드
int sum(int num1, int num2){
return num1+num2;
}
//이걸 이렇게 반환타입,메소드 명 제거,화살표추가
(int num1, int num2) ->{
return num1+num2;
}
//더 축약하면 메소드 바디에 문장이 실행문 하나만 존재할 때 우리는 중괄호,return 문을 생략할수 있다, 세미콜론도 생략해야한다.
(int num1, int num2) ->num1+ num2
//매개변수 타입을 함수형 인터페이스를 통해 유추할수 있다면 매개변수 타입도 생략할수 있다.
(num1,num2) ->num1+num2
public class LamdaExample1 {
public static void main(String[] args) {
/* Object obj = new Object() {
int sum(int num1, int num2) {
return num1 + num1;
}
};
*/
ExampleFunction exampleFunction = (num1, num2) -> num1 + num2;
System.out.println(exampleFunction.sum(10,15));
}
@FunctionalInterface // 컴파일러가 인터페이스가 바르게 정의되었는지 확인하도록 합니다.
interface ExampleFunction {
int sum(int num1, int num2);
}
// 출력값
25
저 인터페이스는 람다식을 참조할 참조변수를 선언할 때, 타입으로 사용하기 위해 필요하다.
@FunctionalInterface 이건 컴파일러가 인터페이스를 확실히 식별시키기 위한 애너테이션이다.
@FunctionalInterface
public interface MyFunctionalInterface {
void accept();
}
MyFunctionalInterface example = ()->{~~~}
example.accept();
매개변수와 리턴값이 없는 인터페이스는 이런 형태로 작성해야한다.
@FunctionalInterface
public interface MyFunctionalInterface {
void accept(int x);
}
public class MyFunctionalInterfaceExample {
public static void main(String[] args) throws Exception {
MyFunctionalInterface example;
example = (x) -> {
int result = x * 5;
System.out.println(result);
};
example.accept(2);
example = (x) -> System.out.println(x * 5);
example.accept(2);
}
}
// 출력값
10
10
매개변수가 있고 리턴값이 없는 인터페이스의 타입 람다식은 이런 형태이다.
@FunctionalInterface
public interface MyFunctionalInterface {
int accept(int x, int y);
}
//리턴타입이 있기때문에 return문이 있어야하며,특정 경우엔 중괄호,return문 생략 가능하다.
public class MyFunctionalInterfaceExample {
public static void main(String[] args) throws Exception {
MyFunctionalInterface example;
example = (x, y) -> {
int result = x + y;
return result;
};
int result1 = example.accept(2, 5);
System.out.println(result1);
example = (x, y) -> { return x + y; };
int result2 = example.accept(2, 5);
System.out.println(result2);
example = (x, y) -> x + y;
//return문만 있을 경우, 중괄호 {}와 return문 생략가능
int result3 = example.accept(2, 5);
System.out.println(result3);
example = (x, y) -> sum(x, y);
//return문만 있을 경우, 중괄호 {}와 return문 생략가능
int result4 = example.accept(2, 5);
System.out.println(result4);
}
public static int sum(int x, int y){
return x + y;
}
}
//출력값
7
7
7
7
//Math 클래스의 max() 메소드를 호출하는 람다식
(left,right) -> Math.max(left,rigth)
이걸 메소드 참조를 이용하면
//클래스이름::메소드이름
Math :: max
클래스::메소드
클래스 이름 뒤에 ::기호 붙이고 정적 메소드 이름을 기술한다.
참조 변수 ::메소드
객체를 생성한 다음 참조변수 뒤에 ::기호 붙이고 인스턴스 메소드 이름을 기술한다.
예제로 비교해보면
//IntBinaryOperator 인터페이스는 두 개의 int 매개값을 받아 int 값을 리턴하므로, int 형식의 메서드 참조를 대입할 수 있습니다.
//Calculator.java
public class Calculator {
public static int staticMethod(int x, int y) {
return x + y;
}
public int instanceMethod(int x, int y) {
return x * y;
}
}
import java.util.function.IntBinaryOperator;
public class MethodReferences {
public static void main(String[] args) throws Exception {
IntBinaryOperator operator;
/*정적 메서드
클래스이름::메서드이름
*/
operator = Calculator::staticMethod;
System.out.println("정적메서드 결과 : " + operator.applyAsInt(3, 5));
/*인스턴스 메서드
인스턴스명::메서드명
*/
Calculator calculator = new Calculator();
operator = calculator::instanceMethod;
System.out.println("인스턴스 메서드 결과 : "+ operator.applyAsInt(3, 5));
}
}
/*
정적메서드 결과 : 8
인스턴스 메서드 결과 : 15
*/
클래스 이름 뒤에 ::기호를 붙이고 new 연산자를 기술한다.
만약 생성자가 여러개 있을경우 컴파일러가 함수형 인터페이스의 추상 메소드와 동일한 매개변수 타입과 개수를 가지고 있는 생성자를 찾아 실행한다.
(a,b) -> new 클래스(a,b)
//이걸 이렇게 할수 있다
//생성자 참조 문법
클래스 :: new
//Member.java
public class Member {
private String name;
private String id;
public Member() {
System.out.println("Member() 실행");
}
public Member(String id) {
System.out.println("Member(String id) 실행");
this.id = id;
}
public Member(String name, String id) {
System.out.println("Member(String name, String id) 실행");
this.id = id;
this.name = name;
}
public String getName() {
return name;
}
public String getId() {
return id;
}
}
import java.util.function.BiFunction;
import java.util.function.Function;
public class ConstructorRef {
public static void main(String[] args) throws Exception {
Function<String, Member> function1 = Member::new;
Member member1 = function1.apply("kimcoding");
BiFunction<String, String, Member> function2 = Member::new;
Member member2 = function2.apply("kimcoding", "김코딩");
}
}
/*
Member(String id) 실행
Member(String name, String id) 실행
*/
생성자 참조를 이용해 두가지 방법으로 Menber 객체를 생성하고 있다.
1. Function<String,Member> 함수형 인터페이스의 Member apply(String)메소드를 이용해 Member 객체를 생성한다.
2. BiFunction<String String,Member>함수형 인터페이스의 Member 객체를 생성한다.