Programming Language/Java

JAVA에서 람다식(Lambda Expression)에 대해 정리해보기

TwinParadox 2021. 5. 2. 23:55
728x90

람다식?

람다식 또는 람다 표현식(Lambda Expression)은 프로그래밍에서 흔히 사용되는 개념으로 익명 함수 등으로 불리기도 한다. 많은 프로그래밍 언어에서 람다식을 볼 수 있으며 Java에서는 이 람다 표현식을 Java8부터 추가되어 활용할 수 있다.

 

특징

기본 형태

(int param1, String param2) -> { DoSomething...} // 기본
(Parameter, ...) -> { DoSomething... } // 타입이 동일한 경우
() -> { DoSomething... } // 매개변수가 없는 경우
(Parameter, ...) -> DoSomething // 단일 실행문인 경우
(Parameter, ...) -> { return some; } // 단일 실행문이 return인 경우 생략 불가

매개 변수는 위와 같은 형태로 사용한다. 매개 변수를 이용해서 중괄호 내 어떤 로직을 수행하는 것으로 해석하면 된다. 형태를 보면 알 수 있듯 이름이 없는 함수, 익명 함수(Anonymous Function)이다.

익명 함수는 다른 객체에 적용 가능한 연산을 모두 지원하는 일급 객체 특성을 가지기 때문에 함수 자체를 값으로 사용하거나 파라미터로 전달 및 변수에 대입하는 등의 연산도 가능하다.

 

 

람다식 적용 예시

public interface Calculator {
	public int calculate(int num1, int num2);
}

public interface NoParamCalculator {
	public void calculate();
}

public interface OneParamCalculator {
	int calculate(int num);
}

여러 가지 형태의 함수가 하나만 존재하는 인터페이스, Functional Interface를 선언했다.

이 인터페이스들을 활용해서 앞에서 예시로 들었던 람다식들을 다음과 같이 구현할 수 있다.

 

Calculator calculator1 = (int num1, int num2) -> {
	return num1 + num2;
};
System.out.println(calculator1.calculate(10, 20));

Calculator calculator2 = (num1, num2) -> {
	return num1 * num2;
};
System.out.println(calculator2.calculate(10, 20));

NoParamCalculator calculator3 = () -> { System.out.println("No Param"); };
calculator3.calculate();

Calculator calculator4 = (num1, num2) -> num1 - num2;
System.out.println(calculator4.calculate(20, 10));

OneParamCalculator calculator5 = num -> num * 10;
System.out.println(calculator5.calculate(10));

 

사용 조건

람다식을 사용하기 위한 인터페이스에는 구현할 인터페이스의 추상 메소드가 1개여야만 한다는 조건이 있다. 2개 이상일 때를 생각해보면 당연한 제약이다. 2개 이상의 메소드는 어떤 것이 람다식으로 표현했는지 알 수 없다.

public interface NoneFunctional {
	public boolean equals(Object obj); // Object 객체의 메소드만 있을 땐 Functional interface가 아님
}

public interface NoneFunctional {
	public Object doSome1();
	public void doSome2();
}

public interface Functional {
	public boolean equals(Object obj);
	public void doSome(); // 추상 메서드 하나만 있으면 Functional interface
}

public interface Functional {
	public Object doSome(); // Object의 doSome은 public이 아니므로 Functional Interface
}

 

인터페이스의 설계자와 사용자가 다르다면, 이를 간과하고 인터페이스 설계를 변경하면서 에러가 발생하고서야 이러한 문제를 알게 되는 부분이 있다. 이럴 때는 @FunctionalInterface 어노테이션을 사용해서 이 자체를 컴파일 타임에 에러를 잡을 수 있다.

 

 

사용 예제

java.util.function 인터페이스

docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html

 

java.util.function (Java Platform SE 8 )

Interface Summary  Interface Description BiConsumer Represents an operation that accepts two input arguments and returns no result. BiFunction Represents a function that accepts two arguments and produces a result. BinaryOperator Represents an operation u

docs.oracle.com

Stream API

docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html

 

Stream (Java Platform SE 8 )

A sequence of elements supporting sequential and parallel aggregate operations. The following example illustrates an aggregate operation using Stream and IntStream: int sum = widgets.stream() .filter(w -> w.getColor() == RED) .mapToInt(w -> w.getWeight())

docs.oracle.com

 

요약

장점

  • 람다는 불필요한 반복문 등을 줄여서 코드를 간결하게 만들 수 있다.
  • 지연 연산 수행으로 불필요한 연산을 최소화할 수도 있다.
  • 멀티 스레드를 이용하면 병렬 처리도 가능하다.

 

 

단점

  • 장점에서 언급한 간결한 코드가 너무 지나치면, 오히려 가독성을 해칠 수 있다.
  • 호출 자체가 까다롭다.
  • 람다 Stream은 단순 for, while에 비해서는 성능이 떨어진다.

 

 

728x90