람다와 함수형 인터페이스

gustjtmd·2022년 1월 13일
0

Java

목록 보기
31/40

인스턴스보다 기능 하나가 필요한 상황을 위한 람다

자바는 객체지향 언어이다. 그리고 코드 흐름에 대부분에 클래스와 인스턴스가 존재한다.
그런데 프로그램을 작성하다보면 다음의 상황을 자주 접하게된다.
기능 하나를 정의해서 전달해야 하는 상황
Comparator<T>인터페이스의 구현이 필요한 상황을 예로 들 수 있다

class SlenCOmp implements Comparator<String>{
    @Override
    public int compare(String s1, String s2){
        return s1.length()-s2.length();
    }
}
public class SlenComparator {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("Robot");
        list.add("Lambda");
        list.add("Box");

        Collections.sort(list,new SlenCOmp());
        for (String s : list)
            System.out.println(s);
    }
}
-----------------------------------------------------------------------
Box
Robot
Lambda
잠시 후에 람다식 기반으로 바꾸고 그전에 람다에 대해 알아보자.

매개변수가 하나이고 반환하지 않는 람다식.

interface Pritable{
    void print(String s);   //매개변수가 하나, 반황형 void
}
public class OneParamNoReturn {
    public static void main(String[] args) {
        Pritable p;
        p = (String s) -> {System.out.println(s);};  //줄임 없는 표현
        p.print("Lambda exp one.");

        p = (String s) -> System.out.println(s);     //중괄호 생략
        p.print("Lambda exp two");

        p = (s) -> System.out.println(s);   // 매개변수 형 생략
        p.print("Lambda exp three");

        p = s -> System.out.println(s);     // 매개변수 소괄호 생략
        p.print("Lambda exp four");
    }
}
-------------------------------------------------------------------

Lambda exp one.
Lambda exp two
Lambda exp three
Lambda exp four

매개변수가 위와 같이 하나일 경우에는 
s -> System.out.println(s)와 같이 소괄호 생략 가능.

매개변수가 둘이고 반환하지 않는 람다식

interface Calculate{
    void cal(int a, int b); //매개변수 둘, 반황형 void
}
public class TwoParamNoReturn {
    public static void main(String[] args) {
        Calculate c;
        c = (a,b) -> System.out.println(a+b);
        c.cal(4,3); //이번에 덧셈이 진행

        c = (a,b) -> System.out.println(a-b);
        c.cal(4,3); //이번엔 뺄셈이 진행

        c = (a,b) -> System.out.println(a * b);
        c.cal(4,3); //이번엔 곱셈이 진행.
    }
}
---------------------------------------------------------------------
7
1
12

매개변수가 있고 반환하는 람다식.

interface Calculate{
    int cal(int a, int b);   //값을 반환하는 추상 메소드
}
public class TwoParamAndReturn {
    public static void main(String[] args) {
        Calculate c;
        c = (a,b) -> {return a+b;};
        System.out.println(c.cal(4,3));

        c = (a,b) -> a + b;
        System.out.println(c.cal(4,3));
    }
}
--------------------------------------------------------------------
7
7
(a, b) -> a + b 
이 연산이 진행되면 그 결과로 값이 남게 된다. 그러면 이 값은 별도로 명시하지 않아도 반환의
대상이 됫 return문이 메소드 몸체를 이루는 유일한 문장이면 위와 같이 작성 가능.
그리고 이것이 보편적인 방식
interface HowLong{
    int len(String s);  //값을 반환하는 메소드
}
public class OneParamAndReturn {
    public static void main(String[] args) {
        HowLong hl = s -> s.length();
        System.out.println(hl.len("I am So Happy"));
    }
}
-------------------------------------------------------------------
13
s -> s.length()
메소드 몸체를 이루는 유일한 문장이 메소드 호출문인데 이 문장에서 호출하는 length는 값을
반환한다. 따라서 메소드의 호출 결과로 반환된 값이 남는다. 그리고 이렇게 반환된 값 역시 
별도로 명시하지 않아도 반환의 대상이 된다 따라서
s -> {return s.lengt();} 생략 가능.

매개변수가 없는 람다식.

interface Generator{
    int rand();
}
public class NoParamAndReturn {
    public static void main(String[] args) {
        Generator gen = () ->{
            Random rand = new Random();
            return rand.nextInt(50);
        };
        System.out.println(gen.rand());
    }
}
-----------------------------------------------------------------------
랜덤된 수

Generator gen = () ->{
            Random rand = new Random();
            return rand.nextInt(50);
        };
매개변수 선언이 없는 관계로 매개변수 정보를 담는 소괄호가 비어 있다. 그리고 이렇듯 둘 이상의
문장으로 이뤄진 람다식은 중괄호로 반드시 감싸야 하며 값을 반환할때도 return 반드시 필요.

함수형 인터페이스와 어노테이션

앞서 보인 람다식 예제에는 다음의 공통점이 하나 있다. "인터페이스에는 추상 메소드가 딱 하나만 존재한다"
이러한 인터페이스를 가리켜 '함수형 인터페이스'라 한다. 그리고 람다식은 이러한 
함수형 인터페이스를 기반으로만 작성이 될 수 있다.
@FunctionalInterface
interface Calculate{
	int cal(int a, int b)
}
@FunctionalInterface는 함수형 인터페이스에 부합하는지를 확인하기 위한 어노테이션이다.
위의 인터페이스에 둘 이상의 추상 메소드가 존재하면 이는 함수형 인터페이스가 아니기 때문에 
컴파일 오류로 이어짐. 그러나 static default 선언이 붙은 메소드의 정의는 
함수형 인터페이스의 정의에 아무련 영향을 미치지 않는다
@FunctionalInterface
interface Calculate{
	int cal(int a, int b);
    	default int add(int a, int b){return a+b;}
        static int sub(int a, int b){return a-b;}
}
위의 인터페이스를 대상으로도 람다식을 구성 가능. 어차피 채워야 할 메소드는 하나이기 때문.

람다식과 제네릭

인터페이스는 제네릭으로 정의하는것이 가능하다.
--------------------------------------------------------------------
interface Calculate50<T>{    //제네릭 기반의 함수형 인터페이스
    T cla(T a, T b);
}
public class LambdaGeneric {
    public static void main(String[] args) {
        Calculate50<Integer> ci = (a,b) -> a+b;
        System.out.println(ci.cla(3,4));

        Calculate50<Double> cd = (a,b) -> a+b;
        System.out.println(cd.cla(4.32,3.45));
    }
}
--------------------------------------------------------------------
7
7.7700000000000005
profile
반갑습니다

0개의 댓글