람다식

JinJinJara·2023년 11월 10일
0

TIL

목록 보기
13/19

람다식이란?

객체지향 언어인 자바에서 함수적 프로그래밍 지원 기법


기본 용어 정리

  • 함수 : 기능, 동작을 정의

    void abc(){ // 기능 및 동작 }
  • 메서드 : 클래스 또는 인터페이스 내부에서 정의된 함수

     class A{
     	void abc() { // 기능 및 동작 }
     }
  • 함수형 인터페이스 : 내부에 단 1개의 추상 메서드만 존재하는 인터페이스

    interface A{
    	public abstract void abc();
    }

함수적 프로그래밍과 객체지향형 개념적 비교

  • 함수적 프로그래밍에서의 함수 사용
    • 순서

      1. 함수 독립적 정의 및 구현

      2. 함수 이름 바로 사용
        (자주 사용하는 기능 구현 - 람다식 표현)

        자바는 새로운 함수 문법을 정의한 것이 아니라 이미 있는 인터페이스를 빌어 람다식을 표현

  • 객체지향형 프로그래밍에서의 함수(=기능) 사용
    • 순서
      1. 클래스 내부에 함수 구현 (독립적x)
      2. 객체 생성
      3. 참조변수 이용해 함수 실행

객체지향형 프로그래밍에서 메서드 활용

  1. 익명 이너 클래스
  // 1. 인터페이스 정의
  interface A{
  	void abc();
  }
  
  // 2. 익명이너클래스
  A a = new A(){
     void abc(){
     	// 메서드 내용
     }
  }
  
  // 3. 메서드 사용
  a.abc()
  
  
  1. 람다식
  // 1. 인터페이스 정의
  interface A{
  	void abc();
  }
  
  // 2. 익명이너클래스
  A a = A() ->{
     // 메서드 내용 (람다식)
     }
  }
  
  // 3. 메서드 사용
  a.abc()
  • 공통점 : void abc() 안에 메서드 내용 구현됨
  • 차이점 : 공통 사향 생략됨
    • new A(), abc 메서드 이름 +) 매개변수 타입
    • 화살표 사용

즉, 람다식은 익명이너클래스를 약식으로 표현한 문법적 형태로 볼 수 있다.


📌 주의사항

모든 인터페이스의 구현 메서드는 람다식으로 변환할 수 없다.

함수적 인터페이스의 메서드만 람다식으로 표현 가능하다.

  • 인터페이스 안에 추상메서드가 2개 이상 있는 경우 람다식에 사용되는 것이 어떤 메서드 인지 알 수 없기 때문

람다식의 가장 큰 특징은 정의하는 것이다.

  • 인터페이스 내의 추상메서드를 람다식으로 기능을 부여해 사용하기 때문

람다식 약식 표현

  1. 실행문이 한개인 경우 중괄호 생략가능
A a = () -> System.out.println("테스트");
  1. 매개변수 타입 생략 가능
A a = (a, b) -> { ... };
  1. 매개변수가 1개인 경우, 소괄호 생략 (타입도 함께 생략해야 함)
A a = b -> { ... };
  1. 실행문으로 return 만 있는 경우, return 생략
A a = (a, b) -> a+b;

람다식 활용

  • 메서드 구현하는 빈 공간을 채우는 방법은 3가지 이다.
  1. 익명이너클래스 내 구현 메서드의 약식(람다식)표현 →함수적 인터페이스만 가능
  1. 메서드 참조 (인스턴스 메서드 참조 Type1, 정적 메서드 참조, 인스턴스 메서드 참조 Type2)
  1. 생성자 참조 (배열 생성자 참조, 클래스 생성자 참조)

활용1. 익명이너클래스

// 함수형 인터페이스
interface A{
	void method(int a, double b);
}

// 1. 익명이너 클래스 활용
A a = new A(){
	public void method(int a, double b){
    	return a+b
    }
}

// 2. 람다식 활용
A a1 = (int a, double b) -> {return ...};
A a2 = (a, b) -> a+b;

활용2-1. 인스턴스 메서드 참조 (Type 1)

이미 정의된 인스턴스 메서드 참조

