15장. 람다식

7 minute read

목표

자바의 람다식에 대해 학습하세요. issue

학습할 것

람다식이란?

람다식은 간단히 말해 메서드를 하나의 식(expression) 으로 표현한 것이다.

람다식은 함수를 간략하면서도 명확한 식으로 표현할 수 있게 해준다.

메서드를 람다식으로 표현하면 메서드의 이름과 반환값이 없어지므로, 람다식을 ‘익명 함수(anonymous function)’ 이라고도 한다.

모든 메서드는 클래스에 포함되어야 하므로 클래스를 새로 만들어야 하고, 객체도 생성해야 비로소 메서드를 호출할 수 있다. 그러나 람다식은 오직 람다식 자체만으로도 메서드의 역할을 대신할 수 있다.

람다식은 메서드의 매개변수로 전달되어지는 것이 가능하고, 메서드의 결과로 반환될 수도 있다.

람다식 사용법

형태

Type methodName(parameter...) {
    ...
}
---

(paramether...) -> {
    ...
}

예시

Integer max(int a, int b) {
    return a > b ? a : b;
}
---

(int a, int b) -> {
    return a > b ? a : b;
}

(int a, int b) -> a > b ? a : b;

함수형 인터페이스

자바에서 모든 메서드는 클래스 내에 포함되어야 하는데, 람다식은 어떤 클래스에 포함되는 것일까? 람다식이 메서드와 동등한 것이라고 생각했지만, 사실 람다식은 익명 클래스의 객체와 동등하다.

타입 f = (int a, int b) -> a > b ? a : b;
---

interface MyFunction {
    public abstract int max(int a, int b);
}

MyFunction f = new MyFunction() {
                      public int max(int a, int b) {
                          return a > b ? a : b;
                      }
              };

int big = f.max(5, 3);

MyFunction 인터페이스에 정의된 메서드 max()는 람다식 (int a, int b) -> a > b ? a : b;와 메서드의 선언부가 일치한다. 따라서 익명 객체를 람다식으로 대체할 수 있다.

MyFunction f = (int a, int b) -> a > b ? a : b;
int big = f.max(5, 3);

위에서 말한 것처럼 람다식은 익명 클래스의 객체와 동등하고 그러기 때문에 익명 객체의 매서드를 람다식으로 바로 대체할 수 있는 것이다. 이렇게 인터페이스를 통해서 람다식을 다루는 인터페이스를 ‘함수형 인터페이스’라고 부른다.

기본적으로 함수형 인터페이스는 오직 하나의 추상 메서드만 정의되어 있어야 한다는 제약이 있다. @FunctionalInterface을 사용하는 경우 컴파일 단계에서 확인해준다.

Variable Capture

익명 구현 객체를 포함해 객체를 만드는 행위를 진행하면서 new라는 키워드를 사용하게 된다. 그 과정에서 해당 데이터는 heap에 저장되게 된다.

하지만 그 익명 구현 객체를 사용하면서 로컬 변수를 사용하는 경우가 존재한다. 그 로컬 변수는 stack에 저장되게 되고 해당 함수가 끝나게 되면 해당 데이터는 메모리에서 참조를 할 수 없다.

그런 문제를 해결하기 위해서 자바에서는 Variable Capture를 통해서 해결하도록 한 것이다.

로컬 변수 챕쳐

Local variable은 조건이 final 또는 effectively final이어야 한다.

effectively final은 Java 8에 추가된 syntatic sugar의 일종으로 초기화된 이후 값이 한번도 변경되지 않았다는 것을 말한다.

final이어야 할까? 그 이유는 힙 영역에 있는 데이터들은 여러 쓰레드들이 접근할 수 있고 그러다보니 동시성에 대한 문제가 발생할 수 있다. 그러다보니 한번 선언 이후에 변경할 수 없는, 혹은 변경이 없는 변수만 사용이 가능한 것이다.

메소드, 생성자 레퍼런스

람다식을 더욱 간결하게 표현할 수 있는 방법이 있다.

