ABOUT ME

읽히는 로직을 구현하고 싶습니다.

Today
Yesterday
Total
  • 람다 표현식(lambda Expression)
    JAVA/스트림, 컬렉션 프레임워크, 람다 2024. 6. 6. 17:22

     

     

    ✔ 람다 표현식

    java SE 8부터 나온 람다 표현식은 메서드를 하나의 식으로 표현한 것을 말한다.

    하나의 추상 메서드를 가지고 있는 인터페이스를 가지고 있어야 사용이 가능하다.
    무명 클래스를 화살표 기호를 사용하여 짧게 줄일 수 있다.

    (parameter ,,,) -> { body }

    만약, 람다식이 하나의 메서드를 호출하는 경우 ::으로 표현할 수 있다.

    1) 클래스 이름 :: 메서드 이름
    
    2) 참조변수 :: 메서드 이름

    가독성이 좋은 쪽으로 선택하자.


    💻 코드로 보기

    interface HelloInter {
    	int calcData(int a, int b);
    }
    
    public class MyLambda1 implements HelloInter {
        @Override
        public int calcData(int a, int b) {
            return a + b;
        }
        public static void main(String[] args) {
            System.out.println(my.calcData(3, 4));
        }
    }

     

    interface HelloInter {
    	int calcData(int a, int b);
    }
    
    public class MyLambda1 implements HelloInter {
        public static void main(String[] args) {
            HelloInter inter = (x, y) -> x + y;
            System.out.println("두 수를 더한 결과 : "+inter.calcDate(4,6));
        }
    }

     

    클래스를 작성하고 객체를 생성하지 않아도 메서드를 사용할 수 있다.
    자바에서는 클래스의 선언과 동시에 객체를 생성하므로, 단 하나의 객체만을 생성할 수 있는 클래스를 익명클래스라고 한다.
    람다 표현식을 사용하면, 불필요한 코드를 줄여주고 가독성을 높여준다.

     

     

    👏 정리

    • 매개변수가 하나인 경우 괄호()를 생략할 수 있다.
    • 매개변수 타입을 추론할 수 있는 경우, 타입을 생략할 수 있다.
    • body에 문장이 1개이면 중괄호{}를 생략할 수 있다.
    • body에 return문 1개인 경우 중괄호{} 생략이 가능하다.

     

     

     

    📝 인터페이스에 추상 메서드가 2개있다면?

    interface HelloInter {
    	int calcData(int a, int b);
    	int calcData2(int a, int b);
    }
    
    public class MyLambda1 implements HelloInter {
    
    	@Override
    	public int calcData(int a, int b) {
    		// 인터페이스의 추상 메서드를 오버라이딩 : 전통적인 방법
    		return a + b;
    	}
    //
    //	@Override
    //	public int calcData2(int a, int b) {
    //		return 0;
    //	}
    
    	public static void main(String[] args) {
    
    		System.out.println();
    		HelloInter inter = (x, y) -> x + y;
    		
    		System.out.println(inter.calcData(4, 5));
    	}
    
    }

     

     

    위의 경우에서는  HelloInter inter = (x, y) -> x + y; 쪽에서 아래와 같은 오류 메시지가 출력된다.

     

    The target type of this expression must be a functional interface

     
    추상 메서드가 1개인 경우 메서드의 이름을 사용하지 않고 찾아갈 수 있다.
     

     

     

    💻 @FunctionalInterface

    여러 개의 디폴트 메서드가 있더라도 추상 메서드가 오직 하나 함수형 인터페이스를 말한다.

    @FunctionalInterface
    interface HelloInter {
    	int calcData(int a, int b);
    	int calcData2(int a, int b);
    }

    이런 경우, 아래와 같은 오류메시지가 나온다.

    Invalid '@FunctionalInterface' annotation; HelloInter is not a functional interface

     
    람다식은 추상메서드가 1개인 경우에 사용할 수 있다.
    위의 어노테이션도 마찬가지로 추상 메서드가 오직 한 개인 함수형 인터페이스에 사용할 수 있다.
    때문에 @FunctionalInterface는 람다표현식을 사용할 때 많이 사용되는 어노테이션이다.

    👻 정리

    람다식은 객체인가? 메서드인가?
    람다는
    함수형 인터페이스를 구현하는 인터페이스이다.
    함수형 인터페이스가 가지고 있는 1개의 추상메서드와 람다가 1:1 매칭을 하게된다.

     

     


     

     

     

    ✔ 함수형 인터페이스 (인자가 없는 추상메서드 처리)

    ⌨ 코드 (전통적인 방법 + 람다식 표현)

    @FunctionalInterface
    interface MyInter { // 함수형 인터페이스
    	void aaa();
    }
    
    public class MyLambda2 {
    
    	public static void main(String[] args) {
    		// 1. 인자가 없는 추상메서드 처리 : 전통적인 방법
    		MyInter inter = new MyInter() {
    			@Override
    			public void aaa() {
    				System.out.println("익명 클래스의 aaa 메소드 오버라이딩");
    			}
    		};
    		inter.aaa();
    
    		// 람다식으로 표현 1
    		MyInter inter2 = () -> System.out.println("일명 클래스 aaa 메서드 오버라이딩 : 람다");
    		inter2.aaa();
    
    		// 람다식으로 표현 2
    		MyInter inter3 = () -> {
    			int imsi = 10;
    			System.out.println("람다식으로");
    			System.out.println("복수의 명령문 처리");
    			System.out.println("imsi : " + imsi);
    		};
    		inter3.aaa();
    
    	}
    }

     

     

     

     


     

     

     

    ✔ 인자가 있는 추상메서드 처리

    💻 코드로 보기

    @FunctionalInterface
    interface MyInterArg {
    	void bbb(int a, int b);
    }
    
    public class MyLambda2 {
    
    	public static void main(String[] args) {
        	MyInterArg interArg = new MyInterArg() {
    
    			@Override
    			public void bbb(int a, int b) {
    				System.out.println("두 수의 합은" + (a + b));
    			}
    		};
    		interArg.bbb(3, 4);
    
    		// 람다식으로 표현2 : arg가 1개일 경우 (a) -> 또는 a ->로 표현 가능
    		MyInterArg interArg2 = (a, b) -> System.out.println("람다로 두 수의 합은" + (a + b));
    		interArg2.bbb(3, 4);
        }
    }

     

     

     

     

     


     

     

     

     

    ✔ 반환값이 있고 인자가 있는 추상메서드 처리

    💻 코드로 보기

    @FunctionalInterface
    interface MyInterArgReturn {
    	int ccc(int a, int b);
    }
    
    public class MyLambda2 {
    
    	public static void main(String[] args) {
        	MyInterArgReturn argReturn = new MyInterArgReturn() {
    
    			@Override
    			public int ccc(int a, int b) {
    				System.out.println("ccc 처리");
    				return a + b;
    			}
    		};
    		int result = argReturn.ccc(5, 6);
    		System.out.println("두 수를 더한 결과 : " + result);
    
    		// 람다식으로 표현 3
    		MyInterArgReturn argReturn2 = (m, n) -> (m + n);
    
    		MyInterArgReturn argReturn3 = (m, n) -> {
    			System.out.println("람다 수행 ");
    			return m + n;
    		};
    		int result2 = argReturn3.ccc(5, 6);
    		System.out.println("두 수를 더한 결과2 : " + result2);
    		
        }
    }

     

     

     

     

     


     

     

     

     

    ✔ 표준 함수형 인터페이스

    람다식을 사용하기 위해서 늘 함수형 인터페이스를 정의해야하는가?
    아니다. 많은 사람들이 이미 만들어 놓은 함수형 인터페이스가 있다.

    우아한 테크 <람다와 스트림>

    📑 Runnable

    매개변수가 없고 반환값이 없는 경우 사용할 수 있다.

    📑Supplier<T>

    매개 변수가 없고 반환값이 있는 경우 사용할 수 있다.

     

    📑Consumer<T>

    매개변수가 있고 반환값이 없는 경우 사용한다.

     

    📑Function<T,R>

    매개변수가 있고 반환값이 있는 경우 사용한다.

    📑Predicate<T>

    매개변수가 있고 반환값이 boolean형인 경우 사용한다.


    표준 함수형 인터페이스 사용 장점
    디폴트 메서드를 제공한다.
    앞서 정리했듯 함수형 인터페이스는 1개의 추상메서드가 존재한다. 다른 디폴트 메서드, 필드가 있을 수 있다.
    사용하는 인터페이스에 따라 디폴트 메서드를 호출하여 새로운 객체를 생성할 수 있다.

     

     

    🎈 정리

    무명(익명) 클래스는 일회용 클래스이다.
    즉, 람다로 표현하는 것도 일회용 클래스이다.
    무명클래스를 짧게 표현하는 방식이다.

Designed by Tistory.