(1)

람다식(Lambda)

[ 람다함수 ] 프로그래밍 언어에서 사용되는 개념으로 익명 함수(Anonymous functions)를 지칭하는 용어 익명 함수들은 어느 언어에서나 일급 객체라는 특징을 가짐 일급 객체 다른 객체들에 일반적으로 적용 가능한 연산을 모두 지원하는 객체 를 가리킨다. 보통 함수에 인자로 넘기기, 수정하기, 변수에 대입하기와 같은 연산을 지원할 때 일급 객체라고 한다. [ 특징 ] 람다 대수는 이름을 가질 필요가 없고 두 개 이상의 입력이 있는 함수는 1개의 입력만 받는 람다 대수로 단순화 될 수 있다 - 커링 람다 실행블록에는 클래스의 필드와 메서드를 제약없이 사용 가능하다 람다식 내에서 사용되는 지역변수는 final이 없어도 상수로 간주된다 람다식으로 선언된 변수명은 다른 변수명과 중복될 수 없다 람다 대..

람다식(Lambda)

Tech/Java & Spring 2022. 12. 22. 09:43
728x90
728x90

[  람다함수  ]


프로그래밍 언어에서 사용되는 개념으로 익명 함수(Anonymous functions)를 지칭하는 용어

익명 함수들은 어느 언어에서나 일급 객체라는 특징을 가짐

 

일급 객체
다른 객체들에 일반적으로 적용 가능한 연산을 모두 지원하는 객체
를 가리킨다. 보통 함수에 인자로 넘기기, 수정하기, 변수에 대입하기와 같은 연산을 지원할 때 일급 객체라고 한다.

 

 

[  특징  ]


람다 대수는 이름을 가질 필요가 없고

두 개 이상의 입력이 있는 함수는 1개의 입력만 받는 람다 대수로 단순화 될 수 있다 - 커링

 

람다 실행블록에는 클래스의 필드와 메서드를 제약없이 사용 가능하다

람다식 내에서 사용되는 지역변수는 final이 없어도 상수로 간주된다

람다식으로 선언된 변수명은 다른 변수명과 중복될 수 없다

 

람다 대수
추상화와 함수 적용 등의 논리 연산을 다루는 형식 체계로 함수를 보다 단순하게 표현하는 방법이다

 

커링
f(a,b,c) → f(a)(b)(c)
다중 인수를 갖는 함수를 단일 인수를 갖는 함수들의 함수열로 바꾸는 것을 말한다.단일 호출로 처리하는 함수를 각각의 인수가 호출 가능한 프로세스로 호출된 후 병합되도록 변환하는 것이다

 

 

[  장점  ]


코드의 간결함

가독성의 향상 : 개발자의 의도가 명확히 드러난다

생산성의 향상 : 함수를 만드는 과정없이 한번에 처리할 수 있다

병렬처리에 용이 : 멀티쓰레드 활용

 

 

[  단점  ]


호출의 까다로움

불필요한 람다의 남발 시 가독성이 떨어진다

디버깅이 어렵다

람다 stream 사용 시 단순 for문 혹은 while문 사용 시 성능이 떨어진다

 

 

[  사용하기  ]


매개변수 -> 함수 몸체

int a(int x, int y) {
    return x < y ? x : y;
}

(x, y) -> x < y ? x : y;
//함수 몸체가 단일 실행문이면 중괄호{} 생략 가능
//return문으로만 구성되어 있으면 생략 불가능
(int x) -> x+1
(x) -> x+1
x -> x+1
(int x) -> { return x+1; }
x -> { return x+1; }

//기존 자바 문법
new Thread(new Runnable() {
    public void run() {
        System.out.println("전통적인 방식의 일회용 스레드 생성");
    }
}).start();

 
//람다식 문법
new Thread(()->{
    System.out.println("람다 표현식을 사용한 일회용 스레드 생성");
}).start();

 

 

[  함수형 인터페이스( Functional Interface )  ]


