ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java] 람다식 - 메소드 참조
    CSE/Java 2015. 9. 23. 14:50

    람다식은 여러 절로 구성되어 있습니다.



    Intro.

    람다식 기본 문법 & 타겟 타입과 함수적 인터페이스

    클래스 멤버와 로컬 변수 사용

    표준 API의 함수적 인터페이스1





    메소드 참조

     메소드 참조(Method Reference)는 말 그대로 메소드를 참조해서 매개 변수의 정보 및 리턴 타입을 알아내어, 람다식에서 불필요한 매개 변수를 제거하는 것이 목적입니다.


     람다식은 종종 기존 메소드를 단순히 호출하는 경우가 많습니다.


     예를 들어 두 개의 값을 받아 큰 수를 리턴하는 Math 클래스의 max() 정적 메소드를 호출하는 람다식은 다음과 같습니다.



    1
    2
    (left, right) -> Math.max(left, right);
     
    cs




     

     람다식은 단순히 두 개의 값을 Math.max() 메소드의 매개값으로 전달하는 역할만 하기 때문에 다소 불편해 보입니다.


     이 경우에는 다음과 같이 메소드 참조를 이용하면 매우 깔끔하게 처리할 수 있습니다.



    1
    2
    Math :: max;
     
    cs





     메소드 참조도 람다식과 마찬가지로 인터페이스의 익명 구현 객체로 생성되므로 타겟 타입인 인터페이스 추상 메소드가 어떤 매개 변수를 가지고, 리턴 타입이 무엇인가에 따라 달라집니다.


     IntBinaryOperator 인터페이스는 두 개의 int 매개값을 받아 int 값을 리턴하므로 Math :: max 메소드 참조를 대입할 수 있습니다.



    1
    2
    IntBinaryOperator operator = Math :: max;
     
    cs





     메소드 참조는 정적 또는 인스턴스 메소드를 참조할 수 있고, 생성자 참조도 가능합니다.






     정적 메소드와 인스턴스 메소드 참조

      정적 메소드를 참조할 경우에는 클래스 이름 뒤에 :: 기호를 붙이고 정적 메소드 이름을 기술하면 됩니다.


     

    1
    2
     
    클래스 :: 메소드;
    cs





      인스턴스 메소드일 경우에는 먼저 객체를 생성한 다음 참조 변수 뒤에 :: 기호를 붙이고 인스턴스 메소드 이름을 기술하면 됩니다.



    1
    참조 변수 :: 메소드;
    cs





      다음 예제는 Calculator의 정적 및 인스턴스 메소드를 참조합니다. 람다식이 메소드 참조로 대체되는 것을 기억해둡시다.



     * Calculator.java


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    package lambda;
     
    public class Calculator {
        public static int staticMethod(int x, int y) {
            return x + y;
        }
     
        public int instanceMethod(int x, int y) {
            return x + y;
        }
    }
     
    cs

     





     * MethodReferenceExam.java


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
     
    package lambda;
     
    import java.util.function.IntBinaryOperator;
     
    public class MethodReferenceExam {
     
        public static void main(String[] args) {
            IntBinaryOperator operator;
     
            operator = (x, y) -> Calculator.staticMethod(x, y);
            System.out.println("결과1: " + operator.applyAsInt(15));
     
            operator = Calculator::staticMethod;
            System.out.println("결과2: " + operator.applyAsInt(51));
     
            Calculator calc = new Calculator();
            operator = (x, y) -> calc.instanceMethod(x, y);
            System.out.println("결과3: " + operator.applyAsInt(48));
     
            operator = calc::instanceMethod;
            System.out.println("결과4: " + operator.applyAsInt(84));
        }
     
    }
     
    cs





     








     매개 변수의 메소드 참조

      메소드는 람다식 외부의 클래스 멤버일 수도 있고, 람다식에서 제공되는 매개 변수의 멤버일 수도 있습니다.


      이전 예제는 람다식 외부의 클래스 멤버인 메소드를 호출하였습니다. 그러나 다음과 같이 람다식에서 제공되는 a 매개 변수의 메소드를 호출해서 b 매개 변수를 매개값으로 사용하는 경우도 있습니다.



    1
    2
    (a, b) -> { a.instanceMethod(b); }
     
    cs




      이것을 메소드 참조로 표현하면 다음과 같습니다. a의 클래스 이름 뒤에 :: 기호를 붙이고 메소드 이름을 기술하면 됩니다. 작성 방법은 정적 메소드 참조와 동일하지만, a의 인스턴스 메소드가 참조되므로 전혀 다른 코드가 실행됩니다.




    1
    2
    Class :: instanceMethod
     
    cs




      다음 예제는 두 문자열이 대소문자와 상관없이 동일한 알파벳으로 구성되어 있는지 비교합니다.


      비교를 위해 사용된 메소드는 String의 인스턴스 메소드인 compareToIgnoreCase()입니다.


      a.compareToIgnoreCase(b)로 호출될 때 사전 순으로 a가 b보다 먼저 오면 음수를, 동일하면 0, 나중에 오면 양수를 리턴합니다.













     * ArgumentMethodReferencesExam.java


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
     
    package lambda;
     
    import java.util.function.ToIntBiFunction;
     
    public class ArgumentMethodReferencesExam {
     
        public static void main(String[] args) {
            ToIntBiFunction<StringString> function;
     
            function = (a, b) -> a.compareToIgnoreCase(b);
            print(function.applyAsInt("Java8""JAVA8"));
     
            function = String::compareToIgnoreCase;
            print(function.applyAsInt("JAVA8""Java8"));
        }
     
        public static void print(int order) {
            if (order < 0) {
                System.out.println("사전순으로 먼저 나옵니다.");
            } else if (order == 0) {
                System.out.println("동일한 문자열입니다.");
            } else {
                System.out.println("사전순으로 나중에 나옵니다.");
            }
        }
     
    }
     
    cs










     생성자 참조

      메소드 참조(method references)는 생성자 참조도 포함됩니다.


      생성자를 참조한다는 것은 객체 생성을 의미합니다. 단순히 메소드호출로 구성된 람다식을 메소드 참조로 대치할 수 있듯이, 단순히 객체를 생성하고 리턴하도록 구성된 람다식은 생성자 참조로 대치할 수 있습니다.


      다음 코드를 보면 람다식은 단순히 객체 생성 후 리턴만 합니다.



    1
    (a, b) -> { return new Class(a, b); }
    cs




      이 경우, 생성자 참조로 표현하면 다음과 같습니다. 클래스 이름 뒤에 :: 기호를 붙이고 new 연산자를 기술하면 됩니다.


      생성자가 오버로딩되어 여러 개가 있을 경우, 컴파일러는 함수적 인터페이스의 추상 메소드와 동일한 매개 변수 타입과 개수를 가지고 있는 생성자를 찾아서 실행합니다. 


      만약 해당 생성자가 존재하지 않으면 컴파일 오류가 발생합니다.



    1
    2
    Class :: new;
     
    cs




      다음 예제는 생성자 참조를 이용해서 두 가지 방법으로 Member 객체를 생성합니다.




     * Member.java


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
     
    package lambda;
     
    public class Member {
        private String name;
        private String id;
     
        public Member() {
            System.out.println("Member 실행");
        }
     
        public Member(String id) {
            System.out.println("Member (String id ) 실행");
            this.id = id;
        }
     
        public Member(String name, String id) {
            super();
            System.out.println("Member (String name, String id) 실행");
            this.name = name;
            this.id = id;
        }
     
        public String getName() {
            return name;
        }
     
        public void setName(String name) {
            this.name = name;
        }
     
        public String getId() {
            return id;
        }
     
        public void setId(String id) {
            this.id = id;
        }
     
    }
     
    cs







     * ConstructorReferenceExam.java


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    package lambda;
     
    import java.util.function.BiFunction;
    import java.util.function.Function;
     
    public class ConstructorReferenceExam {
     
        public static void main(String[] args) {
            Function<String, Member> function1 = Member::new;
            Member member1 = function1.apply("Jolie");
     
            BiFunction<StringString, Member> function2 = Member::new;
            Member member2 = function2.apply("쥴리""Jolie");
        }
     
    }
     
    cs






     * 이 포스트은 서적 '이것이 자바다' 를 참고하여 작성한 포스트입니다.

    댓글

Designed by Tistory.