인프런 워밍업 클럽 백엔드 - 세 번째 과제

인프런 워밍업 클럽 백엔드 - 세 번째 과제

[키워드]

익명 클래스 / 람다 / 함수형 프로그래밍 / @FunctionalInterface / 스트림 API / 메소드 레퍼런스

 

[질문]

  • 자바의 람다식은 왜 등장했을까?

  • 람다식과 익명 클래스는 어떤 관계가 있을까? - 람다식의 문법은 어떻게 될까?


익명 클래스란?

익명 클래스는 이름이 없는 클래스로, 객체 사용 시에 클래스의 선언과 객체 생성이 동시에 이루어집니다. 이미 정의되어 있는 클래스의 멤버들을 재정의하여 사용할 필요가 있을 때, 그리고 그것이 일회성으로 이용될 때 사용하는 기법입니다.

 

람다란?

람다는 어떤 함수의 매개변수로 다른 함수를 넣고 싶을 때 사용합니다. 람다는 anonymous function이라는 명칭을 갖고 있으며, 선언 없이 또는 이름 없이 사용할 수 있는 함수입니다.

 

선언 예제

@FunctionalInterface
public interface CoffeeMachine {
    public abstract String getCoffee(int coin);
}
  • 익명 클래스를 이용하는 방식

CoffeeMachine machine = new CoffeeMachine() {
            @Override
            public String getCoffee(int coin) {
                return coin + "원 커피";
            }
        };

 

  • 람다식을 이용하는 방식

CoffeeMachine lambdaMachine = coin -> coin + "원 커피";

 

함수형 프로그래밍

함수형 프로그래밍은 자료 처리를 수학적 함수의 계산으로 취급하고 상태와 가변 데이터를 멀리하는 프로그래밍 패러다임의 하나 입니다. 함수형 프로그래밍은 함수의 응용을 강조하며, 프로그래밍이 문이 아닌 식이나 선언으로 수행되는 선언형 프로그래밍 패러다임을 따르고 있습니다.

 

@FunctionalInterface

@FunctionalInterface는 Java 8에서 도입된 어노테이션으로, 인터페이스가 함수형 인터페이스로서 작동하도록 지정합니다. 함수형 인터페이스는 단 하나의 추상 메소드를 가지는 인터페이스를 의미하며, 람다 표현식의 타겟 타입으로 사용됩니다.

@FunctionalInterface
public interface RunSomething {
    void doIt();
}

 

스트림 API

스트림 API는 Java 8에 추가된 기능으로, 데이터를 추상화하여 다루므로, 다양한 방식으로 저장된 데이터를 읽고 쓰기 위한 공통된 방법을 제공합니다. 배열이나 컬렉션뿐만 아니라 파일에 저장된 데이터도 모두 같은 방법으로 다룰 수 있게 됩니다.

// 스트림 API를 사용하지 않은 경우
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = 0;
for (int n : numbers) {
    if (n % 2 != 0) {
        sum += n * n;
    }
}

// 스트림 API를 사용한 경우
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream()
                 .filter(n -> n % 2 != 0)
                 .mapToInt(n -> n * n)
                 .sum();

 

메소드 레퍼런스

메소드 레퍼런스는 메소드를 가리키는 참조입니다. 메소드 레퍼런스를 사용하면 람다 표현식을 더 간결하게 표현할 수 있습니다. 메소드 레퍼런스는 '::' 연산자를 사용하여 표현합니다.

public class Main {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("Apple", "Banana", "Cherry");

        // 람다 표현식
        list.forEach(s -> System.out.println(s));

        // 메소드 레퍼런스
        list.forEach(System.out::println);
    }
}

 

람다식은 왜 등장했을까?

자바의 람다식이 등장한 이유는 불필요한 코드를 줄이고, 가독성을 높이기 위함입니다. 함수형 인터페이스의 인스턴스를 생성하여 함수를 변수처럼 선언하는 람다식에서는 메소드의 이름이 불필요하다고 여겨져서 이를 사용하지 않습니다.

 

람다식과 익명 클래스는 어떤 관계가 있을까?

람다식과 익명클래스의 관계는 다음과 같습니다. 람다식은 익명 클래스와 동등한 기능을 하는 식(Expression)입니다. 익명 클래스로 거추장스럽게 정의했던 것을 벗어나 간결한 식만으로 익명 클래스를 구현할 수 있습니다. 하지만, 람다는 함수형 인터페이스에서만 사용됩니다. 추상 클래스의 인스턴스를 만들 때 람다를 쓸 수 없으니, 익명 클래스를 사용해야 합니다. 또한, 람다는 자신을 참조할 수 없습니다. 람다에서의 this 키워드는 바깥 인스턴스를 가리킵니다. 반면 익명 클래스에서의 this 는 익명 클래스의 인스턴스 자신을 가리킵니다. 그래서 함수 객체가 자신을 참조해야 한다면 반드시 익명 클래스를 사용해야 합니다.

 

람다식의 문법은 어떻게 될까?

  • 매개 변수가 하나 인 경우 (괄호 생략 가능, 두 개인 경우 생략 불가능)

msg -> {System.out.println(msg)};

 

  • 중괄호 안의 구현부가 한 문장인 경우 (중괄호 생략)

    msg -> System.out.println(msg);

 

  • 중괄호 안에 구현부가 한 문장이라도 return문은 중괄호를 생략할 수 없음

msg -> return msg.length(); // 오류

 

댓글을 작성해보세요.

채널톡 아이콘