JAVA - 람다와 스트림(1)

DevSeoRex·2022년 11월 1일
0
post-thumbnail

Lambda & Stream

Lambda식 이란?

  • 람다식(Lambda expression)은 메서드를 하나의 '식(expression)'으로 표현한 것
  • 람다식은 함수를 간략하면서도 명확한 식으로 표현할 수 있게 해줌
  • 람다식을 익명 함수(anonymous function) 이라고 함

Lambda식의 예시

// 람다식이 적용되지 않은 Method
int method() {
	return (int)(Math.random() * 5) + 1;
}

// 람다식이 적용된 Method
Arrays.setAll(arr, (i) -> (int)(Math.random() * 5) +1);

람다식이 적용되지 않았을때보다 람다식이 적용되었을때가 간결하고 이해하기 쉽다.

Lambda식의 장점

  • 일반 메서드보다 람다식이 간결하고 이해하기 쉽다.
  • 람다식은 클래스를 생성하고 객체를 생성하는 과정없이 람다식 자체만으로 메서드의
    역할을 대신 할 수 있다.
  • 람다식은 메서드의 매개변수로 전달 가능하다.
  • 람다식은 메서드의 결과로 반환 될 수 있다.

람다식을 작성하는 방법

  • 람다식은 메서드에서 이름과 반환타입을 제거하고 매개변수 선언부와 몸통{ } 사이에 '->'(화살표)를 추가하면 된다.
// 람다식 적용 전
int max(int a, int b) {
	return a > b ? a : b;
}

// 람다식 적용 후 - return문 사용
(int a, int b) -> {return a > b ? a : b}

// 람다식 적용 후 - 식(expression) 사용
(int a, int b) -> a > b ? a : b

반환값이 있는 메서드의 경우, return문 대신 식(expression)으로 대체 가능하다.
문장이 아닌 식이기 때문에 끝에 ";"를 붙이지 않아야 한다.

람다식에 선언된 매개변수의 타입은 추론이 가능한 경우 생략이 가능하다.

// 람다식 타입 생략 전
(int a, int b) -> a > b ? a : b 

// 람다식 타입 생략 후
(a, b) -> a > b ? a : b

// 람다식 타입 생략 에러 CASE
(int a, b) -> a > b ? a : b

맨 마지막 에러 CASE와 같이 두 매개변수 중 어느 하나의 타입만 생략하는 것은 허용되지 않는다.

람다식에서의 괄호( '( )' , '{ }') 생략

아래와 같이 선언된 매개변수가 하나라면, 괄호( )를 생략할 수 있다.

// 괄호 생략 전
(a) -> a * a
(int a) -> a * a

// 괄호 생략 후
a -> a * a // OK
int a -> a * a // 에러

매개변수의 타입이 있는 경우에는 괄호를 생략할 수 없다.

괄호{ }안의 문장이 하나일 때는 괄호{ }를 생략할 수 있다. 이 때 문장의 끝에는 ' ; '을 붙이지 않아야 한다.

// 괄호 생략 전
(String name, int i) -> {
	System.out.println(name + "=" + i);
}

// 괄호 생략 후
(String name, int i) -> 
	System.out.println(name + "=" + i)

괄호 { } 안의 문장이 return문일 경우에는 괄호{ } 생략이 불가능하다.

(int a, int b) -> { return a > b ? a : b; } // OK
(int a, int b) -> return a > b ? a : b      // ERROR

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

람다식은 익명 클래스의 객체와 동등하다.

interface MyFunction {
	public abstract int max(int a, int b);
}

위와 같은 max( )라는 메서드가 정의된 MyFunction 인터페이스가 정의 되어 있다고 가정한다면
이 인터페이스를 구현한 익명 클래스의 객체는 아래와 같이 생성할 수 있다.

MyFunction f = new MyFunction() {
					public int max(int a, int b) {
                    	return a > b ? a : b;
                    }
                    
}

// 익명 객체의 메서드를 호출
int big = f.max(5, 3);

Myfunction 인터페이스에 정의된 메서드 max( )는 선언부가 일치한다면, 람다식으로
대체가 가능하다. 아래 코드는 위 코드를 람다식으로 대체한 코드이다.

MyFunction f = (int a, int b) -> a > b ? a : b; // 익명 객체를 람다식으로 대체
int big = f.max(5, 3); // 익명 객체의 메서드를 호출

인터페이스를 구현한 익명객체를 람다식으로 대체하려면, 익명 객체의 메서드와 람다식의 매개변수의 타입 및 개수 반환값이 일치해야 한다.

그래서 인터페이스를 통해 람다식을 다루기로 결정되어, 람다식을 다루기 위한 인터페이스를 함수형 인터페이스(Functional interface) 라고 부른다.

@FunctionalInterface
interface MyFunction { // 함수형 인터페이스 MyFunction을 정의
	public abstract int max(int a, int b);
}

함수형 인터페이스는 오직 하나의 추상 메서드만 정의되어 있어야 한다.
그래야만 람다식과 인터페이스의 메서드가 1:1로 연결될 수 있기 때문이다.
static 메서드와 default 메서드의 개수에는 제약이 없다.

@FunctionalInterface 애너테이션을 붙이지 않아도 에러가 발생하지는 않지만,
컴파일러가 함수형 인터페이스를 올바르게 정의하였는지 확인해주는 역할을 하므로,
붙이면 도움이 된다.

출처 : 자바의 정석 3rd(남궁성 저 , 도우출판)

0개의 댓글