[Android] RxJava (5) - lambda

Oxong·2021년 8월 5일
0

21.08.03
공부한 것을 정리하는 용도의 글이므로 100% 정확하지 않을 수 있습니다.
참고용으로만 봐주시고, 내용이 부족하다고 느끼신다면 다른 글도 보시는 것이 좋습니다.
+ 틀린 부분, 수정해야 할 부분은 언제든지 피드백 주세요. 😊
                                            by. ryalya




들어가기 전

기존의 자바는 인터페이스(interface)를 만들고, 인터페이스를 구현한 class를 생성하여 작성해놓은 후, 사용할 때는 참조변수에 class 객체를 불러와 사용한다.

하지만 람다식은 인터페이스 참조변수에 람다식을 바로 대입하여 사용한다.


람다 함수(Lambda Function)


람다(lambda)식이란?


람다 함수는 함수형 프로그래밍 언어에서 사용되는 개념으로 익명 함수(Anonymous functions)를 말한다.

함수를 람다식으로 표현하면 메소드의 이름이 필요 없는데, 함수를 따로 만들지 않고, 코드 한 줄 안에서 함수를 사용하여 호출하는 방식이기 때문이다.

예를 들어 우리는 메소드를 아래 예시 처럼 사용한다.

<예시 - 메소드 >
int min(int x, int y) {
    return x < y ? x : y;
}

하지만 람다 함수로 위의 메소드를 표현하면

<예시 - 람다>
(x, y) -> x < y ? x : y;

이렇게 간결하게 표현할 수 있다.

람다 함수는 Java8부터 지원되며, 불필요한 코드를 줄이고 가독성을 향상시키는 것을 목적으로 두고 있다.



람다(lambda)의 장점


- 코드의 간결성 → 생산성↑

- 지연연산 수행(연산 최소화)

- 가독성 ↑

- 병렬 처리 가능(멀티 쓰레드 활용)


람다(lambda)의 단점


- 무명함수의 재사용 불가능

- 단순 for문 혹은 while문 사용 시 성능↓

- 람다 함수를 과다하게 사용 시, 가독성↓ 스파게티 코드 가능성↑



람다(lambda)식 작성법


람다식은 메서드의 매개변수로 전달될 수 있고, 메서드의 결과로 반환될 수 있다.

즉, 메서드를 변수처럼 다루는 것이 가능하다.

1. 메서드에서 이름과 반환타입 제거

2. 매개변수 선언부와 몸통{} 사이에 -> 추가

// 기존
반환타입 메서드이름 (매개변수 선언)  {
  ...
}

// 람다식
(매개변수 선언) ->  {
  ...
}

3. 반환값이 있는 메서드는 return 대신 식(expression)으로 대신할 수 있다.(연산 결과가 자동으로 반환값이 되고 ; 생략)

4. 매개변수의 타입은 추론가능하면 생략 가능 (대부분 생략 가능)

5. 두 매개변수 중 하나의 타입만 생략하는 것은 불가능

6. 매개변수가 하나뿐이면 괄호() 생략 가능

7. 중괄호{} 안의 문장이 하나일 때는 중괄호{} 생략 가능 (문장 끝에 ; 생략)

8. 중괄호{} 안의 문장이 return문일경우 중괄호{} 생략 불가능

// 기존
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();


람다(lambda) 사용 조건

  • @FunctionalInterface 어노테이션을 선언해야 한다.
  • 추상 메소드가 한 개만 선언되어야 한다.
  • interface로 선언되어야 한다.

그런데 함수형 프로그래밍에는 단점이 있다.
함수형 인터페이스 안에 선언된 메소드에 종속되는 람다식 밖에 구현할 수 없기 때문이다.

그래서 매개변수의 타입과 개수, 반환 값의 유무 등을 가진 메소드를 하나의 함수형 인터페이스로 구현할 수 없고, 필요한 동작에 따라서 함수형 인터페이스를 만들어줘야 한다.

Build.gradle 추가

안드로이드에서 람다식을 사용하려면 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해서 사용한다.


Functional Interface(함수형 인터페이스)

- Supplier〈T〉

: 매개 변수는 없고, 반환 값이 있는 함수형 인터페이스이다.
추상 메소드 T supplier()를 가진다.

- Consumer〈T〉

: 객체 T를 매개 변수로 받아서 소비한다. 반환 값은 없다.
추상메소드 void accpet(T t)를 가진다.

- Function〈T,R〉

: 객체 T를 매개 변수로 받아 처리 후 R로 반환한다.
추상메소드 R apply(T t)를 가진다.

- Predicate〈T〉

: 객체 T를 매개 변수로 받아 처리 후 Boolean으로 반환한다.
추상메소드 Boolean test(T t)를 가진다.

참고 : Oracle 공식 java doc


+) 테스트 내용 추가 필요

Reference

[Java]람다식(Lambda Expression)과 함수형 인터페이스(Functional Interface)

자바의 정석 - 람다식(Lambda Expression)

Java - Lambda Expression(람다식)이란?

Java 8 Lambda Expression - 람다식 #3

0개의 댓글