익명클래스 vs 람다식 비교

반응형
728x90
반응형

람다표현식

메서드를 하나의 식(expression)으로 표현한 것이다. 메서드를 람다식으로 표현하면 메서드 이름과 반환값이 존재하지 않기 때문에 이를 '익명함수' 라고도 한다.

 

람다표현식의 뜻을 글로만 보면 감이 안올 수 있다. 아래 예제로 어떤식으로 람다표현식이 사용되는지 눈으로 확인하자.

 

람다식 예제
import dto.SampleDto;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class Basic {
    private void test() {
        List<SampleDto> sampleDtoList = new ArrayList<>();
        
        // 람다식 사용
        sampleDtoList.sort(
                (SampleDto sampleDto1, SampleDto sampleDto2) -> sampleDto1.getName().compareTo(sampleDto2.getName())
        );
    }
}

 

 

 

람다표현식이 필요한 이유

우선 아래 예제를 보자. 위의 '람다식 예제'의 코드는 기존에 익명클래스로도 구현이 가능하다. 익명클래스와 람다표현식의 차이를 눈여겨보자.

 

import dto.SampleDto;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class Basic {
    private void test() {
        List<SampleDto> sampleDtoList = new ArrayList<>();
        
        // 익명클래스 사용
        sampleDtoList.sort(new Comparator<SampleDto>() {
            @Override
            public int compare(SampleDto sampleDto1, SampleDto sampleDto2) {
                return sampleDto1.getName().compareTo(sampleDto2.getName());
            }
        });

        // 람다식 사용
        sampleDtoList.sort(
                (SampleDto sampleDto1, SampleDto sampleDto2) -> sampleDto1.getName().compareTo(sampleDto2.getName())
        );
    }
}

 

위 익명 클래스 사용 로직부터 분석해보자.

 

...
     sampleDtoList.sort(new Comparator<SampleDto>() {
            @Override
            public int compare(SampleDto sampleDto1, SampleDto sampleDto2) {
                return sampleDto1.getName().compareTo(sampleDto2.getName());
            }
        });
...

 

우선 List.java 의 sort() 를 호출하였다. sort() 메서드는 다음과 같다.

 

...
    default void sort(Comparator<? super E> c) {
        Object[] a = this.toArray();
        Arrays.sort(a, (Comparator) c);
        ListIterator<E> i = this.listIterator();
        for (Object e : a) {
            i.next();
            i.set((E) e);
        }
    }
...

 

인자로 Comparator 인터페이스를 받는다. 이 뜻은 Comparator 인터페이스를 구현한 객체를 받는다는 의미다. 익명클래스는 Comparator 인터페이스를 구현한 클래스를 가지지않고도 로직 안에서 객체를 생성하여 파라미터로 넘길 수 있다.

 

- 익명클래스

...
     sampleDtoList.sort(new Comparator<SampleDto>() {
            @Override
            public int compare(SampleDto sampleDto1, SampleDto sampleDto2) {
                return sampleDto1.getName().compareTo(sampleDto2.getName());
            }
        });
...

 

위 코드를 람다표현식으로 표현하면 아래와 같다. 기능은 익명클래스와 모두 동일하다.

 

- 람다표현식

// 람다식 사용
sampleDtoList.sort(
        (SampleDto sampleDto1, SampleDto sampleDto2) -> sampleDto1.getName().compareTo(sampleDto2.getName())
);

 

 

위 람다표현식은 아래의 장점을 가진다.

 

1) 이름 없는 함수 선언 가능

2) 소스코드의 분량을 줄일 수 있고, 반복 코드 관리에 유용하다.

3) 코드를 파라미터로 전달이 가능하여, 동작을 정의하여 메서드에 전달할때 편리하게 사용이 가능하다.

 

 

 

 

함수형 인터페이스 (@FunctionalInterface)

위 예제 코드를 따라오면서 한가지 의문점이 들 수 있다. 람다표현식은 메서드 명도 없고, 단순히 구현 로직을 명시한다. 그렇다면 만약 여러개의 추상메서드가 있는 인터페이스의 경우에는 어떻게 처리될까?

 

정답을 말하자면, 위 상황에서 람다표현식의 사용은 불가능하다. 람다표현식은 함수형 인터페이스의 경우에만 가능하다. 위에서 예제로 설명했던 Comparator 인터페이스를 보자.

 

Comparator.java
package java.util;

import java.io.Serializable;
import java.util.function.Function;
import java.util.function.ToIntFunction;
import java.util.function.ToLongFunction;
import java.util.function.ToDoubleFunction;
import java.util.Comparators;

@FunctionalInterface
public interface Comparator<T> {
    int compare(T o1, T o2);

    // Object의 public 함수이므로 추상 메서드로 속하지 않는다.
    // boolean equals(Object obj);

    ...
}

 

우선 다른 default 메서드는 제외하고 추상 메서드만 가져왔다.  compare 메서드 단 1개만을 갖고있다. 즉, 함수형 인터페이스란 하나의 추상메서드만을 갖고있는 인터페이스로, 이러한 함수형 인터페이스의 경우에만 람다표현식 사용이 가능하다.

 

어노테이션
@FunctionalInterface

 

함수형 인터페이스라는 의미를 어노테이션으로 명시 가능하다. 생략이 가능하지만, 명시적으로 사용해주는 것을 권장한다. 이유는 해당 어노테이션의 선언으로 혹시라도 인터페이스에 추상 메서드가 2개 이상으로 선언되면 컴파일 에러가 발생하여 오류를 방지할 수 있기 때문이다.

 

 

 

Object 의 public 메서드

위 Comparator 인터페이스에서 아래 코드를 짚고 넘어가보자.

 

- 함수형 인터페이스인 경우
int compare(T o1, T o2);

// Object의 public 함수이므로 추상 메서드로 속하지 않는다.
boolean equals(Object obj);

 

Comparator 인터페이스에 추상 메서드는 compare, equals 총 2개였는데 함수형 인터페이스가 가능했다. 이유는 equals 메서드는 Object 객체의 public 메서드이기 때문에 포함되지 않았기 때문이다. 

 

- 함수형 인터페이스가 아닌 경우 
int compare(T o1, T o2);

// Object의 public 메서드가 아니므로 추상메서드로 포함된다.
Object clone();

 

만약 위의 clone 메서드가 선언되어 있었다면 그것은 함수형 인터페이스가 될 수 없었을 것이다. Object 클래스의 public 메서드일 경우에만 추상메서드 개수로 포함되지 않는 것이다. 

 

위 내용 참고 : http://wiki.sys4u.co.kr/pages/viewpage.action?pageId=7766426#app-switcher 

 

 

 

 

 

 

반응형

Designed by JB FACTORY