ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 람다식
    언어/JAVA 2023. 7. 5. 17:07

     

    1. 람다식이란? 

     

    - 메서드를 하나의 식으로 표현 

    - 함수를 간략,명확한 식으로 표현 할 수 있게 해준다.

    - 람다식으로 메서드를 표현하면, 이름과 반환값이 사라지므로, 익명함수라고도 한다.

     

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

     

    *모든 메서드는 기본적으로 클래스에 포함되어 있어야하므로, 필요한 메서드를 만드는 작업이 복잡하다.

    *람다식은 이를 간결하게 처리할 수 있도록 해준다. 

    *람다식을 통해 매개변수를 전달하여 값을 return받을 수 도 있지만, 람다식 자체를 매개변수로 사용할 수 있다.

     

    1.2 람다식 작성

     

    - 메서드의 이름과 반환타입을 제거하고 선언부와 몸통부 사이에 ->를 추가한다.

    - 반환값이 있는 메서드의 경우 return문을 식으로 대신할 수 있다. 식의 연산결과가 자동적으로 반환값이 된다.

       (식으로 끝나면 ;를 사용하지 않는다. return을 사용하면 ;을 붙여야한다.)

    - 매개변수 타입과 반환 타입은 대부분의 경우 생략가능(추론이 됨 -> 함수형 인터페이스 확인)

     

    int max(int a, int b){ return a>b ? a: b;}
    (a,b) -> a>b? a:b
    
    void printVar(String name,int i){ System.out.println(//)}
    (String name, int i) -> System.out.println(//)

     

    1.3 함수형 인터페이스

     

    - 자바에서 모든 메서드는 클래스 내에 포함되어야한다.

    - 람다식도 특정 클래스(익명 클래스)에 포함되어 있다. 

    - 람다식을 정의하고, 이를 담아서 사용할 인터페이스를 함수형 인터페이스라고 한다.

     

    @FunctionalInterface
    interface MyFunc{
      public int max (int a, int b);
    }
    //람다식을 사용할 기본 골격만 정의
    
    //인터페이스를 구현하는 익명 클래스 구현
    MyFunc f = new MyFunc(){
       public int max (int a, int b) {
        return a>b ? a:b;  
       }
    }
    
    //람다식을 통해 이를 간단하게 구현할 수 있다.(익명 객체를 람다식으로 대체)
    MyFunc f = (a,b) -> a>b?a:b
    
    //메서드를 구현해서 익명 클래스를 생성한 것일 뿐, 메서드를 사용하려면 아래와 같이 
    //매개변수를 넣고 함수를 호출해야하듯이 람다식도 동일하다.
    int maxnum = f.max(1,2);

     

    * 위가 가능한 이유는 람다식도 익명 객체이고 MyFunc에서 구현한 익명 메서드와 람다식의 매개변수과 개수 반환값이 일치하기 때문이다.

    *위의 구현은 자바의 규칙을 어기지 않고 자연스럽다. 위와같이 람다식을 다루기 위한 인터페이스를 함수형 인터페이스라고 한다.

     

    ** 함수형 인터페이스에는 하나의 추상메서드만 정의되어 있어야한다. (static, default메서드는 개수에 제약이 없다)

     

     

    1.3.1 함수형 인터페이스 타입의 매개변수와 반환타입

     

    - 특정 메서드의 매개변수가 MyFunc타입이면, 람다식을 그대로 넣어주거나, 람다식을 참조하는 참조변수를 넣어주면

    된다. 

     

    void AMethod(MyFunc f) {f.max(1,2);}
    MyFunc f = (a,b) -> a>b ? a:b
    
    AMethod(f);
    
    // 반환 타입이 함수형 인터페이스일 수도 있다.
    
    Mtfunc myMethod() { 
    //Myfunc f = () -> {};
    //return f;
    return () -> {}}

     

    1.3.2 람다식의 타입과 형변환

     

    - 함수형 인터페이스로 람다식을 참조할 수 있는 것일 뿐, 람다식의 타입이 함수형 인터페이스의 타입과 일치하는 것은 아님

    (람다식은 익명 객체 - 익명 객체는 타입이 없음)

    - 정확히는 타입이 있지만, 컴파일러가 임의로 이름을 정한다. 

    MyFunc f = (MyFunc)(()->{});
    //위와 같은 형변환이 필요하지만, 람다식이 함수형 인터페이스의 메서드를 정확하게 구현한다면
    //형변환을 생략할 수 있다. 
    //람다식은 함수형 인터페이스로만 형변환이 가능하다.

     

    * 일반적인 익명 클래스는 외부클래스이름$번호와 같은 형식으로 타입이 결정

    * 람다식 타입은 외부클래스이름$$Lambda$번호와 같은 형식으로 결정

     

    1.3.3 외부 변수를 참조하는 람다식

     

    - 람다식도 익명 객체, 익명 클래스의 인스턴스이므로 람다식 외부에서 선언된 변수에 접근하는 규칙은 익명 클래스와 같다.

    - 람다식 내부에서 참조하는 외부지역변수는 final로 간주된다. 클래스의 인스턴스 변수는 상수로 간주하지 않는다.

    - 외부 지역변수와 같은 람다식의 매개변수 허용하지 않는다.

    class Outer
    { int val=10;
    
    class Inner{
       int val =20;
       
       void method(int i){ // 람다식에서 i를 사용하면, i는 final int i취급
         int val =30; // final int val
         i=10; //에러 상수의 값을 변경할 수 없음
         
         Myfunc f = () -> {
          System.out.println(i);
          System.out.println(val);
          System.out.println(this.val);
           System.out.println(outer.this.val);
         }
       	
       }
    }
    
    }

     

     

    2. java.util.function패키지

     

    - 대부분의 메서드의 매개변수와 반환타입은 비슷하다 (매개변수 1~2개, 반환값은 없거나 1개)

    - 지네릭 메서드로 정의하면, 메서드의 매개변수나 반환타입이 달라도 상관없다.(그때그때 달라도됨)

    - 따라서 function패키지에 자주쓰는것 정의해 둠 

    -크게 Supplier<t>, Consumer<t>, Function<T,R>, Predicate<T>, Operator<T>로 나눌 수 있다.

    - 매개변수가 두개인 경우 위의 함수형 인터페이스에서 Bi를 붙인다

    - Runnable에 void run()도 함수형 인터페이스임 (매개변수없고 반환값 없음)

     

    2.1 Supplier<T> 계열

         - 매개변수는 없고, 반환값만 있다.

         - 데이터를 공급해주는 공급자의 역할을 한다.(외부로 데이터를 리턴)

    출처: https://hudi.blog/functional-interface-of-standard-api-java-8/

     

    2.2 Consumer<T>

        

    - 매개변수만 있고, 반환값이 없다.

    - 파라미터를 입력받아 그것을 소비하는 interface이다.

    - 함수내에서 매개변수를 사용하고, 반환값이 없음으로, 내부에서 매개변수를 소비한 것으로 의미를 부여한다.

     

    출처: https://hudi.blog/functional-interface-of-standard-api-java-8/

     

    2.3 Function<T,R>

     

    - 일반적인 함수, 하나의 매개변수를 받아서 결과를 반환한다.

    - Mapping 입력->출력을 연결하는 함수형 인터페이스이다.

    - 입력타입과 출력타입은 다를 수도 같을 수도 있다. 주로 매개변수타입을 리턴타입으로 변환하는 역할을 한다.

    출처: https://hudi.blog/functional-interface-of-standard-api-java-8/

     

    2.4 Operator<T>

     

    - 입력받은 타입과 동일한 타입을 출력하는 함수형 인터페이스이다.

    - Funtion계열과 달리 입출력 타입이 다를 수 없다.

    - 매개값을 이용하여 연산 후 동일한 타입으로 리턴값을 제공하는 역할을 한다.

     

    출처: https://hudi.blog/functional-interface-of-standard-api-java-8/

     

    2.5 Predicate<T> 계열

     

     - 논리 판단을 해주는 함수형 인터페이스

     - 입력을 받아서 boolean 타입 출력을 반환한다.

     - 매개변수와 boolean 리턴값이있는 test() 메소드를 가지고 있다.

     

    출처: https://hudi.blog/functional-interface-of-standard-api-java-8/

     

    3. Function 합성 Predicate 결합 

     

    - 추상메서드 외에 default, static 메서드로 정의되어있는 메서드이다.

    Function

    default <V> Function<T,V> andThen (Function<? super R, ? extends V> after)  f.andThen(g) : f를 먼저 적용하고, g를 적용한다.
    default <V> Function<V,R> compose(Function<? super V, ? extends T> before) f.compose(g) : g를 먼저 적용하고 f를 적용한다.
    static <T> Function<T,T> indentity() 이전과 이후가 동일한 항등함수가 필요할 때 사용한다.

     

    Function<String,Integer> f = (s) -> Integer.parseInt(s,16);
    Function<Integer,String> g = (i) -> Integer.toBinaryString(i);
    Function<String,String> h = f.andThen(g);
    
    Function<Integer,String> g = (i) -> Integer.toBinaryString(i);
    Function<String,Integer> f = (s) -> Integer.parseInt(s,16);
    Function<Integer,Integer> h = f.compose(g);
    
    
    Functoin<String,String> f = Function.identity();
    // Function<String,String> f = x->x 와 같음

     

    Predicate

    default Predicate<T>  and(Pridecate<? super T> other)
    default Predicate<T>  or(Predicate<? super T> other)
    default Predicate<T> negate()
    static <T> Predicate<T> isEqual(Object targeRef)

     

    - Predicate의 논리 결합이다. 논리연산자로 &&,||,!사용하듯이 Predicate계열을 연결해서 사용한다.

     

     

    4. 메서드참조 

     

    - 람다식이 하나의 메서드만 호출하는 경우 메서드 참조라는 방식을 사용할 수 있다.

    Function<String,Integer> f = (s) -> Integer.parseInt(s)
    Function<String,Integer> f = Integer::parseInt;

    - String을 Integer로 바꾸는 과정에서 매개변수가 Integer.parseInt를 통과하는 즉 람다식이 메서드 하나만 호출해서 사용하는 간단한 람다식이라면 메서드 참조를 통해 Integer::parseInt로 고칠 수 있다. 

     

    -컴파일러가 parseInt 메서드의 선언과 지네릭 타입을 통해 매개변수와 반환값을 추정해서 간결하게 표현할 수 있도록 한다.

     

    BiFunction<String, String, Boolean> f = String::equals;
    
    //static 메서드 참조
    (x) -> ClassName.method(x) 
    ClassName::method
    
    //인스턴스 메서드 참조
    (obj,xx) -> obj.method(x)
    ClassName::method
    
    //특정 객체 인스턴스 메서드 참조
    (x) -> obj.method(x) 
    obj::method

    하나의 메서드만 호출하는 람다식은 

    클래스이름(or참조변수)::메서드명으로 바꿀 수 있다.

     

    //생성자 메서드 참조
    
    Supplier<MyClass> s = MyClass::new
    
    Function<Integer,MyClass> f =(i) -> new MyClass(i);
    Function<Integer,MyClass> f1 = MyClass::new;
    
    Function<Integer,int[]> f = int[]::new;

     

     

    참고자료: 자바의 정석 -남궁성 저

     

    https://hudi.blog/functional-interface-of-standard-api-java-8/

     

    자바 8 표준 API의 함수형 인터페이스 (Consumer, Supplier, Function, Operator, Predicate)

    이 글은 이것이 자바다의 내용을 참고하여 작성되었다. 학습 동기 우테코 미션 중, 특히 Stream 을 사용하면서 매개변수에 낯선 타입을 전달 받는 메소드를 많이 마주치게 되었다. 추후 알아보니

    hudi.blog

    https://ttl-blog.tistory.com/207

     

    [JAVA] 자바의 표준 함수형 인터페이스

    자바의 표준 함수형 인터페이스 종류 자바 8부터 표준 API로 제공되는 함수형 인터페이스 java.util.function 패키지에 포함되어 있다. 매개타입으로 사용되어 람다식을 매개값으로 대입할 수 있도록

    ttl-blog.tistory.com

     

    '언어 > JAVA' 카테고리의 다른 글

    중첩 선언과 익명 객체  (0) 2023.07.07
    상속,동적생성  (0) 2023.07.06
    객체지향 - 캡슐화  (0) 2023.06.12
    자바 - 입출력(I/O) (1) 바이트기반 스트림/ 문자기반 스트림  (0) 2023.05.14
    자바 - 열거형(enums)  (0) 2023.03.26
Designed by Tistory.