[Java] Lambda expression (람다식)

17420 단어 JavaJava

람다식과 함수형 프로그래밍

  • 자바는 객체지향 프로그래밍으로써 특정 기능을 수행하기 위해서는 객체를 만들고 객체 내부에 멤버 변수를 선언하고 기능을 수행하는 메서드를 구현하였다.

  • 하지만 Java8부터 자바는 함수형 프로그래밍 방식을 지원하였으며 우리는 이것을 람다식이라고 부른다.

  • 함수형 프로그래밍(Functional Programming: FP)

    • 함수를 구현하고 매개변수를 기반으로 호출을 하는 식으로 구현이되는데 외부 매개 변수를 사용하지 않아 외부에 영향을 주지 않도록 구현하는 방법이다. 즉, 함수 내부에서 함수 외부에 있는 변수를 사용하지 않아 함수가 수행되더라도 외부에는 영향을 주지 않는다.
    • 함수를 기반으로 하는 프로그래밍으로 입력받는 자료 이외의 외부 자료를 사용하지 않아 여러 자료가 동시에 수행되는 병렬처리가 가능하다.
    • 함수의 기능이 자료에 독립정임을 보장하여 동일한 자료에 대해 동일한 결과를 보장하고 다양한 자료에 대해 같은 기능을 수행할 수 있다.
    • 가독성이 좀 떨어진다는 단점이 있다.

람다식 문법

  • 자바는 Class가 있고 class의 instance변수가 있고, 그 instance 변수를 활용한 method를 만들며 구현을 하지만 람다식은 함수가 있고 함수의 매개변수를 이용한 시행문으로 구성된다.

  • (매개변수) -> {실행문;}
    매개변수를 받아서 실행을 하라는 의미

Example

  • 일반적으로 사용하는 함수
	int add(int x, int y){
    		return x+y;
	}
  • 람다식으로 표현한 함수
    (int x, int y) -> {return x+y;}
    
    // 매개 변수가 하나인 경우 자료형과 괄호 생략가능
    str->{System.out.println(str);}
    
    // 매개변수가 두 개이상인 경우 괄호를 생략할 수 없음
    x, y -> {System.out.println(x+y);}  //오류
    
    // 실행문이 한 문장인 경우 중괄호 생략 가능
    str-> System.out.println(str);
    
    // 실행문이 한 문장이라도 return문(반환문)은 중괄호를 생략할 수 없음
    str-> return str.length();  //오류
    
    // 실행문이 한 문장의 반환문인 경우엔 return과 중괄호를 모두 생략
    (x, y) -> x+y;
    str -> str.length;

함수형 인터페이스와 람다식 구현하기

  • 함수형 인터페이스는 람다식을 선언하기 위한 인터페이스로 익명 함수와 매개변수만으로 구현되므로 인터페이스는 단 하나의 메서드만을 선언해야한다.

  • @FunctionalInterface 애노테이션(annotation)을 interface에 추가하여 컴파일러에게 함수형 인터페이스라는 정보를 줘서 2개 이상의 메서드가 선언되는 것을 방지해야한다.

  • Example

@FunctionalInterface
public interface Add {
	int add(int a, int y);
}

👨🏻‍💻 Example Code

MyNumber.java (interface)

package ch03;

@FunctionalInterface
public interface MyNumber {
	
	int getMax(int num1, int num2);
}

MyNumberTest.java

package ch03;

public class MyNumberTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		MyNumber myNumber = (x, y) -> x > y? x : y;
		
		/* 아래와 같이 표현도 가능하다.
		MyNumber myNumber = (x, y) -> {
			if (x > y) 
				return x;
			else return y;
		};
		*/
		
		System.out.println(myNumber.getMax(10, 20));
	}

}

객체지향 프로그래밍 vs 람다식

  • 객체지향 프로그래밍의 프로그래밍 순서는 Interface생성, interface를 구현하는 class생성, 해당 클래스로 instance를 생성하고 사용하는 순서로 진행된다.

  • 반대로 람다식은 객체지향 프로그래밍의 class를 생성하는 과정이 생략되었다. 람다식의 class생성과정이 없어 class가 생성되지 않는다고 생각할 수 있지만 내부적으로는 익명의 class가 생성되어져 프로그램이 돌아가게 된다.

👨🏻‍💻 Example Code

StringConcat.java

package ch04;

@FunctionalInterface
public interface StringConcat {
	public void makeString(String s1, String s2);
}

StringConcat.java

package ch04;

public class StringConcatImpl implements StringConcat{

	@Override
	public void makeString(String s1, String s2) {
		// TODO Auto-generated method stub
		System.out.println(s1 + ", " + s2);
	}
}

StringConcat.java

package ch04;

public class StringConcatTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		String s1 = "Hello";
		String s2 = "World";
		
        
        // 람다식을 사용하지 않은 일반적인 객체지향 프로그래밍 방법!!
		// Interface생성, interface를 구현하는 class생성, 해당 클래스로 instance를 생성하고 사용
		StringConcatImpl strImpl = new StringConcatImpl();
		strImpl.makeString(s1, s2);
		
		
		// 람다식을 사용한 프로그래밍!!!
		StringConcat concat = (s, v)-> System.out.println(s + ", " + v);
		concat.makeString(s1, s2);
		// 객체지향과 비교했을때 class를 생성하는 과정이 생략되었다.
		// class가 생성안된다고 생각을 하겠지만 내부적으로 익명 class가 생성되어지게 된다.
		// class생성은 개발자가 직접 프로그래을 하는 과정만 생략된 것이다.
		// *람다식 함수형 인터페이스에는 하나의 메서드만 가능!!
	}
}

람다식의 익명의 내부 class

람다식 사용 예시

StringConcat concat2 = (s, v)->System.out.println(s + "," + v ); //System.out.println(i);
concat2.makeString(s1, s2);

람다식을 컴파일할 때 내부적으로 돌아가는 구조

StringConcat concat3 = new StringConcat() {			
	@Override
	public void makeString(String s1, String s2) {
			
		System.out.println( s1 + "," + s2 );
	
};		
concat3.makeString(s1, s2);
  • 위와 같이 람다식을 구현하면 익명의 내부 클래스가 만들어지고, 이를 통해 익명의 객체가 생성된다.
  • 익명 내부 클래스에서와 마찬가지로 람다식 내부에서도 외부에 있는 지역 변수의 값을 변경하면 오류가 발생한다.



Reference

좋은 웹페이지 즐겨찾기