메소드 레퍼런스

Function<String, Integer> f = (String s) -> Integer.parseInt(s);

Function<String, Integer> f = Integer::parseInt;
---
BiFunction<String, String, Boolean> f = (s1, s2) -> s1.equals(s2);

BiFunction<String, String, Boolean> f = String::equals;

기본적으로 받아내는 파라미터가 생략되며 해당 메소드에 인스턴스나 클래스와 실제 메소드이름을 ::을 사이에 두고 표현된다.

생산자 레퍼런스

Supplier<MyClass> s = () -> new MyClass();    
Supplier<MyClass> s = MyClass::new;

---

Function<Integer, MyClass> f = (i) -> new MyClass(i);    
Function<Integer, MyClass> f2 = MyClass::new;

매개변수가 필요한 생성자라면, 매개변수의 개수에 따라 알맞은 함수형 인터페이스를 사용하면 된다. 필요에 따라 함수형 인터페이스를 새로 정의해야 한다.

ref

야돈님의 블로그

라이브 방송

방송 전 토크

유독 비싼 강의가 있음. -> 많이 팔고 싶지 않은 강의이기 때문에.

여러분에게 요령만 줄 법만 한것들. 혹은 대중적으로 보면 안좋은 것들.

강의를 보면 요령을 얻을 수 있지만 그렇지 않기를 바라기에.

요령 부리지말고 정통파로 나가봅시다

책 추천

시작의 기술 (가볍게 읽기 좋음)

방송중

  • 익명 내부 클래스와 비슷하다고 하면 안됩니다~
    • 익명 내부 클래스는 $1 이런것들이 새로 생김.
  • 람다식 구현 자체가 다릅니다.
    • https://sujl95.tistory.com/76
      • 이분이 어떻게 저기까지 갈 수 있었던 것인지. 사고의 흐름을 잘 파악했으면 좋겠다.
    • indy(INVOKEDYNAMIC CALL) 라는 것을 활용해서 만들어진다.
    • 스콥도 다르고 만들어지는 것도 다르고.
  • Variable Capture
    • https://blog.naver.com/hsm622/222260183401
      • JVM에 대해서 이해하고 있지 않았다면 해당 글을 이해하기 어려울 것이다.
      • 그래서 기본기가 중요함.

