(매개변수) -> {실행문};
(int a) -> { System.out.println(a); } // 매개 변수 a의 값을 출력
(a) -> { System.out.println(a); }
a -> System.out.println(a);
(x, y) -> { return x + y; }
(x, y) -> x + y //중괄호 생략
//기존 메서드
int add(int a, int b) {
return a+b
}
//람다식
(a,b) -> a+b;
//예문1
int add(int x, int y) {
return x + y;
}
// 위의 메서드를 람다 표현식을 이용해 아래와 같이 단축 시킬수 있다. (메서드 반환 타입, 메서드 이름 생략)
(int x, int y) -> {
return x + y;
};
// 매개변수 타입도 생략 할 수 있다.
(x, y) -> {
return x + y;
};
// 함수에 리턴문 한줄만 있을 경우 더욱 더 단축 시킬 수 있다. (중괄호, return 생략)
(x, y) -> x + y;
타입을 생략해도 오류가 안 나는 이유는 컴파일러가 생략한 타입 위치를 추론해서 동작하기 때문이다.
예문2
interface MyFunction {
void print(String str);
}
public class Main {
public static void main(String[] args) {
MyFunction myfunc = (str) -> System.out.println(str);
myfunc.print("Hello World");
}
}
MyFunction myfunc = (str) -> System.out.println(str);
myfunc.print("Hello World"); 부분을 보면, 함수식을 변수에 대입해서 변수에서 함수를 호출해서 사용한 것을 확인 할 수 있다. 즉, 자바는 메서드를 단독으로 선언하는 것이 아니라, 항상 클래스의 구성 멤버로 선언하기 때문에 메서드를 가지고 있는 객체를 생성해 낸다고 볼 수 있다.
인터페이스 변수 = 람다식;
위 식을 통해, 람다식은 인터페이스의 익명 구현 객체를 생성한다는 뜻이다.
인터페이스는 직접 객체화를 할 수 없으므로, 반드시 구현 클래스가 필요하다. 람다식은 익명 구현 클래스를 생석하고 동시에 객체화한다.
이 때, 인터페이스의 종류에 따라 람다식의 작성 방법이 달라지는데, 람다식이 대입되는 인터페이스를 람다식의 target type이라고 한다.
하나의 추상 메소드가 선언된 인터페이스라면 람다식이 가능하다!!!!
단, 두 개 이상의 추상 메소드가 선언된 인터페이스는 람다식을 이용해서 구현 객체를 생성할 수 없다.
@FunctionalInterface 어노테이션을 써주면, 두 개이상의 메서드 선언시 컴파일 오류를 발생시킨다.
@FunctionalInterface
public interface MyFunctionalInterface {
public void method();
public void otherMethod(); // 컴파일 오류 발생
}
본래 list를 만들고, 각각의 요소에 대해서 반복문을 통해 접근한다.
하지만, 람다식을 이용하면, 아래 3가지 방법으로 간편하게 접근이 가능하다.
package javaplus.lamda;
import java.util.ArrayList;
import java.util.List;
public class LambdaTypeExam {
public static void main(String[] args) {
List<String>list = new ArrayList<>();
list.add("Java");
list.add("C");
list.add("React");
for (String s : list) {
System.out.println(s);
}
System.out.println();
list.stream().forEach((String s) -> System.out.println(s));
list.stream().forEach(s -> System.out.println(s));
list.stream().forEach(System.out::println);
//람다 표현식에서 list에 해당하는 것을 가져올 것이고, 해당 타입이 String이라고 추론이 가능하기 떄문에 String을 생략해도 된다.
}
}
1. 매개 변수와 리턴값이 없는 람다식
@FunctionalInterface
public interface MyFunctionalInterface {
public void method();
}
위와 같은 경우에는 아래와 같이 람다식을 작성한다.
MyFunctionalInterface fi = () -> { ... }
호출할 경우에는 아래와 같이 호출한다.
fi.method();
public class MyFinctionalInterfaceExample {
public static void main(String[] args) {
MyFunctionalInterface fi;
fi = () -> {
String str = "method call1";
System.out.println(str);
}
fi.method();
fi = () -> { System.out.println("method call2"); };
fi.method();
fi = () -> System.out.println("method call3");
fi.method();
}
}
2. 매개 변수가 있는 람다식
@FunctionalInterface
public interface MyFunctionalInterface {
public void method(int x);
}
위와 같은 경우에는 아래와 같이 람다식을 작성한다.
MyFunctionalInterface fi = (x) -> { ... } 또는 x -> { ... }
호출할 경우에는 아래와 같이 호출한다.
fi.method(5);
public class MyFinctionalInterfaceExample {
public static void main(String[] args) {
MyFunctionalInterface fi;
fi = (x) -> {
int result = x * 5;
System.out.println(result);
}
fi.method(2);
fi = (x) -> { System.out.println(x*5); };
fi.method(2);
fi = x -> System.out.println(x*5);
fi.method(2);
}
}
3. 리턴값이 있는 람다식
//매개 변수와 리턴값이 있는 추상 메서드를 가진 인터페이스
@FunctionalInterface
public interface MyFunctionalInterface {
public int method(int x, int y);
}
위의 인터페이스는 아래와 같이 람다식을 적는다.
MyFunctionalInterface fi = (x,y) -> { ...; return 값; }
람다식 호출은 아래와 같이 한다.
int result = fi.method(2, 5);
public class MyFinctionalInterfaceExample {
public static void main(String[] args) {
MyFunctionalInterface fi;
fi = (x, y) -> {
int result = x + y;
return result;
}
System.out.println(fi.method(2, 5));
fi = (x, y) -> { return x + y; };
System.out.println(fi.method(2, 5));
fi = (x, y) -> x + y;
System.out.println(fi.method(2, 5));
fi = (x,y) -> sum(x + y);
System.out.println(fi.method(2, 5));
public static int sum(int x, int y) {
return (x + y);
}
}
}
람다 함수가 정의된 위치에서 외부 변수를 참조하는 것을 말한다.
1.지역 변수(변경 불가능/읽기 가능)
2.인스턴스 변수
3.정적 변수
이 중에서 지역 변수만 변경이 불가능하고, 나머지는 람다 내부에서 읽기/쓰기 모두 가능하다.
Method Reference(메서드 참조)
(left, right) -> Math.max(left, right);
위 코드는 두 개의 값을 받아서 큰 수를 리턴하는 Math 클래스의 max() 함수를 호출하는 코드이다.
이는 단순히 두 개의 매개변수 값을 함수에 전달하는 것이기 때문에, 아래와 같이 간소화할 수 있다.
Math::max;
Method Reference는 람다식처럼 인터페이스의 익명 구현 객체로 생성되기 때문에, 인터페이스의 추상 메서드가 어떤 매개변수이며, 리턴 타입이 무엇이냐에 따라 달라지게 된다.
1. 정적 메서드와 인스턴스 메서드 참조
//정적 메서드
클래스 :: 메소드
//참조 메서드
참조변수 :: 메소드
2. 매개변수의 메서드 참조
(a, b) -> { a.instanceMethod(b); }
a 매개변수의 함수를 호출해서 b 매개변수를 instanceMethod의 매개변수 값으로 사용한다.
이를 MethodReference로 바꾸면 이렇다.
클래스 :: instanceMethod
a 클래스 이름 뒤에 ::를 붙이고 메서드 이름을 적으면 된다.
3. 생성자 참조(=객체 생성)
(a, b) -> { return new 클래스(a,b); }
위 코드는 객체를 생성하고 리턴하도록 구성된 람다식이다.
클래스 :: new
이는 위와 같이 생성자 참조로 대치된다.
//생성자가 오버로딩되어 여러 개 있는 경우, 컴파일러는 functional Interface의 추상 메서드와 동일한 매개 변수의 type과 개수를 가지고 있는 생성자를 찾아 실행한다.
생성자가 존재하지 않는다면, 컴파일 오류가 발생한다.
출처: https://github.com/yeGenieee/java-live-study/blob/main/[15]Java%20Live%20Study.md