21.08.03
공부한 것을 정리하는 용도의 글이므로 100% 정확하지 않을 수 있습니다.
참고용으로만 봐주시고, 내용이 부족하다고 느끼신다면 다른 글도 보시는 것이 좋습니다.
+ 틀린 부분, 수정해야 할 부분은 언제든지 피드백 주세요. 😊
by. ryalya
들어가기 전
기존의 자바는 인터페이스(interface)를 만들고, 인터페이스를 구현한 class를 생성하여 작성해놓은 후, 사용할 때는 참조변수에 class 객체를 불러와 사용한다.
하지만 람다식은 인터페이스 참조변수에 람다식을 바로 대입하여 사용한다.
람다 함수는 함수형 프로그래밍 언어에서 사용되는 개념으로 익명 함수(Anonymous functions)를 말한다.
함수를 람다식으로 표현하면 메소드의 이름이 필요 없는데, 함수를 따로 만들지 않고, 코드 한 줄 안에서 함수를 사용하여 호출하는 방식이기 때문이다.
예를 들어 우리는 메소드를 아래 예시 처럼 사용한다.
<예시 - 메소드 >
int min(int x, int y) {
return x < y ? x : y;
}
하지만 람다 함수로 위의 메소드를 표현하면
<예시 - 람다>
(x, y) -> x < y ? x : y;
이렇게 간결하게 표현할 수 있다.
람다 함수는 Java8부터 지원되며, 불필요한 코드를 줄이고 가독성을 향상시키는 것을 목적으로 두고 있다.
람다식은 메서드의 매개변수로 전달될 수 있고, 메서드의 결과로 반환될 수 있다.
즉, 메서드를 변수처럼 다루는 것이 가능하다.
// 기존
반환타입 메서드이름 (매개변수 선언) {
...
}
// 람다식
(매개변수 선언) -> {
...
}
// 기존
int max(int a, int b) {
return a > b ? a : b;
}
// 람다식 기본 사용법
// (매개변수 타입) -> {};
(int a, int b) -> {
return a > b ? a : b;
}
// return문 대신 expression 사용
(int a, int b) -> a > b ? a: b
// 매개변수 타입 생략
// (매개변수)->{};
(a, b) -> a > b ? a : b
// 매개변수 1개일 경우 괄호 생략
a -> a*a // OK
int a -> a*a // 에러
// 본문 문장 1개일 경우 중괄호 생략
(String name, int i) -> System.out.println(name+"="+i)
// 매개변수가 없는 경우
// ()->{};
String str = () -> {System.out.println("매개 변수가 없는 경우")};
str.str();
그런데 함수형 프로그래밍에는 단점이 있다.
함수형 인터페이스 안에 선언된 메소드에 종속되는 람다식 밖에 구현할 수 없기 때문이다.
그래서 매개변수의 타입과 개수, 반환 값의 유무 등을 가진 메소드를 하나의 함수형 인터페이스로 구현할 수 없고, 필요한 동작에 따라서 함수형 인터페이스를 만들어줘야 한다.
안드로이드에서 람다식을 사용하려면 build.gradle(app)에 아래 코드를 추가해야 한다.
android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
@FunctionalInterface
interface MyFunction {
int calc(int x, int y);
}
lambdapractice.MyFunction sum = (x, y) -> {
return x+y;
};
Log.e("테스트", "sum : " + sum.calc(10, 20));
lambdapractice.MyFunction sub = (x, y) -> {
return x-y;
};
Log.e("테스트", "sub : " + sub.calc(30, 20));
}
<결과>
public void lambda() {
AtomicInteger base = new AtomicInteger(1000);
new Thread(() -> {
try {
Thread.sleep(1000);
base.set(1500);
} catch (Exception e){
}
}).start();
Log.e("테스트", "base >>>>>> " + base);
}
<결과>
lambda 내부에서 base에 값을 재할당 하더라도, lambda() 함수는 lambda를 실행하는 thread가 끝나기 전에 실행이 완료되어 stack 메모리에서 사라진다. 따라서 lambda 내부 지역변수가 바뀌지 않는다.(수정 불가) 따라서 람다 내부에서는 해당 함수를 참조만 할 수 있도록 해당 값을 capturing해서 사용한다. : 매개 변수는 없고, 반환 값이 있는 함수형 인터페이스이다.
추상 메소드 T supplier()를 가진다.
: 객체 T를 매개 변수로 받아서 소비한다. 반환 값은 없다.
추상메소드 void accpet(T t)를 가진다.
: 객체 T를 매개 변수로 받아 처리 후 R로 반환한다.
추상메소드 R apply(T t)를 가진다.
: 객체 T를 매개 변수로 받아 처리 후 Boolean으로 반환한다.
추상메소드 Boolean test(T t)를 가진다.
[Java]람다식(Lambda Expression)과 함수형 인터페이스(Functional Interface)
자바의 정석 - 람다식(Lambda Expression)