[JAVA 스터디] 15주차 과제 : 람다식

2021. 3. 3. 22:15·Live Study
728x90
반응형

목표

자바의 람다식에 대해 학습하기

 

스터디 목차

  • 람다식 사용법
  • 함수형 인터페이스
  • Variable Capture
  • 메소드, 생성자 레퍼런스

 

 

1. 람다식 사용법

 

람다식 이란?

 

자바 8부터는 객체지향 프로그래밍과 함수적 프로그래밍을 혼합할 수 있게 람다식을 제공한다.

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

 

람다식 예제

 

일반적인 plus 메서드를 람다식으로 바꿔보기

int plus(int x, int y){
   return x+y;
}

 

우선 람다식은 메서드 이름과 반환 타입을 제거할 수 있다.

또한, 반환값이 있는 경우 return 키워드 대신에 식으로 대신할 수 있다. (식의 연산결과가 반환값이 되므로 세미콜론 생략)

그리고 함수 몸체 {} 괄호 안에 한 문장일 경우 괄호 또한 생략할 수 있다.

(int x, int y) -> x + y

그리고 람다식에 선언된 매개변수 타입은 추론이 가능한 경우 생략할 수 있다.

(x, y) -> x + y

 

 

 

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

 

함수형 인터페이스는 단 하나의 추상 메소드만이 선언된 인터페이스 이다.

 

MyFunction 인터페이스는 다음과 같이 정의되어 사용될 수 있다.

MyFunction f = new MyFunction() {
                   public int plus(int x, int y) {
                        return x + y;
                   }
              };
f. plus(1,2);

 

이때, MyFunction 인터페이스에 정의된 plus 메서드를 다음과 같이 람다식으로 표현할 수 있다.

MyFunction f = (int x, int y) -> x + y;
f.plus(1,2);

MyFunction 인터페이스를 구현한 익명 객체를 람다식으로 표현할 수 있는 이유는 람다식도 사실 익명 객체이고,

인터페이스를 구현한 익명 객체의 메서드 plus와 람다식이 매개변수 타입, 개수, 반환값이 일치하기 때문이다.

 

반드시 함수형 인터페이스에는 오직 하나의 추상 메서드만 정의되어 있어야한다.

왜냐하면 람다식과 인터페이스의 메서드가 1:1로 연결되어야 하기 때문이다.

 

 

 

3. Variable Capture

 

람다의 바디에서는 파라미터 말고 바디 외부에 있는 변수를 참조할 수 있다.

 

public class LambdaCapturing {
    private int a = 12;

    public void test() {
        int b = 123;

        final Runnable r = () -> System.out.println(a);

        final Runnable r2 = () -> System.out.println(b);
    }
}

이렇게 람다 시그니처의 파라미터로 넘겨진 변수가 아닌 외부에서 정의된 변수를 자유 변수라고 부른다.

또한 람다 바디에서 자유변수를 참조하는 행위를 람다 캡처링(Lambda Capturing)이라고 부른다.

 

람다 캡처링의 제약조건

  • 지역변수는 final로 선언되어 있어야한다.
  • final로 선언되지 않은 지역변수는 final처럼 동작해야한다. (즉, 값의 재할당이 일어나면 안된다.)
public class LambdaCapturing {
    private int a = 12;

    public void test() {
        final int b = 123;
        int c = 123;
        int d = 123;

        final Runnable r = () -> {
            // 인스턴스 변수 a는 final로 선언돼있을 필요도, final처럼 재할당하면 안된다는 제약조건도 적용되지 않는다.
            a = 123;
            System.out.println(a);
        };

        // 지역변수 b는 final로 선언돼있기 때문에 OK
        final Runnable r2 = () -> System.out.println(b);

        // 지역변수 c는 final로 선언돼있지 않지만 final을 선언한 것과 같이 변수에 값을 재할당하지 않았으므로 OK
        final Runnable r3 = () -> System.out.println(c);
        
        // 지역변수 d는 final로 선언돼있지도 않고, 값의 재할당이 일어났으므로 final처럼 동작하지 않기 때문에 X
        d = 12;
        final Runnable r4 = () -> System.out.println(d);
    }
}

 