사람들이 정리한 것들을 보면 정말로 다들 잘한다. 다들 못하는게 아니고 잘한다고 생각한다.

  • 못하는 건가? 안하는 건가?
    • 힘들다고 안하는 거였던 것.
    • 그래서 결국 뒤쪽에서 정말 좋은 글들을 발견 했다.
    • 내 생각: 내가 어떤 것을 귀찮다고 할 때 단순히 하기 싫다 라고만 해서 무시했는데… 이런 생각 좋은 것 같다. 못하는 건가 안하는건가
    • 밑에 있는 인생 이야기와 연결됨
  • 함수형 인터페이스에 대한 별명
    • https://b-programmer.tistory.com/279
    • Function이 가장 여러곳에서 사용할 수 있는 경우이고 나머지는 약간 Function에 대한 구체적인 사례같은 경우
    • 별명까지 알면 좋죠 ㅎㅎㅎ
  • 메모스 레퍼런스
    Sring[] names = {"hi", "hello"};
    // Arrays.sort(naems, (o1, o2) -> o1.compareTo(o2));
    Arrays.sort(naems, String::CompareToIgnoreCase);
    

    위와 같이 클래스에 대한 메소드를 가저오는 것이 신기함. 위와 같은 메소드는 인자를 하나를 받아서 리턴하는 식. 그런데 (o1, o2) -> o1.compareTo(o2)는 2개를 받아서 사용하는데? 첫번째 o1에 대해서 메소드를 호출한 것 -> o1.compareToIgrenoCase(o2) 이 되는 것

  • 쉐도잉
    • https://www.notion.so/758e363f9fb04872a604999f8af6a1ae
    • 익명 클래스 구현체와 다른 쉐도잉
    • 람다는 람다 밖과 람다 안에 있는 것과 스콥이 같음. -> 변수명을 다르게 해야됨. (컴파일 ㄹ에러 발생)
    • 밖에 있는 변수를 가려버림. 그래서 밖에 있는 변수와 같이 해도 상관없음.
  • 왜? 어떻게? 를 계속 생각해서 공부하는 것

  • 맛집. 정리를 너무 잘하심
    • https://yadon079.github.io/2021/java%20study%20halle/week-15
    • 예습과 복습이 확실함.
    • 이런 모습을 꼭 배웠으면 좋겠다.
    • 람다식의 타입과 형변환.
    • 함수형 프로그래밍으로 하려고 한다면
    • 함수가 first class가 되어야한다. -> 일급 객체. 변수로 보내고 리턴으로 받고 파라미터로 사용할 수 있어야 한다.
  • 아주 깔끔
    • https://watrv41.gitbook.io/devbook/java/java-live-study/15_week
  • 지연 연산
    • https://velog.io/@kwj1270/Lambda
    • 비싼 연산. 비싼 객체 생성 작업을 뒤로 미룰 수 잇음.
    • 함수이다보다보니 콜백처럼 사용하는.
    • 필요한 순간에 함수를 호출하는 것이지 선언된 곳에서 코드가 작동하는 것이 아니기 때문에
    • 그런 방법을 활용할 수 있음.
  • 람다와 익명 내부 클래스 스콥 차이
    • https://www.notion.so/a875fcd046db4ddd8dce01bf61743f5e
    • 그림으로 눈에 딱 보임.
    • 이것이 쉐도잉. 그 딱 다 덮어버린다.
  • 매우 깔끔한 내용
    • https://parkadd.tistory.com/60
  • oracle 공식 문서 보는 것에 익숙해지면 정말 좋다!!!

  • first class function
  • 매우 인상깊음. 처음봄
    • https://www.notion.so/15-757106032d85452cbc60cf1808d53978
    • 인보크 다이나믹에 대해서 자세하게 설명해주심
    • LambdaMethodFactory를 활용하여 Reflection 대체하기. 이 부분이 매우 의아함.
    • 참고 링크: https://dzone.com/articles/java-reflection-but-faster
    • devil is in the details. -> 매우 개발이 어려운 상황.
  • 인생 이야기
    • 인생의 도움이 되는 거 말고. 금전적인 거. 인생에 직접적으로 도움되는 거 말고
    • 만약 누구를 만나면 밥을 사줘. 그러면 그 사람이 좋은 건가? 아니면 단순히
    • 근본적인 것을 건드려야 함.
    • 내게 지식, 혹은 가치관, 같이 뛰는 사람이 되어서 내가 돈을 주고 밥을 사줄 수 있는 사람이 되는 사람
    • 나를 자극시켜주고 당장의 이익을 주는 거 말고. 그런 사람 주변에 머물수 있도록 노력하세요.
    • 스터디 했던 거 맨날 이야기하지만 그 사람 덕분에 성장했고 모두 덕분에 성장했고.
    • 스터디 하는 사람들을 만나는 것이니까
    • 여러분이 누구를 만나고 어울리는 것이 정말로 중요하다.
    • 대학교 친구, 고등학교 친구. 왜 친구냐. 같은 공간에 있어서? 같은 동네라서? 정서적으로는 좋은 친구.
    • 인생을 발전시키려면 새로운 생각이나, 새로운 것을 봐야 됨.
    • 스터디하면서 정말로 센세이션이 일어난다고 해야되나. 볼 수가 없는 사람이었음.
    • 나이를 떠나서 본받을 사람들. 개발자를 떠나서.
    • 친구가 없다. 대학교 친구들 연락안함. 성격이 모나서 친구 없고. 친구 만드는데 관심도 없음.
    • 그런 선한 영향력이 있는 사람들에게 관심이있음.
    • 자수성과해서 성공한 사람들이 있음. 가진 거 너무 없이. 말도 안되게 살아오신 분이
    • 아무것도 없이 미국에 왔다. 인종차별을 받았고 살았어. 보호막이 되어줄 사람이 없어.
    • 언니가 불렀지만 벌써 그 사람은 미국사람이 되어버려서 얼마나 힘들었겠냐고
    • 그런데 지금은 회사도 가지고 있고 성공했고 주변사람들에게 엄청 베풀려고 한다. 필리핀에 도와주려고 뭔 일을 함. 헌옷 주려고 하고.
    • 그런 사람들 만나려면 어떻게 해야되나…? 사실 운이다.
    • 그런 운이 왜 유지가 되는지 아냐?
    • 여러분들이 그런 결에 맞기 때문이다. 어느정도는 그 결에 맞춰야된다. 그 사람들을 자주 볼수가 없다.
    • 그 결에 맞추는 것이 어려운 것이 아니다. 노력하면
    • 스터디를 했을 때 정말로 내가 스터디에 정말로 집중할 상황이었고 엄청나게 집중을 했으. 그러다보니까 그 때 스터디했던 형이 밥도 사주고 도와줬다고 생까한다.
    • 토비님을 만났을 때도 내가 블로깅했던 모습을 봤고 나도 쭈욱 해오다보니까 토비님하고 계속 인연이 되었던 것이다.
    • 내가 정말 스터디 했을 때는 그 사람들하고 열심히 했고 모두 성장해서 정말로 잘 되었다.
    • 못하는 게 아니고 안하는 것이다. 그냥 하면 된다.
    • 사람들이 그렇게 생각하지만 정말로 된다고 생각해서 이 생각까지 간다.
    • 못한다라고 생각하지마. 업무를 못한다고 절대 생까하면 안됨.
    • 못한다는 생각을 가지고 있는 사람하고 일하는게 너무 힘들다.
    • 개발자는 못한다는 없다.
    • yobi 개발할 때. 프론트 한분. 백앤드 개발이 프론트도 같이 하고 그럼. 개발하다보면 못한다는 생각
    • 코드리뷰를 할 때 깃헛은 라인별로 밖에 코드 리뷰를 못담.
    • 그런데 우리가 자랑했던 기능은 블락 단위, 혹은 멀티 블럭으로도 개발을 했었다.
    • 그 기능을 이야기하기 위해서 모두 모여서 회의했다. 그런데 이게 안된다고 하는것이다. 지금 상황으로는 안되겠지라는 이야기. 나는 이렇게 말함. “단지 지금 사고가 막혀있었기 때문에 안되는 것이라고 생각할 뿐이다.”
    • 그리고 노래를 틀었음. 라이언킹 노래. 그 노래를 틀었더니 리프레쉬가 된 것이다. 약간 웃긴게 된것이었다. 진지이야기하다가 같자기 웃긴 분위기.
    • 그러면서 회의를 웃기게 만들면서 할 수 있다. 그렇게 말하면서 회의 안에서 생각해 냈음. 결론은 할 수 있다로 끝났다. 실제로 구현도 했다.
    • 안한다와 못하다가 이렇게 큰 차이를 만든다.
    • 절대로. 절대로 못한다고 생각하지 말아라. 할 수 있다.
    • 나는 방법을 몰랐다. 나는 분위기 전환만 했고. 프론트 엔지니어 생각이 바뀜. 그 사람이 오히려 생각해내어서 문제를 해결했었다.
    • 이것 뿐만 아니라 많은 경우가 있다.
    • 나도 이렇게 말한다. 너무 효율이 안나오는 일은 못한다. 못한다는 말은 차마 나와 맞지 않지만 효율이 안좋다 혹은 우선순위가 높지 않다 이런말이 맞을 때가 많다.

베스트 글 모음

좋은 글! 여러가지 활용이 많음! -> https://www.notion.so/758e363f9fb04872a604999f8af6a1ae

Leave a comment