Java는 기본적으로 객체지향 언어이기 때문에 순수 함수와 일반 함수를 다르게 취급하고 있으며 Java에서는 이를 구분하기 위해 함수형 인터페이스가 등장하게 되었다

 

함수형 인터페이스란 함수를 1급 객체처럼 다룰 수 있게 해주는 어노테이션으로, 인터페이스에 선언하여 단 하나의 추상 메소드만을 갖도록 제한하는 역할을 한다. 함수형 인터페이스를 사용하는 이유는 Java의 람다식이 함수형 인터페이스를 반환하기 때문이다

 

하지만 함수형 인터페이스의 등장으로 우리는 함수를 변수처럼 선언할 수 있게 되었다

함수형 인터페이스를 구현하기 위해서는 인터페이스를 개발하여 그 내부에는 1개 뿐인 abstract 함수를 선언하고, 위에는 @FunctionalInterface 어노테이션을 붙여주면 된다

 

람다식으로 생성된 순수 함수는 함수형 인터페이스로만 선언이 가능하다. 또한 @FunctionalInterface는 해당 인터페이스가 1개의 함수만을 갖도록 제한하기 때문에, 여러 개의 함수를 선언하면 컴파일 에러가 발생한다 

@FunctionalInterface
public interface LambInter {
	void test(int a);	
}
public class Lambda {

	public static void main(String[] args) {
		
		LambInter lam = null;
		
		lam = (a) ->{
			int result = a*30;
			System.out.println("람다" + result);
		};		
		lam.test(30);
	}
}

//Console
//람다900

 

[  JAVA에서 제공하는 함수형 인터페이스  ]


자바8부터는 빈번하게 사용되는 함수형 인터페이스(Functional Interface)는 java.util.function 표준 API 패키지로 제공된다

이 패키지에서 제공하는 함수적 인터페이스의 목적은 메소드 또는 생성자의 매개 타입으로 사용되어 람다식을 대입할 수 있도록 하기 위해서이다 

  • Consumer
  • Supplier
  • Function
  • Operator
  • Predicate

 

1. Consumer

파라미터만 있고 리턴값이 없는 추상 메서드를 가진다

추상메서드 accept를 호출하여 사용

 

인터페이스 추상 메서드 설명
Consumer<T> void accept(T t) 객체 T를 받아 소비
BiConsumer<T, U> void accept(T t, U u) 객체 T와 U를 받아 소비
DoubleConsumer void accept(double value) double 값을 받아 소비
IntConsumer void accept(int value) int 값을 받아 소비
LongConsumer void accept(long value) long 값을 받아 소비
ObjDoubleConsumer<T> void accept(T t, double value) 객체 T와 double 값을 받아 소비
ObjIntConsumer<T> void accept(T t, int value) 객체 T와 int 값을 받아 소비
ObjLongConsumer<T> void accept(T t, long value) 객체 T와 long 값을 받아 소비

 

import java.util.function.Consumer;
import java.util.function.BiConsumer;
import java.util.function.DoubleConsumer;
import java.util.function.ObjIntConsumer;

public class Lambda {	

	public static void main(String[] args) {	
    
		Consumer<String> consumer = (t) ->{
			System.out.println("디파일러 컨슘" + t);
		};		
		consumer.accept("ㅇㅇㅇㅇ");;		
		
		BiConsumer<String, String> bi = (a,b) -> {
			System.out.println("ㅋㅋㅋㅋ" + a + "ㅋㅋㅋㅋ" + b);
		};
		bi.accept("어제 길을 가는데", "누가 넘어짐");		
		
		DoubleConsumer dc = (dd) ->{
			System.out.println("내가 지금 사용하는 자바 버전은? " + dd);
		};
		dc.accept(1.8);
        
        	ObjIntConsumer<String> obc = (i, j) ->{
			System.out.println(i + j);
		};
		obc.accept("자바", 8);
	}
}
//Console
디파일러 컨슘 지이이잉
ㅋㅋㅋㅋ 어제 길을 가는데 ㅋㅋㅋㅋ 누가 넘어짐
내가 지금 사용하는 자바 버전은? 1.8
자바8

 

 

