람다식
이란 무엇일까요. 그 동안 java를 이용하다가 lambda식 이란 것을 처음 보았을때는 매우 생소하고 거부감이 느껴졌습니다. 하지만, java8에서 추가된 stream과 같은곳에서 한두번씩 사용하기 시작해보니 정말 편리한 기능임을 알게 되었습니다.
( 한편에서는 너무 많은 코드를 생략하다보니 오히려 프로그램의 가독성을 저해시킨다는 의견도 있습니다. )
1. 람다식이란?
java 8부터 추가된 기능으로 익명객체
를 생성하기 위한 표현식을 말합니다. 무슨말일까요.. 역시 예제를 살펴보는것이 더 나을것 같습니다.
1.1 람다식 이전
xpublic interface Goods {
public void doSome();
}
public class Computer implements Goods{
public void doSome() {
System.out.println("do Operation!");
}
}
public class Main {
public static void main(String[] args) {
Goods com = new Computer();
com.doSome();
}
}
기존 자바에서 interface
를 이용해 다형성을 제공하기 위해서는 interface
를 만들고, 그것을 구현한 class
를 작성한 뒤, 사용시에는 interface
타입의 참조변수에 interface를 구현한 class
의 객체를 생성하여 사용했습니다.
간단하게 흐름을 살펴보면 이러한 흐름을 가지는것 같습니다.
xxxxxxxxxx
public class Main {
public static void main(String[] args) {
Goods com = new Goods() {
public void doSome() {
System.out.println("do Operation!");
}
};
com.doSome();
}
}
또는 위와 같이 실행하는 쪽에서 익명 객체
를 만들어 사용했습니다. 하지만 Goods를 구현한 객체가 자주 사용되어야 한다면, 위의 코드를 계속해서 반복해서 사용해야할 것이고 그렇게 되면 지저분한 코드가 될 것입니다.
1.2 람다식 사용
xxxxxxxxxx
public class Main {
public static void main(String[] args) {
Goods com = () -> System.out.println("do Operation!");
com.doSome();
}
}
하지만 람다식
을 사용하는 경우 위와 같이 아주 간결하게 표현을 할 수 있습니다.
람다식을 이용한 흐름은 이전보다 훨씬 간단하게 변경된것 같습니다.
2. 람다식 표현법
람다식은 매개변수 + 실행문
으로 구성됩니다. 즉 접근자, 반환형
모두 생략되는 구조 입니다.
모양은 ()->{};
의 형태로 구성됩니다. 첫 괄호 ()
해당 interface 함수의 매개변수
를 입력하면 됩니다. 그 다음 ->
를 입력하고, {}
(중괄호) 안에 실행할 코드를 작성하면 됩니다.
2.1 예제
xxxxxxxxxx
public interface Calculator {
public int cal(int num1, int num2);
}
아래의 람다식에서 사용될 인터페이스 입니다.
1. 기본 사용법((매개변수 타입)->{};
)
xxxxxxxxxx
public static void main(String[] args) {
Calculator cal = (int num1, int num2) -> {return num1 + num2; };
System.out.println(cal.cal(1, 2));
}
람다식에 필요한 기호를 모두 사용한 방법입니다.
2. 매개변수 타입 생략((매개변수)->{};
)
xxxxxxxxxx
public static void main(String[] args) {
Calculator cal = (num1, num2) -> {return num1 + num2; };
System.out.println(cal.cal(1, 2));
}
매개변수가 1개
이거나 2개 이상의 매개변수의 타입이 모두 같을
때에는 타입을 생략할 수 있습니다.
3. 매개변수가 없는 경우(()->{};
)
xxxxxxxxxx
public static void main(String[] args) {
Calculator cal = () -> {System.out.println("매개변수가 없는 경우")};
cal.cal();
}
만약 Calculator
인터페이스의 cal() 메소드에 매개변수가 없다면
위와 같이 매개변수를 생략하여 작성할 수 있습니다.
4. 중괄호 생략(()->;
)
xxxxxxxxxx
public static void main(String[] args) {
Calculator cal = (num1, num2) -> num1 + num2;
System.out.println(cal.cal(1, 2));
}
실행할 문장이 1개
일 때에는 {}(중괄호)
를 생략할 수 있습니다. 이 때 중요한 점은 반환이 필요한 메소드의 경우return 키워드를 생략
해야 한다는 것 입니다.
5. 소괄호 중괄호 생략(매개변수 -> ;
)
public static void main(String[] args) {
Calculator cal = num1 -> System.out.println(num1);
cal.cal(1);
}
매개변수가 1개
이고 실행할 문장도 1개
이면 위와 같이 ()
와 {}
를 생략할 수 있습니다.
3. 람다 사용 조건
람다식을 사용하기 위한 인터페이스에는 조건이 있습니다. 바로 구현해야할 인터페이스의 추상 메소드가 단1개
이어야 한다는 조건입니다. 2개 이상인 경우 어떤 메소드를 람다식으로 표현했는지 알 수 없으니
당연하지 않냐구요? 예 사용하는 입장에서는 당연합니다. 사용하는 입장이라는게 무슨 말일까요? 그럼 사용하는 입장의 반대의 경우는 누구일까요? 바로 인터페이스를 설계 또는 작성하는 사람
일 것입니다.
람다식으로 사용하기 위한 인터페이스를 만들었고, 잘 사용하고 있었습니다. 하지만 해당 인터페이스를 구현하는 클래스에서 또 다른 기능이 필요하게 되었고 개발자가 해당 인터페이스에 메소드를 추가했습니다. 어? 그런데 사용하는 곳에서 갑자기 에러가 나기 시작합니다. 개발자는 이제서야 해당 인터페이스가 람다식을 위한 단일 추상메소드를 가진 인터페이스였음을 알게 되었습니다.
//Object 객체의 메소드만 인터페이스에 선언되어 있는 경우는 Functional Interface가 아님
public interface NotFunctional {
public boolean equals(Object obj);
}
//Object 객체의 메소드를 제외하고 하나의 추상 메소드만 선언되어 있는 경우는 Functional Interface임
public interface Functional {
public boolean equals(Object obj);
public void execute();
}
//Object객체의 clone 메소드는 public 메소드가 아니기 때문에 Functional Interface의 대상이 됨
public interface Functional {
public Object clone();
}
public interface NotFunctional {
public Object clone();
public void execute();
}
출처 - http://wiki.sys4u.co.kr/pages/viewpage.action?pageId=7766426
이뿐만이 아닙니다. 람다식을 위한 인터페이스를 작성하기 위해서는 지켜야할 규칙이 더 있습니다. 개발자가 이것을 모두 기억한 상태로 모든 인터페이스들을 검사하며 개발하기에는 너무 어렵습니다. 물론 인터페이스 이름으로 구분하는 것도 좋은 방법입니다. 하지만 이보다 더 확실한 방법이 있습니다.
3.1 @FunctionalInterface Annotation
바로 @FunctionalInterface
어노테이션을 사용하는 것 입니다.
위와 같이 람다식
으로 표현하기 위해 사용될 interface위에 @FunctionalInterface
만 붙혀준다면 컴파일 타임에 알아서 에러를 잡아줍니다. 위의 그림에서 Interface에 메소드를 2개 작성하여 에러가 표시된것을 알 수 있습니다.
'Language > Java' 카테고리의 다른 글
Java - ArrayList 제거 안되는 문제(Wrapper Class) (0) | 2019.07.02 |
---|---|
Java - Annotation 이란? Annotation 사용법 (0) | 2019.05.02 |
Java - Json 과 Gson 이란? (0) | 2019.03.30 |
Java - Eclipse에서 Gradle프로젝트 생성한 뒤 Build 하기 (0) | 2019.03.30 |
Java - 직렬화에 관해서(csv, json, java serializable) (0) | 2019.03.30 |