왜??

 

JVM에서 지역변수는 스택에 생성된다. 그리고 실제 메모리 와는 달리 JVM에서 스택 영역은 쓰레드마다 별도의 스택이 생성된다. 따라서 지역변수는 쓰레드끼리 공유가 안 된다.

 

JVM에서 인스턴스 변수는 힙 영역에 생성된다. 인스턴스 변수는 쓰레드끼리 공유가 가능하다.

 

람다는 별도의 쓰레드에서 실행이 가능한데 원래 지역 변수가 있는 쓰레드는 사라져서 해당 지역변수가 사라졌는데도 불구하고, 람다가 실행 중인 쓰레드는 살아있을 가능성이 있다.

 

람다에서는 지역변수(해당 쓰레드의 스택)에 직접적으로 접근하는게 아니라 변수를 자신(쓰레드)의 스택에 복사하기 때문에 해당 지역변수가 사라진다고 에러는 나지는않지만 위와 같이 변수를 복사해서 쓰는데 그 변수의 값이 중구난방으로 변경된다고 하면 해당 복사본을 믿고 쓸 수 없다.

 

따라서 지역 변수에는 final이어야 하거나 final 같이 동작해야한다는 제약조건이 생긴 것이다.

 

그렇다면 인스턴스 변수는 왜 이런 조건이 없는걸까?

이는 인스턴스 변수는 힙에 존재하고, 쓰레드끼리 공유도 가능하기 때문에 별도로 복사할 필요도 없고, 직접 힙에 접근해서 사용하면 되기 때문이다.

 

 

 

4. 메소드, 생성자 레퍼런스

 

메서드 레퍼런스

메서드 레퍼런스는 람다 표현식이 단 하나의 메서드만을 호출하는 경우에 해당 람다 표현식에서 불필요한 매개변수를 제거하고 사용할 수 있도록 해준다.

메서드 레퍼런스는 메서드명 앞에 구분자(::)를 붙이는 방식으로 사용된다.

 

Method Reference를 만드는 유형에는 다음 3가지가 있다.

 

(1) 정적 메서드 참조 레퍼런스 : Integer의 parseInt 메서드는 Integer::parseInt

(2) 다양한 형식의 인스턴스 메서드 레퍼런스 : String의 length 메서드는 String::length

(3) 기존 객체의 인스턴스 메서드 레퍼런스 : Car 객체를 할당받은 bmw 지역변수가 있고, Car객체에는 getPrice라는 메서드가 있다면 bmw::getPrice라고 표현할 수 있다.

 

예제를 바탕으로 다시 보면

(1) 정적메서드 레퍼런스

- 파라미터로 전달받은 변수의 메서드를 사용하지 않고, 정적 메서드의 인자로 사용됨

 

(2) 다양한 형식의 인스턴스 메서드 레퍼런스

- 파라미터로 전달받은 변수의 메서드를 사용함

 

(3) 기존 객체의 인스턴스 메서드 레퍼런스

- 1번과 비슷한데 차이점이라면 정적 메서드의 인자가 아닌 기존에 이미 생성된 인스턴스의 인자로 사용된다.

 

 

생성자 레퍼런스

 

생성자를 호출하는 람다 표현식도 앞서 살펴본 메서드 참조를 이용할 수 있다.

즉, 단순히 객체를 생성하고 반환하는 람다 표현식은 생성자 참조로 변환할 수 있다.

 

다음 예제는 단순히 객체를 생성하고 반환하는 람다 표현식이다.

(a) -> { return new Object(a); }

 

위의 예제는 단순히 Object 클래스의 인스턴스를 생성하고 반환하기만 하므로, 생성자 참조를 사용하여 다음과 같이 간단히 표현할 수 있다. 

Object::new

 

 

이때 해당 생성자가 존재하지 않으면 컴파일시 오류가 발생한다.

 