2. Supplier

파라미터는 없고 리턴값만 있다

get....() 메서드를 호출하여 실행한 후 호출한 곳으로 데이터를 리턴한다

 

인터페이스 추상 메서드  설명
Supplier<T> T get() T 객체를 리턴
BooleanSupplier Boolean getAsBoolean() Boolean 값을 리턴
DoubleSupplier double getAsDouble() double 값을 리턴
IntSupplier int getAsInt() int 값을 리턴
LongSupplier long getAsLong() long 값을 리턴

 

import java.util.function.Supplier;
import java.util.function.IntSupplier;

public class Lambda {

	public static void main(String[] args) {

		Supplier<String> supplier = () ->{
			String study = " 나는 오늘도 열심히 자바 공부를 한다";
			return study;
		};
		System.out.println(supplier.get());
				
		IntSupplier lotto = () ->{
			int num = (int)(Math.random()*45)+1;
			return num;		
		};
        
	}
       
}
//Console
나는 오늘도 열심히 자바 공부를 한다
로또 가즈아 : 9

 

 

 

3. Function

매개값과 리턴값이 있는 apply....()메서드를 사용

매개값을 리턴으로 매핑한다

 

인터페이스 추상 메서드 설명
Function<T, R> R apply(T t) 객체 T를 객체 R로 매핑
BiFunction<T, U, R> R apply(T t, U u) 객체 T와 U를 객체 R로 매핑
DoubleFunction<R> R apply(double value) double을 객체 R로 매핑
IntFunction<R> R apply(int value) int을 객체 R로 매핑
IntToDoubleFunction double applyAsDouble(int value) int를 double로 매핑
IntToLongFunction long applyAsLong(int value) int를 long으로 매핑
LongToDoubleFunction double applyAsDouble(long value) long을 double로 매핑
LongToIntFunction int applyAsInt(long value) long을 int로 매핑
ToDoubleBiFunction<T, U> double applyAsDouble(T t, U u) 객체 T와 U를 double로 매핑
ToDoubleFunction<T> double applyAsDouble(T value) 객체 T를 double로 매핑
ToIntBiFunction<T, U> int applyAsInt(T t, U u) 객체 T와 U를 int로 매핑
ToIntFunction<T> int applyAsInt(T t) 객체 T를 int로 매핑
ToLongBiFunction<T, U> long applyAsLong(T t, U u) 객체 T와 U를 long으로 매핑
ToLongFunction<T> long applyAsLong(T t) 객체 T를 long으로 매핑

 

Function<Student, String> function = t -> {
	return t.getName();
};


Function<Student, String> function = t -> t.getName();

 

 

 

4. Operator

파라미터, 리턴값이 모두 있는 추상 메서드 apply....()를 가지고 있다

파라미터 값을 연산하고 그 결과를 리턴 시 사용할 수 있다

 

인터페이스  추상 메서드  설명
BinaryOperator<T> BiFunction<T,U,R>의 하위 인터페이스 T와 U를 연산 후 R 리턴
UnaryOperator<T> Function<T, R>의 하위 인터페이스 T를 연산한 후 R 리턴
DoubleBinaryOperator double applyAsDouble(double, double) 두 개의 double을 연산
DoubleUnaryOperator double applyAsDouble(double) 한 개의 double을 연산
IntBinaryOperator int applyAsInt(int, int) 두 개의 int를 연산
IntUnaryOperator int applyAsInt(int) 한 개의 int를 연산
LongBinaryOperator long applyAsLong(long, long) 두 개의 long을 연산
LongUnarayOperator long applyAsLong(long) 한 개의 long을 연산

 

import java.util.function.BinaryOperator;

public class Lambda {
	
