람다 표현식이란 무엇인가

gryoh·2022년 3월 7일
0

람다 표현식(Lambda Expressions)

함수형 프로그래밍을 하기 위해선 람다 표현식을 알아야 좋다. 람다 함수가 뭔지 알아보자

람다함수란 프로그래밍 언어에서 사용되는 개념으로 익명 함수(Anonymous functions)를 지칭하는 용어이다.

현재 사용되고 있는 람다의 근간은 수학과 기초 컴퓨터과학 분야에서의 람다 대수이고 람다 대수는 간단히 말하자면 수학에서 사용하는 함수를 보다 단순하게 표현하는 방법이다.

람다 함수란

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

람다 함수의 장단점

  • 장점
    - 숙련만 된다면 코드를 간결하게 줄일 수 있다.
    - 멀티스레드를 활용하여 병렬처리를 할 수 있다.
    - 사이드 이팩트가 없다. → 함수 밖에 있는 값을 변경할 수 없다.

  • 단점
    - 너무 많은 코드를 생략하다보니 가독성이 떨어질 수 있다.

이전에 람다 표현법을 사용하지 않을 때

1) 내부/로컬클래스

class TestClass {
    class LocalClass {
        public String hello(String name) {
            return name + "님";
        }
    }
}

2) 익명클래스

public static void main(String[] args) {
    WelcomeSomething welcomeSomething = new WelcomeSomething() {
        @Override
        public String hello(String name) {
            return name + "님";
        }
    };
    System.out.println(welcomeSomething.hello("GRYOH") + " Welcome");
}

람다 표현식 표현법

람다식은 매개변수 + 실행문으로 구성되어 있다

모양은 () -> {} //매개변수 : () , 실행문 : {}

첫 괄호에 인터페이스의 매개변수()를 입력하고 -> 를 입력하고 {}안에 실행할 코드를 작성하면 된다.

@FunctionalInterface
public interface WelcomeSomething {
    public String hello(String name);
}

@FunctionalInterface
public interface WelcomeDefaultSomething {
    public void hello(String name);
}
  • 사용법1)
    기본 사용법 : (매개변수 타입) -> {실행문}
WelcomeSomething welcomeSomething = (String name) -> { return name + "님"; };
System.out.println(welcomeSomething.printName("GRY") + " Welcome");
  • 사용법2)
    매개변수 타입 생략 : (매개변수) -> {실행문}
WelcomeSomething welcomeSomething = (name) -> { return name + "님"; };
System.out.println(welcomeSomething.printName("GRY") + " Welcome");
  • 사용법3)
    매개변수 없는 경우 : () -> {실행문}
    매개변수가 하나일 경우 매개변수를 생략 할 수 있다
WelcomeDefaultSomething welcomeDefaultSomething = () -> {
  System.out.println("임시회원님 Welcome");
};
welcomeDefaultSomething.hello();
  • 사용법4)
    중괄호 생략 : () -> 실행문
    함수몸체가 단일 실행문이면 괄호{}를 생략 할 수 있다
    함수몸체가 return문으로만 구성되어 있는 경우 괄호{}를 생략 할 수 없습니다.
WelcomeDefaultSomething welcomeDefaultSomething = () -> System.out.println("임시회원님 Welcome");
welcomeDefaultSomething.hello();
  • 사용법5)
    매개변수 괄호 생략 : 매개변수 -> 실행문
WelcomeSomething welcomeSomething = name -> name + "님";
System.out.println(welcomeSomething.hello("GRYOH") + " Welcome");

익명 내부 클래스로 작성했던 코드보다 훨씬 간결해졌다

내부클래스 vs 람다

공통점

바깥 클래스의 변수나 메서드에 접근할 수 있다.

차이점

1.내부클래스와 람다에서의 this는 다른 의미이다.

  • 내부클래스의 this는 자기 자신을 의미하지만 람다에서의 this는 선언된 클래스를 의미한다.
int num1 = 1;   
// 변수값 변경이 없기 때문에 사실상 final이고 final키워드 생략이 가능하다. (컴파일러가 추론가능)

// 내부클래스(로컬클래스)
class TestClass {
    class InnerClass {
        int num2 = 2;
        public int printNum(int number) {
            this.num1 = 3;  // 컴파일 에러 - 현재 this는 InnerClass임
            this.num2 = 3;
            return number;
        }
    }
}

// 익명클래스
NumberClass nc = new NumberClass() {
    int num2 = 2;
    @Override
    public int printNum(int number) {
        this.num1 = 3;      // 컴파일 에러-현재 this는 NumberClass임 
        this.num2 = 3;
        return number;
    }
};

//람다 표현식
NumberClass nc2 = number -> {
    int num1 = 3;           // 컴파일 에러 - shadowing 불가
    int num2 = 2;
    return number;
};

2.람다는 은닉변수(Shadow Variable)를 허용하지 않는다.(shadowing 불가)

  • 내부클래스는 재정의한 변수를 덮을 수 있다.
int baseNumber = 10;    // 사실상 final 변수 (effective final)

class InnerClass {
    class LocalClass {
        int baseNumber = 20;    // shadowing 된 변수
        public int printNum(int number) {
            return number + baseNumber;         // baseNumber => 20
        }
    }
}

NumberClass ncAnonymousClass = new NumberClass() {
    int baseNumber = 20;    // shadowing 된 변수
    @Override
    public int printNum(int number) {
        return number + baseNumber;             // baseNumber => 20
    }
};

NumberClass ncLambda = n -> {
    return n + baseNumber;                      // baseNumber => 10 (1)
}; 

baseNumber++;   // 사실상 final 이기 때문에 값을 변경하면 (1)람다표현식에서 컴파일 에러가 발생한다
// variable used in lambda expression should be final or effectively final 에러 발생

3.람다는 단일 추상함수 인터페이스만 사용할 수 있다.

public interface Greeting {
    void hello();
    void hi();
}

public static void main(String[] args) {
    //multiple non-overriding abstract methods found in interface 에러발생
    Greeting greeting = () -> System.out.println("안녕"); //컴파일 에러발생
}

0개의 댓글