interface A{
	void abc();
}
class B{
	/* 인스턴스 메서드 */
	void bcd(){
    	System.out.println("메서드");
    }
}
  • 익명이너클래스 방법으로 표현하면.
A a = new A(){
	public void abc(){
    	B b = new B();
        b.bcd();
    }
}
  • abc() 메서드 기능 = B 객체tmp() 메서드 기능

서로 같다는 것을 확인할 수 있다. 이를 람다식으로 줄이면,

  • 람다식 표현식
// 람다식으로 표현
A a = () ->
	B b = new B();
    b.bcd();

// 축약!
B b = new B();
A a = b ::bcd;

클래스객체:: 인스턴스메서드 이름

클래스 객체 속 인스턴스메서드 안에 있는 내용으로 람다식을 채워라!

  • 예시1
interface A{
	void abc(int k);
}

A  a = new A(){
	public void abc(int k){
    	System.out.println(k);
    }
}

A  a = System.out::println;
a.abc(30);

활용2-2. 정적 메서드 참조

이미 정의된 정적 메서드 참조

interface A{
	void abc();
}

class B{
	static void bcd(){
		System.out.println("메서드");
    }
}

// 익명이너클래스 방법
A a = new A(){
	public void abc(){
    	B.bcd();
    }
}
// 람다식으로 표현
A a = () ->
	B.bcd();

// 축약!
A a = B::bcd;

클래스이름:: 인스턴스메서드 이름

  • 정적 메서드 참조를 위해서는
    리턴타입과 매개변수가 동일해야 함

활용2-3. 인스턴스 메서드 참조 (Type 2)

첫번째 매개변수로 전달된 객체의 메서드를 참조하는 경우

interface A{
	void abc(B b, int k);
}

class B{
	static void bcd(int k){
		System.out.println(k);
    }
}

// 익명이너클래스 방법
A a = new A(){
	public void abc(B b, int k){
    	b.bcd(k);
    }
}
// 람다식으로 표현
A a = (b, k) ->
	b.bcd(k);

A a = B::bcd;
  • 클래스이름:: 인스턴스메서드 이름

    • 클래스 객체를 만들 필요 없이, 첫번째 매개변수로 객체를 전달해준다.

    • 표현 방법은 정적 메서드와 동일!

      • static 메서드가 아님에도 클래스 이름을 람다식에 썼다는 점에서
        활용2-2. 정적 메서드 참조와 다름
  • 예제
A a = String::length;
a.abc("안녕"); // 2
  • length 는 정적메서드가 아니기 때문에, 인스턴스 메서드이다.
interface A {
	int abc(String str);
}

A a = new A(){
	public int abc(String str){
    	return str.length();
    }
}

A a = (str)->str.length();

활용3.1 배열 생성자 참조

배열의 new 생성자를 참조하는 경우
interface 메서드이 리턴타입 = 배열객체

interface A {
	int[] abc(int len);
}

A a = new A(){
	public int[] abc(int len){
    	return new int[len];
    }
}

A a = (len)->new int[len];

// 축약!
A a = int[]::new;

배열 타입 ::new

  • 배열 생성자 참조를 위해서는
    인터페이스 메서드의 매개변수로, 배열의 길이를 전달

활용3.2 클래스 생성자 참조

클래스의 new 생성자를 참조하는 경우
interface 메서드의 리턴타입 = 클래스 객체

interface A {
	B abc(int k);
}

class B{
	B(){ // 첫번째 생성자 }
    B(int k) { // 두번째 생성자 }
}
  1. 첫번째 생성자
A a = new A(){
	public B abc(){
    	return new B;
    }
}

A a = ()->new B();

// 축약! -> 첫번째 생성자를 이용한 객체 생성
A a = B::new;
  1. 두번째 생성자
A a = new A(){
	public B abc(int k){
    	return new B;
    }
}

A a = (k)->new B(k);

// 축약! -> 두번째 생성자를 이용한 객체 생성
A a = B::new;

클래스이름:: 인스턴스메서드 이름

  • 클래스 생성자 참조를 위해서는
    인터페이스 메서드의 매개변수에 따라 생성자 선택

출처 :
Do it! 자바 완전 정복 동영상 강의 중 람다식...

0개의 댓글