코딩하렴

Lambda Expressions 람다식

by 으렴

람다쓰...

 

"수학자 Alonzo Church가 발표한 람다계산법에서 사용된 식"을 제자 John Macarthy가 프로그래밍 언어에 도입!

 

Java8부터 Lambda Expressions 지원

 

람다는 객체지향보다 함수지향(병렬처리, 이벤트 지향)에 가깝다.

 

객체지향 언어인 자바에서 값이나 객체가 아닌 하나의 함수를 변수에 담아둔 다는 것이 이해가 가지 않을 것이다.

 

람다식은 객체지향언어인 자바에서 변수안에 함수 매핑을 가능케한다.

 

람다식은 로컬 익명 구현 객체를 생성하게 된다.

이 목적은 인터페이스가 갖고있는 메소드를 간편하게 즉흥적으로 구현해서 사용하는 것이다.

 

먼저 인터페이스를 직접 클래스로 구현한 메소드를 호출해보자.

public interface LogicName {
	public int plusAandB(int a, int b);
}

기본 인터페이스는 다음과 같다.

 

이것을 클래스로 구현하여 그 함수를 불러볼 것이다.

class LogicName_Impl implements LogicName {
	@Override
	public int plusAandB(int a, int b) {
		return a+b;
	}
}

 

이렇게 하면 클래스에서 구현한 함수를 메인에서 호출 할 수 있다.

public class Lambda_Main {
	public static void main(String[] args) {

		//class implements로 구현
		LogicName_Impl lni = new LogicName_Impl();
		System.out.println("1번 :"+lni.plusAandB(1, 1));	
	}
}

 

이번엔 그냥 인터페이스를 익명함수로 불러보자

public class Lambda_Main {
	public static void main(String[] args) {

		//class implements로 구현
		LogicName_Impl lni = new LogicName_Impl();
		System.out.println("1번 :"+lni.plusAandB(1, 1));
		
		//interface를 익명함수로 구현
		System.out.println("2번 :"+new LogicName() {
			@Override
			public int plusAandB(int a, int b) {
				return a+b;
			}
		}.plusAandB(12, 10));
	}
}

편의상 println에 다 때려 넣었다.

 

public class Lambda_Main {
	public static void main(String[] args) {

		//class implements로 구현
		LogicName_Impl lni = new LogicName_Impl();
		System.out.println("1번 :"+lni.plusAandB(1, 1));
		
		//interface를 익명함수로 구현
		System.out.println("2번 :"+new LogicName() {
			@Override
			public int plusAandB(int a, int b) {
				return a+b;
			}
		}.plusAandB(12, 10));

		
		//람다식 구현
		LogicName lambda = (a, b) -> {
			return a + b;
		};
		System.out.println("3번 :"+lambda.plusAandB(202, 20));

	}
}

그리고 맨 마지막 람다식을 구현해 보면 저렇게 된다.

이렇게 나오면 일단 람다식에 대한 구분은 완성되었다.

 

 

람다식의 기본구조는 다음과 같다.

(타입 매개변수, ...) -> { 실행문; ...};

(int a, int b, ...) -> { return a+b; };

 

여기서 생략 가능한 것.

① 매개인자의 자료형

함수 몸체에 실행문이 한개인 경우 함수 몸체를 감싸는 중괄호 { }

③ 함수 몸체에 실행문이 한개이고 그 실행문이 return문 일 경우에 몸체를 감싸는 중괄호와 return 키워드

④ 매개인자가 1개인 경우 매개인자를 감싸는 소활호 ( )

 

생략 가능한 람다식 구문을 테스트 해 봅시당.

interface LogicOne {
	public void returnNo();
}

interface LogicTwo {
	public void One(int a);
}
interface LogicThree {
	public void returnNN(int a, int b);
}
interface LogicFour {
	public String returnString(int a);
}
interface LogicFive {
	public void returnNo(int a);
}

 

 

위와 같은 인터페이스 들을 만들었다.

		LogicOne l1 = () -> { System.out.println("인자가 없는 함수"); };  
		
		LogicTwo lo1 = (int a) -> { System.out.println("a:" + a); };
		LogicTwo lo2 = (a) -> { System.out.println("a:" + a); };    // 매개인자 자료형 생략

		LogicThree ln1 = (int a, int b) -> { System.out.println("a+b:" + (a + b) ); };
		LogicThree ln2 = (a, b) -> { System.out.println("a+b:" + (a + b) ); };   // 매개인자 자료형 생략

		LogicFour lo3 = a -> { return "a:" +  a; };
		LogicFour lo4 = a -> "a:" + a;      // 함수의 실행문 한개, 리턴문만 존재시 중괄호, return문 둘다 생략가능

		LogicFive ln3 = a -> { System.out.println("a:" + a); };    //매개인자가 하나라서 소괄호 생략
		LogicFive ln4 = a -> System.out.println("a:" + a);    //함수의 실행문이 하나라서 중괄호를 생략

 

람다식과 관련된 어노테이션을 설명하겠다.

 

기본적으로 람다식을 위한 인터페이스에서 추상메소드는 단 하나여야한다.

 

이러한 사실을 개발자가 알고잇다고 하더라도 뭐 유지 보수 측면에서 나중에 알아보기 힘들 가능성이 있다.

@FunctionalInterface
interface LogicSix {
	public String returnStrings(int a,String b);
}

이런식으로 인터페이스위에 어노테이션을 사용할 수 있다.

 

실제로 저 어노테이션을 선언하면 해당 인터페이스에 메소드를 두개 이상 선언하면 에러가 나게됩니다.

 

머라고했더라 'LogicSix'는 functional Interface가 아닙니다 뭐이렇게 얘기한다.

 

즉 해당 인터페이스에 메소드를 두개 이상 선언하면 컴파일러 수준에서 유효하지 않다는 말이다.

 

 

 

자바에서 클래스는 메소드(기능,행위)에서 변수(상태)를 제어할 수 있다.

 

즉 객체가 메소드를 호출하면 입력+상태에서 출력이 결정된다 side-effect(부작용)가 발생할 가능성이 있다.

 

함수단위의 배타적인 수행이 보장되지 않기 때문에 병렬처리와 멀티스레드 환경에서 단점이 있을수 있다.

 

람다식은 입력 + 출력에 종속되어있기때문에 side-effect가 발생하지 않는 것을 최대한 보장할 수 있다. 

사이트의 정보

코딩하렴

으렴

활동하기