	static int[] arr = {13, 15, 100, 1, 37, 76};

	public static void main(String[] args) {

                IntBinaryOperator operMin = (a, b) ->{
                return Math.min(a, b);
		};
		int min = maxOrMin(operMin);
		
		IntBinaryOperator operMax = (a, b) ->{
			return Math.max(a, b);
		};        
		int max = maxOrMin(operMax);
		
		System.out.printf("최소값 : %d, 최대값 : %d", min, max);		
		
	}
	
	public static int maxOrMin(IntBinaryOperator oper){
		int result = arr[0];
		for(int num : arr) {
			result = oper.applyAsInt(result, num);
		}
		return result;
	}
    
}
//Console
최소값 : 1, 최소값 : 100

 

 

5.Predicate

파라미터를 조사하여 truse / false값을 리턴하는 test....()메서드를 가지고 있다

 

인터페이스 추상 메서드 설명
Predicate<T> Boolean test(T t) 객체 T를 조사
BiPredicate<T, U> Boolean test(T t, U u) 객체 T와 U를 비교 조사
DoublePredicate Boolean test(double value) double 값을 조사
IntPredicate Boolean test(int value) int 값을 조사
LongPredicate Boolean test(long value) long 값을 조사

 

더보기
package java1222;

public class Ourclass {
	
	private String name;
	private String gender;
	private int score;
	
	public Ourclass(String name, String gender, int score) {
		this.name = name;
		this.gender = gender;
		this.score = score;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getGender() {
		return gender;
	}

	public void setGender(String gender) {
		this.gender = gender;
	}

	public int getScore() {
		return score;
	}

	public void setScore(int score) {
		this.score = score;
	}
	
	
	
	
	
}

 

import java.util.ArrayList;
import java.util.function.Predicate;

public class PredicateExam {
	
	public static ArrayList<Ourclass> arrayList = new ArrayList<>();

	public static void main(String[] args) {
		
		arrayList.add(new Ourclass("김범수", "남자", 30));
		arrayList.add(new Ourclass("나얼", "남자", 50));
		arrayList.add(new Ourclass("박효신", "남자", 60));
		arrayList.add(new Ourclass("이수", "남자", 55));
		arrayList.add(new Ourclass("아이유", "여자", 42));
		arrayList.add(new Ourclass("김연우", "남자", 30));
		arrayList.add(new Ourclass("박화요비", "여자", 25));
		arrayList.add(new Ourclass("이선희", "여자", 20));
		arrayList.add(new Ourclass("이승기", "남자", 95));
		arrayList.add(new Ourclass("허각", "남자", 80));
		
		
		Predicate<Ourclass> female = t ->{
			System.out.print(t.getName());
			System.out.println(t.getScore());
			return t.getGender().equals("여자");
		};
		
		Predicate<Ourclass> male = t ->{
			System.out.print(t.getName());
			System.out.println(t.getScore());
			return t.getGender().equals("남자");
		};
		
		double fe = avg(female);
		System.out.println("여성 평균 : " + fe);
		
		double ma = avg(male);
		System.out.println("남성 평균 : " + ma);
		
		
	}
	
	public static double avg(Predicate<Ourclass> score){
		int count = 0;
		int sum = 0;
		
		for(Ourclass clsMate : arrayList) {
			if(score.test(clsMate)) {
				count++;
				sum += clsMate.getScore();
			}
		}
		return (double)sum/count;		
	}

}
//Console
여성 평균 : 29.0
남성 평균 : 57.142857142857146

 

 

 

참조

https://palpit.tistory.com/673
https://mangkyu.tistory.com/113
https://khj93.tistory.com/entry/JAVA-%EB%9E%8C%EB%8B%A4%EC%8B%9DRambda%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B4%EA%B3%A0-%EC%82%AC%EC%9A%A9%EB%B2%95

 

728x90
300x250
mag1c

mag1c

2년차 주니어 개발자.

방명록