코드스테이츠_국비교육/[Section1]

18.01_람다_22.09.15

생각없이 해도 생각보다 좋다. 2022. 9. 15. 21:47

학습 키워드

  • 람다식
  • 함수형 인터페이스
  • 람다식 변환(메서드 참조 방식)

람다, Lambda

>의미 및 특징

: 메서드를 하나의 식으로 표현하기 위한 자바의 문법요소

: 함수형 인터페이스를 간소하게 구현하기 위한 문법요소이다.
: 람다식 사실 이름 없는 익명 객체이다.

: 람다식이 객체이기 때문에 람다식을 인자로 전달하거나, 같은 참조변수에 다른 람다식을 새로 구현하는 등 객체의 특성을 지닌다.

//람다식 : 람다로 표현된 문장을 지칭하는 용어.

>함수형 인터페이스

: 딱 하나의 추상 메서드가 존재하는 인터페이스

: 람다로 구현가능한 인터페이스

//참고

//추상 메서드가 하나만 있다면 다른게 무엇이 있어도 함수형 인터페이스이다.

//다른게 있어도 람다로 구현할 것은 오직 추상 메서드 하나 뿐...

>익명 클래스(익명 객체)

: 내부 클래스처럼 내부에서 클래스를 생성함

: 클래스 생성과 동시에 객체도 생성함

: 클래스를 상속하는 하위 클래스, 혹은 인터페이스를 구현하는 클래스면 익명 객체로 만들 수 있다.

참조형(클래스명) 참조변수 = new 생성자(){...};

>람다식의 필요성에 대한 단계별 이해(글)

//참고한 책과 자료를 바탕으로 제 임의대로 해석한 람다식입니다. 정확한 것은 아닙니다...

//개인적으로 익명 객체에서 시작되는 람다의 이야기가 이해하기 어려워서 함수형 인터페이스부터 시작하였습니다.

  • 인터페이스를 사용하는 방법

: 인터페이스는 필수적으로 구현하는 과정을 거쳐야 사용 가능하다.

: 인터페이스를 구현하기 위해서는 클래스가 필요하다.

  • 클래스의 간소화

: 인터페이스 중 함수형 인터페이스는 단발적으로 사용할 인터페이스이다.

: 함수형 인터페이스를 구현하기 위해 클래스를 만들어서 사용하는 것이 손해이고, 코드도 길어 가독성이 떨어지게 된다.

: 이러한 이유로 익명 클래스(객체)를 사용하기로 한다.

  • 익명 클래스(객체)의 간소화

: 역시나 프로그램 언어의 진화는 코드의 간소화로 이루어진다.

: 익명 객체는 굉장히 길고 지저분한 코드처럼 보인다.

: 이를 해결하고자 '람다'라는 문법 요소를 만든다.

  • 람다의 단순화 과정

: 익명 객체를 참조하는 참조변수의 참조형. 즉, 인터페이스만 봐도 추론가능 한 부분을 생략한다.

: 'new 생성자()'를 생략한다. 해당 익명 객체가 함수형 인터페이스를 구현하기 위한 식임을 이미 알기에. 

: 메소드 제어자와 메소드 명을 생략한다. 어차피 함수형 인터페이스는 메소드가 하나 뿐이니까.

: 남은 건 매개 변수와 메소드 구현 몸체인데, 여기서 람다식임을 알 수 있게 특별한 표현을 사용한다.

: 매개 변수가 해당 몸체에 사용될 것이라는 의미로 화살표(->)를 만들어주면 람다식 완성!

>람다식의 필요성에 대한 단계별 이해(코드)

1. 가장 기본적인 방식(근본)

//함수형 인터페이스
interface Watch{
    public abstract void time(String s); //public abstract 생략 가능
}
//인터페이스를 사용하기 위한 클래스 구현
class WhatTime implements Watch{
    public void time(String s){
        System.out.println("현재 시간: " + s);
    }
}
//main메서드에서 객체를 생성하여 사용.
public class Main {
    public static void main(String[] args) {
        Watch time1 = new WhatTime();
        time1.time("23시");
    }
}

