ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 221220 자바 13 (스레드, 람다) : 람다식이 뭘까요?
    스타터스 백엔드 3기 2022. 12. 20. 21:57

    하루입니다.

     


     

    람다식이란?

    • 메서드를 하나의 식으로 정리한 것이다.
    • 함수를 간략하면서도 명확하게 표현할 수 있게 해준다.
    • 메서드 -> 람다식 : 이 경우 이름과 반환값이 없어지므로, 익명 함수라고도 한다.
    • 1.8이후 디폴트 메소드 + 스테틱 메소드 여러 개 정의 가능하게 되었다.
    • 함수형 인터페이스란 1개의 추상 메소드를 갖는 인터페이스이다.
    • 람다식 대상 함수형 인터페이스이다
    • 람다 함수를 사용하기 위해서는 메소드의 매개변수가 @FunctionalInterface로 선언된 인터페이스여야 한다.

     

     

    람다식 작성하기

    • 람다식에서 이름,  객체생성, 오버라이딩한 메소드 이름을 모두 생략해도 되는 이유는?
    • 함수형 인터페이스 안에 추상메소드가 한 개만 있기에 굳이 지정하지 않아도 그 메소드인지 알기 때문이다.
    • 매개변수와 내용만 있으면 된다.

     

    1. 이 식을 람다로 바꿔 보자.
    int max(int a, int b) {
        return a > b ? a : b;
    }
    
    2. 이름 생략 후 ->를 넣자.
    (int a, int b) -> {
        return a > b ? a : b;
    }
    
    3. 매개변수 타입은 생략 가능하다.
    (a, b) -> { return a > b ? a : b; }
    
    4. { } 안의 문장이 하나이며 return이 아닌 경우, 생략 가능하다.
       이 경우, ;도 생략해야 한다.
    (a, b) -> a > b ? a : b
    
    5. { } 안의 문장이 하나가 아니며, return이 있는 경우 생략 불가하다.
    (a, b) -> return a*b				==>  ERROR
    (a, b) -> { return a*b; }

     

     

    1. 매개변수가 하나일 때는 ( )를 생략 가능하다.
    a -> a*a
    
    2. 매개변수가 하나라도 타입이 있는 경우는 ( )를 생략 불가하다.
    (int a) -> a*a

     

     

    int sumArr(int[] arr) {
    	int sum = 0;
        for(int i:arr) {
        	sum += 1;
    	}
    }
    
    
    람다식으로 변경
    (int[] arr) ->  
    	int sum = 0;
        for(int i:arr) {
        	sum += 1;
    	}

     

     


     

     

    람다식은 익명 객체!

    람다식은 익명 클래스의 객체와 동등하다.

    익명 객체의 주소를 참조변수에 넣으려면, 참조변수의 타입은 무엇이야 할까?

     

    클래스 혹은 인터페이스여야 하고, 람다식과 동등한 메서드가 정의되어있어야 한다. 그래야 참조변수로 람다식의 메서드를 호출할 수 있기 때문이다.

    Runnable r4 = () -> { System.out.println("Runnable를 구현한 람다식이 실행되었습니다.");	};

     

     


     

     

    코드 예시

    1. 람다식 기본

    package chap14;
    
    // 함수형 인터페이스를 선언한다.
    // 함수형 인터페이스는 추상메소드 하나만 존재하는 인터페이스를 말한다.
    // 함수형 인터페이스라는 것을 선언하기 위해 @FunctionalInterface 어노테이션을 붙인다.
    // 어노테이션을 붙일 경우, 함수형 인터페이스의 형식에 맞지 않을 경우 에러를 발생시키시에 붙이는 것을 권장한다.
    // 큰 수를 반환하는 프로그램을 만들 것이다. max() 메소드를 가진 추상형 인터페이스를 만든다.
    @FunctionalInterface
    interface MyFunction1 {
    	int max(int a, int b);
    }
    
    // 람다식 기본
    // 함수형 인터페이스 무명 클래스를 구현하자. ㅡ
    // 이 인터페이스를 구현한 익명 클래스의 객체는 다음과 같이 생성할 수 있다.
    public class LambdaGeneric1 {
    	public static void main(String[] args) {
    		
    		// 1. MyFunction1의 max()를 @Override한 익명클래스
    		MyFunction1 f1 = new MyFunction1() {
    			@Override
    			public int max(int a, int b) {
    				return a > b ? a : b;
    			}
    		};
    		System.out.println("1. 익명클래스 : " + f1.max(10, 20));
    		
    		// 2. 1번 코드를 람다식으로 대체한다.
    		//    매개변수 타입의 생략도 가능하다.
    		//	  return에 한 줄만 있을 경우, { } 생략도 가능하다.
    		MyFunction1 f2 = (int a, int b) -> { return a > b ? a : b; };
    		MyFunction1 f3 = (a, b) -> a > b ? a : b;
    		System.out.println("2. 람다식 기본 : " + f2.max(10, 20));
    		System.out.println("3. 람다식 매개변수와 {} 생략 : " + f3.max(10, 20));
    		
    	}
    
    }

     

     

     

     

    2. 람다식이 매개변수로 가는 경우

    @FunctionalInterface
    interface MyFunction2 {
    	int max(int a, int b);
    }
    
    // 람다식의 변수 전달
    public class LambdaParameter1 {
    	// 람다식을 변수로 전달받는 static 메소드를 만들었다.
    	// max(a, b)로 max에도 매개변수를 주기 위해서는 소속 메소드에서도 파라미터 a, b를 받아야 한다.
    	// MyFunction2 변수인 mf2, mf2.max()의 매개변수인 a와 b를 모두 받았다.
    	// 클래스 메소드를 활용하기 위해 static을 붙였다.
    	static int lambdaParameterMethod (MyFunction2 mf2, int a, int b) {
    		return mf2.max(a, b);
    	}
    	
    	// 인터페이스명 변수 = 람다식의 형태로 적힌 것을 알 수 있다.
    	// mf2와 mf3의 추상메소드를 람다식 형태로 재정의했다.
    	// 같은 메소드를 실행해도 다른 값이 나오는 다형성도 보인당
    	// MyFunction2의 max() 메소드를 재정의한 mf2, mf3 객체변수(?)를 lambdaParameterMethod의 매개변수로 넣어서 보냈다.
    	public static void main(String[] args) {
    		MyFunction2 mf2 = (a, b) -> a+b;
    		MyFunction2 mf3 = (a, b) -> { 
    				int result = 0;
    				if (a > b) {
    					result = a*b;
    				} else {
    					result = b/a;
    				}
    				return result;
    			 };
    		System.out.println("1. 람다식을 매개변수로 받기 : " + lambdaParameterMethod(mf2, 10, 20));
    		System.out.println("1-1. 람다식을 매개변수로 받기 (다형성): " + lambdaParameterMethod(mf3, 30, 20));
    	}
    }

     

     

     

     

    3. 람다식에 제네릭 사용하는 경우

    @FunctionalInterface
    interface GenericInterface1<T> {
    	public void getValue(T a, T b);
    }
    
    public class LambdaGeneric1 {
    	public static void main(String[] args) {
    		GenericInterface1<String> genS1 = (str1, str2) -> System.out.println("GenericInterface1<String> : " + str1 + str2);
    		GenericInterface1<Integer> genI2 = (str1, str2) -> System.out.println("GenericInterface1<Integer> : " + str1 + str2) ;
    		GenericInterface1<Double> genD3 = (str1, str2) -> System.out.println("GenericInterface1<Double> : " + str1 + str2) ;
    		
    		genS1.getValue("123", "456");
    		genI2.getValue(123, 456);
    		genD3.getValue(123.0, 456.0);
    	}
    }

     

     

     

     

    4. java.util.function 패키지

    • 자바에서는 필요한 동작에 따라 함수형 인터페이스를 구현해야 한다.
    • 자바에서 우리가 사용할만한 함수형 인터페이스를 미리 정의해 두었다.
    • 매번 새로운 함수형 인터페이스를 정의하는 것보다는, 함수형 인터페이스에 정의된 인터페이스와 메서드를 사용하는 것이 좋다.
    함수형 인터페이스 메서드 설명
    java.lang.Runnable void run() 매개변수 X, 반환값 X
    Supplier<T> T get() 매개변수 X, 반환값 X
    Consumer<T> void accept( T t ) 매개변수 O, 반환값 X
    Function<T, R> R apply ( T t ) 매개변수 O, 반환값 O
    Predicate<T> boolean test ( T t ) 조건식 표현할 때 사용

     

     

     

     

     

     

    코드 예시

    // 리턴타입, 매개변수 없는 람다식 사용
    Thread c5 = new Thread( () -> {System.out.println("람다스레드");});
    c5.start();
    
    // 리턴타입, 매개변수 모두 있는 람다식 사용
    // 날짜포맷과 매개변수를 전달하면 날짜형식이 완성되는 형태
    Function<String, String> mydate = str -> new SimpleDateFormat(str).format(new Date());
    String now =  mydate.apply("yyyy년도 MM월 dd일");

     

     

     

     

     

     


    출처

    선생님

    자바의 정석 기초편

    https://bamdule.tistory.com/75

    LambdaTest1 LambdaTest2(함수형 인터페이스 선언) LambdaTest3 server(chap13)

     

Designed by Tistory.