Lambda_expression(1)

자바의 정석의 책을 중심으로 정리하였습니다.

JDK1.8 부터 추가된 람다식(Lambda) 등장

Lambda expression이란 ?

메서드를 하나의의 식으로 표현한것.

함수를 간략하면서도 명확한 식으로 표현할 수 있게 해준다.

메서드를 람다식으로 표현하면, 메서드의 이름과 반환값이 없어지므로, 람다식을 익명함수(anonymous function) 이라고도 한다.

int[] arr= new int[5];
Arrays.setAll(arr, (i) -> (int)(Math.random()*5)+1);

위의 람다식 (i) -> (int)(Math.random()*5)+1 을 메서드로 표현하면 다음과 같다

int method(){
  return (int)(Math.random()*5) +1;
}

lambda expression 작성하기

반환값이 있는 메서드의 경우, return문 대신 Expression으로 대신 할 수 있다.

식의 연살 결과가 자동적으로 반환값이 됨,

  • 중요한점은 '문장'이 아닌 식(Expression)이므로 끝에 ; 를 붙이지 않는다.

(int a, int b) -> { return a>b ? a:b ;} —> (int a, int b) -> a>b? a:b

문장(statement) 식 (expression)
return a>b ? a:b ; a>b? a:b

  • 람다식에 선언된 매개변수의 타입은 추론이 가능한 경우는 생략이 가능한 경우는 생략 가능
    람다식에 반환타입이 없는 이유는 항상 추론이 가능하기 때문이다.
    (int a, int b) -> a>b? a:b —> (a,b) -> a>b? a:b
    두 매개변수 중 어느 하나의 타입만 생략하는것은 허용되지 않는다.
  • 매개변수가 하나일 경우에는 괄호를 생략 가능하다.
    (a) -> aa —> a -> aa (int a) -> a/a —> int a-> a/a ( 에러 )
  • 괄호{ } 안의문장이 하나일 경우에는 괄호 생략 가능
    (String name, int i) -> { System.out.println(name+"="+ i ) ;} 은 다음과 같이 만들수 있다.
    (String name, int i) -> System.out.println(name+"="+ i ) 여기서는 ; 를 제거 해야한다.

함수형 인터페이스( functional interface)

자바에서 모든 메서드는 클래스 내에 포함되어야하는데, 람다식은 어떤 클래스에 포함되는 것일까??

람다식은 익명 클래스의 객체와 동등하다. 라고 되어있는데 무슨말일까??

package lambda_expression;

public class lambda01 {


    public static void main(String[] args) {

        //익명클래스의 객체의 생성
        MyFunction f1 = new MyFunction() {
            @Override
            public int max(int a, int b) {
                return a > b ? a : b;
            }
        };

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

        //람다식으로 표현으로 바꿈
        MyFunction f2 = (int a, int b) -> a > b ? a : b; // 익명 객체를 람다식으로 대체
        int big2 = f2.max(6,3);//익명 객체의 메서드 호출

        System.out.println(big2);
    }
}

결과

5
6

람다식과 동등한 메서드가 정의 되어 있는 것이어야한다.!!

그래야만 참조변수로 익명 객체의 메서드를 호출할 수 있기 때문이다.

MyFunction인터페이스를 구현한 익명 객체를 람다식으로 대체가 가능한 이유

: 람다식도 실제로는익명객체이고, MyFunction 인터페이스르 구현한 객체의 메서드 max()와 람다식의 매개변수의 타입과 개수 그리고 반환값이 일치 하기 때문이다.

람다식을 다루기 위한 인터페이스를 '함수형 인터페이스(functional interface) 라고 부르기로 함

람다식과 인터페이스의 메서드가 1:1 로 연결될 수 있기 때문

기존의 인터페이스의 메서드를 구현하여 사용하는 것은 아래와 같다.

 List<String> list = Arrays.asList("abc","aaa","bbb","ddd","aaa");
        Collections.sort(list, new Comparator<String>(){
            @Override
            public int compare(String s1, String s2) {
                return s2.compareTo(s1);
            }
        });

이것을 람다형식으로 변경해주면 ??

 List<String> list = Arrays.asList("abc","aaa","bbb","ddd","aaa");
Collections.sort(list,(s1,s2) -> s2.compareTo(s1));

이렇게 간단하게 사용할 수 있다.

Collections클래스의 sort 메서드와 Comparator 인터페이스를 살펴 보았다

public class Collections {
    // Suppresses default constructor, ensuring non-instantiability.
    private Collections() {
    }
    ....    
@SuppressWarnings({"unchecked", "rawtypes"})
    public static <T> void sort(List<T> list, Comparator<? super T> c) {
        list.sort(c);
    }
  ...
}

Collections의 sort의 파라미터는 Compator 인터페이스이며,

Comparator인터페이스는 @FunctionalInterface 를 어노테이션으로 선언되어 있었다.

@FunctionalInterface
public interface Comparator<T> {
    /**
     * Compares its two arguments for order.  Returns a negative integer,
     * zero, or a positive integer as the first argument is less than, equal
     * to, or greater than the second.<p>
     ...
        */
    int compare(T o1, T o2);
  ...

//p 798

메서드의 매개변수가 @FunctionalInterface 로 정의된 타입의 인터페이스라면 메서드를 호출할때 람다식을 참조하는 참조변수를 매개변수로 지정해야한다는 뜻

void aMethod(Function f){
  f.myMethod();
}
...
MyFunction f = () -> System.out.println("myMethod()");
aMethod(f);

종합 한 코드를 보면 다음과 같다.

package lambda.example;


@FunctionalInterface
interface LambdaFunction {
    void run(); //public abstract void run()
}

public class LambdaEx1 {

  //매개변수의 타입이 LambdaFunction인 메서드
    static void execute(LambdaFunction f) {
        f.run();
    }
    //반환 타입이 LambdaFunction인 메서드    
    static LambdaFunction getMyFunction() {
        LambdaFunction f = () -> System.out.println("f3.run()");
        return f;
    }

    public static void main(String[] args) {
      //람다 식으로 LambdaFunction run()을 구현
        LambdaFunction f1 = ()->System.out.println("f1.run()");

        LambdaFunction f2 = new LambdaFunction(){//익명 클래스로 run()을 구현
            @Override
            public void run() {
                System.out.println("f2.run()");
            }
        };

        LambdaFunction f3 = getMyFunction();//이미 함수로 LambdaFunction의 run을 구현 
        f1.run();
        f2.run();
        f3.run();

        execute(f1);
        execute(()->System.out.println("run()"));
    }
}

'ProgramLanguage > Java' 카테고리의 다른 글

Java 와 객체 지향  (0) 2019.12.03
Java jar파일 만들기  (0) 2019.08.04
인터페이스와 추상클래스  (0) 2019.06.10
익명클래스(Anonymous Class)  (0) 2019.06.08
Java OutOfMemoryError  (0) 2017.12.18

+ Recent posts