또한, 배열을 생성할 때에도 다음과 같이 생성자 참조를 사용할 수 있다.

Function<Integer, double[]> func1 = a -> new double[a]; // 람다 표현식
Function<Integer, double[]> func2 = double[]::new;      // 생성자 참조

 

 

 

 

Reference


inma.tistory.com/150

 

[Java] 람다(Lambda)

본 시리즈에서는 Java8에 추가된 람다식과 함수형 프로그래밍에대해 알아봅니다. Java8부터 람다식이 추가되면서 Java는 객체지향언어인 동시에 함수형 언어의 기능까지 갖추게 되었습니다. 함수

inma.tistory.com

perfectacle.github.io/2019/06/30/java-8-lambda-capturing/

 

(Java) 람다 캡처링과 final 제약조건

람다의 바디에서는 파라미터 말고 바디 외부에 있는 변수를 참조할 수 있다. 1234567891011public class LambdaCapturing { private int a = 12; public void test() { int b = 123; final Runnable r = () -> S

perfectacle.github.io

countryxide.tistory.com/127

 

[Java8] Method Reference (메서드 참조) - 생성 방법

Method Reference를 이해하려면 Lambda를 먼저 이해해야한다. 여기서는 Lambda식을 Method Reference로 변경하는 방법을 다룬다. Lambda식을 사용하다보면 IDE에서 친절하게 노란색으로 Method Reference로 바꾸지..

countryxide.tistory.com

 

www.tcpschool.com/java/java_lambda_reference

 

코딩교육 티씨피스쿨

4차산업혁명, 코딩교육, 소프트웨어교육, 코딩기초, SW코딩, 기초코딩부터 자바 파이썬 등

tcpschool.com

 

반응형
저작자표시 (새창열림)

'Live Study' 카테고리의 다른 글

[JAVA 스터디] 14주차 과제 : 제네릭  (0) 2021.02.24
[JAVA 스터디] 13주차 과제 : I/O  (0) 2021.02.08
[JAVA 스터디] 12주차 과제 : 애노테이션  (0) 2021.02.01
[JAVA 스터디] 11주차 과제 : Enum  (0) 2021.01.25
[JAVA 스터디] 10주차 과제 : 멀티쓰레드 프로그래밍  (0) 2021.01.19
'Live Study' 카테고리의 다른 글
  • [JAVA 스터디] 14주차 과제 : 제네릭
  • [JAVA 스터디] 13주차 과제 : I/O
  • [JAVA 스터디] 12주차 과제 : 애노테이션
  • [JAVA 스터디] 11주차 과제 : Enum
wookcode
wookcode
공부한 내용들을 정리하고 기록하는 블로그입니다.
    반응형
  • wookcode
    wookcode
    wookcode
  • 전체
    오늘
    어제
    • 카테고리 (196)
      • study (1)
        • 아파치 카프카 애플리케이션 프로그래밍 with 자.. (0)
        • 인프런 (1)
      • Live Study (15)
      • Programming (14)
        • Java (8)
        • Python (1)
        • Springboot (5)
        • MSA (0)
      • 알고리즘 (117)
        • 백준 (58)
        • 프로그래머스 (59)
      • 에러로그 (5)
      • 항해99 (23)
      • 면접 (1)
      • 프로젝트 (1)
      • CS (19)
        • 네트워크 (2)
        • 운영체제 (2)
        • 데이터베이스 (2)
        • 컴퓨터구조 (1)
        • Java (8)
        • Spring (4)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    정리
    orm
    조합
    괄호
    에러
    SpringBoot
    미니프로젝트
    알고리즘
    김영한
    항해99
    회고
    java
    브루트포스
    카카오코딩테스트
    jpa
    스파르타코딩클럽
    프로그래머스
    그리디
    실전프로젝트
    카카오인턴
    인프런
    코딩테스트
    SFlash
    버그
    spring
    백준
    해결
    항해마켓
    후기
    파이썬
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
wookcode
[JAVA 스터디] 15주차 과제 : 람다식
상단으로

티스토리툴바