2. 익명 클래스 사용(발전1)

interface Watch{
    public abstract void time(String s); //public abstract 생략 가능
}
//내부에서 구현 클래스(객체)를 냅다 생성하기.
public class Main {
    public static void main(String[] args) {
        Watch time1 = new Watch() {
            public void time(String s) {
                System.out.println("현재 시간: " + s);
            }
        }; //Watch time1 문장의 종결점(;)
    }
}

3. 람다식 표현

//함수형 인터페이스
interface Watch{
    public abstract void time(String s); //public abstract 생략 가능
}
//람다식 표현(new,생성자,메서드 제어자 및 이름 생략
public class Main {
    public static void main(String[] args) {
        Watch time1 = (String s) -> {System.out.println("현재 시간: " + s);};//Watch time1 문장의 종결점(;)
    }
}

>생략의 생략, 람다식 내에의 간소화

1. 매개변수 O, 반환값 X

//함수형 인터페이스
interface Watch{
    public abstract void time(String s); //public abstract 생략 가능
}
//람다식 표현(new,생성자,메서드 제어자 및 이름 생략
public class Main {
    public static void main(String[] args) {
        //(1) 람다 기본형, 매개변수가 많을 경우는 쉼표(,)로 구분
        Watch time1 = (String s) -> {System.out.println("현재 시간: "+ s);};
        //(2) 매개변수 타입 생략(추론 가능)
        Watch time2  = (s) -> {System.out.println("현재 시간: "+ s);};
        //(3) 중괄호 생략(문장이 한 줄일 경우 가능)
        Watch time3  = (s) -> System.out.println("현재 시간: "+ s);
        //(4) 매개변수 소괄호 생략(매개변수가 하나일 경우 가능)
        Watch time4  = s -> System.out.println("현재 시간: "+ s);
    }
}

 

2. 매개변수 O, 반환값 O

//함수형 인터페이스
interface Watch{
    public abstract int time(int a, int b); //public abstract 생략 가능
}
//람다식 표현(new,생성자,메서드 제어자 및 이름 생략
public class Main {
    public static void main(String[] args) {
        //(1) 람다 기본형
        Watch time1 = (int a, int b) -> {return a + b;};
        //(2) 매개변수 자료형 생략
        Watch time2 = (a, b) -> {return a + b;};
        //(3) return 과 중괄호 생략
        Watch time3 = (a, b) -> a + b;
        //return 의 경우, 기본적으로는 생략 불가
        //위의 식처럼 문장 실행 후 하나의 값으로 나올 때, 생략 가능
        //return 을 쓸거면 중괄호도 꼭 써야함
        //return 을 안쓸거면 중괄호도 꼭 안써야함
        //일반적으론 return 까지 생략함.
    }
}

3. 매개변수 X

//함수형 인터페이스
interface Watch{
    public abstract int time(); //public abstract 생략 가능
}
//람다식 표현(new,생성자,메서드 제어자 및 이름 생략
public class Main {
    public static void main(String[] args) {
        //(1) 매개변수 소괄호는 꼭 써줘야함. '실행'의 의미
        Watch time1 = () -> {...};
        //중괄호 몸체 내용은 반환형 고려해서 구현.
    }
}

>제네릭 기반의 함수형 인터페이스 람다식 구현(람다 응용)

: 사실 별 거 없음. 어차피 인터페이스 참조변수 선언할 때 타입을 지정하기 때문에 람다식 구현은 그대로다.

//함수형 제네릭 인터페이스
interface Watch<T> {
    T time(T a, T b);
}
public class Main {
    public static void main(String[] args) {
        Watch<Integer> time1 = (a, b) -> a + b;
        //참조변수 선언 시, 타입을 지정함!!
        //람다 표현에는 큰 변화가 없음.
        //타입에 맞는 몸체를 구현하면 됨.
    }
}