[JAVA] 람다식

JUNSEUNG LEE·2022년 10월 28일
0

JAVA

목록 보기
17/17
post-thumbnail

1. 람다식이란?

  • 자바 8부터 제공하는 함수형 프로그래밍 방식
  • 함수형 프로그래밍 : 함수의 구현과 호출만으로 프로그램을 만드는 방식

2. 람다식 작성하기

  • 함수 이름이 없는 익명 함수를 만드는 것
(매개변수) -> {실행문;}

// 일반
int add(int x, int y) {
	return x + y;
}

// 람다
(int x, int y) -> {return x + y;}
  • 매개변수 자료형 생략 가능, 매개 변수가 하나인 경우 괄호 생략 가능
str -> {System.out.pringln(str);}
  • 매개 변수가 두 개인 경우는 괄호 생략 불가
x, y -> {System.out.pringln(x + y);} // 잘못된 형식
  • 중괄호 안의 구현 부분이 한문장인 경우 중괄호 생략 가능
str -> System.out.pringln(str);
  • return문은 중괄호 생략 불가
str -> return str.length(); // 잘못된 형식
  • 중괄호 안의 구현 부분이 return문 하나라면 중괄호와 return 모두 생략
(x, y) -> x + y
str -> str.length()

3. 함수형 인터페이스(Functional Interface)

  • 람다식을 구현하기 위한 인터페이스
  • 인터페이스에 람다식으로 구현할 메서드를 선언
  • 두 개 이상의 메서드를 가질 수 없음
    - 람다식은 이름이 없는 익명 함수로 구현하기 때문에 구분이 모호해짐
public interface MyNumber { // 함수형 인터페이스 선언
	int getMax(int num1, int num2); // 추상 메서드 선언
}

...
MyNumber max = (x, y) -> (x >= y) ? x : y; // 람다식을 인터페이스형 max변수에 대입
System.out.println(max.getMax(10, 20)); // 인터페이스형 변수로 메서드 호출
  • @FunctionalInterface 애노테이션을 사용하면 메서드를 하나 이상 선언하면 오류 발생
@FunctionalInterface
public interface MyNumber { // 메서드가 2개이므로 오류 발생
	int getMax(int num1, int num2); 
	int add(int num1, int num2);
}

3.1. 객체 지향 프로그래밍 방식과 람다식 비교

public interface StringConcat() { 
	public void makeString(String s1, String s2); // 문자열 두 개를 받아 연결하여 출력하는 메서드
}

3.1.1. 클래스에서 인터페이스 구현

public StringConCatImpl implements String { // 클래스 인터페이스를 수현
	@Override
	public void makeString(String s1, String s2) { // 인터페이스 메서드 재정의
		System.out.println(s1 + "," + s2);
	}
}

...
String s1 = "HELLO";
String s2 = "WORLD"
StringConCatImpl concat1 =  new StringConCatImpl();
concat1.makeString(s1, s2);

/*결과
HELLO,WORLD
*/

3.1.2. 람다식으로 인터페이스 구현

String s1 = "HELLO";
String s2 = "WORLD"
StringConcat concat2 = (s, v) -> System.out.println(s + "," + v);
concat2.makeString(s1, s2);
/*결과
HELLO,WORLD
*/
  • 코드가 간결해짐

3.2. 익명 객체를 생성하는 람다식

  • 람다식으로 메서드를 구현해서 호출하면 익명 클래스가 생성되고 이를 통해 객체가 생성되는 것
StringConcat concat3 = new StringConcat() {
	@Override
	public void makeString(String s1, String s2) { // 인터페이스 메서드 재정의
		System.out.println(s1 + "," + s2);
	}
};

3.2.1. 람다식에서 사용하는 지역변수

...
int i = 100; 
 
StringConcat concat2 = (s,v) -> {
	// i = 200; 람다식 내부에서 변경하면 오류 발생, 지역 내부 클래스 변수 값 변경 오류와 같은 원리
	System.out.println(s + "," + v);
};

3.3. 함수를 변수처럼 사용하는 람다식

3.3.1. 인터페이스형 변수에 람다식 대입

public interface PrintString() { 
	public void showString(String str);
}

...
PrintString lambdaStr = s -> System.out.println(s); // 인터페이스형 변수에 람다식 대입
lambdaStr.showString("JUNSEUNG");

3.3.2. 매개변수로 전달하는 람다식

public interface PrintString() { 
	public void showString(String str);
}

public class Test {
	public static void main(String[] args) {
		PrintString lambdaStr = s -> System.out.println(s); // 인터페이스형 변수에 람다식 대입
		lambdaStr.showString("JUNSEUNG"); // 구현부 호출
		showMyString(lambdaStr); // 메서드의 매개변수로 람다식을 대입한 변수 전달
	}
	public static void showMyString(PrintString p){ // 매개변수를 인터페이스 형으로 받음, main()이 static이기 때문에 static 메서드 생성
		p.showString("BABO");
	}
}

/*결과
JUNSEUNG
BABO
/

3.3.3. 반환 값으로 쓰이는 람다식

public static PrintString returnString(){ 
	return s -> System.out.println(s);
}

...
PrintString pStr = returnString(); // 변수로 반환받기
pStr.showString("JUNSEUNG"); // 메서드 호출

4. java.util.function패키지

4.1. 자주 사용되는 다양한 함수형 인터페이스를 제공

구분함수형 인터페이스메서드설명
java.lang.Runnablevoid run()매개변수도 없고, 반환값도 없음.
공급자Supplier<T>T get()매개변수는 없고, 반환값만 있음.
소비자Consumer<T>void accept(T t)Supplier와 반대로 매개변수만 있고, 반환값이 없음.
함수Funcation<T,R>R apply(T t)일반적인 함수. 하나의 매개변수를 받아서 결과를 반환
조건식Predicate<T>boolean test(T t)조건식을 표현하는데 사용됨. 매개변수는 하나. 반환 타입은 boolean
f = () -> (int)(Math.random() * 100 ) + 1; // Supplier 매개변수는 없고, 반환값만 있음.
f = i -> System.out.print(i); // Consumer 매개변수만 있고 반환값이 없음.
f = i -> i % 2 == 0; // Predicate 반환타입이 boolean.
f = i -> i / 10 * 10; // Function 매개변수도 있고 반환값도 있음.

4.2. 매개변수가 2개인 함수형 인터페이스

함수형 인터페이스메서드설명
BiConsumer<T,U>void accept(T t, U u)두개의 매개변수만 있고, 반환값이 없음
BiFuncation<T,U>R apply(T t, U u)두 개의 매개변수를 받아서 결과를 반환
BiPredicate<T,U,R>boolean test(T t, U u)조건식을 표현하는데 사용됨. 매개변수는 둘. 반환 타입은 boolean

4.3. 매개변수의 타입과 반환타입이 일치하는 함수형 인터페이스

함수형 인터페이스메서드설명
UnaryOperator<T>T accept(T t)두개의 매개변수만 있고, 반환값이 없음
BinaryOperator<T>T apply(T t, T t)두 개의 매개변수를 받아서 결과를 반환
  • Unary 단항, Binary 이항을 말함

5. Function의 합성과 Predicate의 결합

5.1. Function의 합성

  • 여러 기능을 합치는 것
메서드설명
andThen()f.andThen(g)는 함수 f를 먼저 적용하고 g 적용
compose()f.compose(g)는 함수 g를 먼저 적용하고 f 적용
identity()함수를 적용하기 이전과 이후가 동일한 항등 함수 필요 시 사용 (1 넣으면 1 나옴)
// andThen()
Function<Integer, Integer> f = i -> i * i;
Function<Integer, Integer> g = i -> i + 2;

Function<Integer, Integer> h = f.andThen(g); // f.andThen(g)는 함수 f를 먼저 적용하고 g 적용
System.out.println(h.apply(5)); // 27

// compose()
Function<Integer, Integer> f = i -> i * i;
Function<Integer, Integer> g = i -> i + 2;

Function<Integer, Integer> h = f.compose(g); // f.compose(g)는 함수 g를 먼저 적용하고 f 적용
System.out.println(h.apply(5)); // 49

//identity()
Function<String, String> f = Function.identity();
System.out.println(h.apply(A)); // A

5.2. Predicate의 결합

  • 논리 연산자의 &&(and), ||(or), !(not)을 뜻함
메서드설명
and()&&(and)와 동일
or()||(or)와 동일
negate()!(not)과 동일
isEqual()두 대상을 비교
// and(), or(), negate()
Predicate<Integer> p = i -> i < 100;
Predicate<Integer> q = i -> i < 200;
Predicate<Integer> r = i -> i%2 == 0;
Predicate<Integer> notP = p.negate();

// i >= 100 && (i < 200 || i%2==0)
// ture.and(true.or(true))
Predicate<Integer> all = notP.and(q.or(r));
System.out.println(all.test(150));  // true

// isEqual()
Predicate<String> p = Predicate.isEqual(str1);
boolean result = p.test(str2);  //str1과 str2가 같은지 비교하여 결과를 반환

// 위의 두 문장을 하나로 합치면
boolean result = Predicate.isEqual(str1).test(str2);

6. 메서드 참조

  • 하나의 메서드만 호출하는 람다식은 '메서드 참조'로 간단히 가능
  • 클래스명::메서드명 또는 참조변수::메서드명
// 기존
Function<String, Integer> f = (String s) -> Integer.parseInt(s);

// 메서드 참조
Funcation<String, Integer> f = Integer::parseInt; // static 메서드 참조
  • 생성자를 호출하는 람다식도 메서드 참조로 변환 가능
// 매개변수 없는 생성자
Supplier<MyClass> s = () -> new MyClass();  // 람다식
Supplier<MyClass> s = MyClass::new; // 메서드 참조

// 매개변수가 1개인 생성자
Funcation<Integer, MyClass> s = (i) -> new MyClass(i);
Funcation<Integer, MyClass> s = MyClass::new;

// 매개변수가 2개인 생성자
BinFuncation<Integer, Integer, MyClass> s = (i, j -> new MyClass(i, j);
BinFuncation<Integer, Integer, MyClass> s = MyClass::new;
  • 배열 생성할 경우
Function<Integer, int[]> f = x -> new int[x]; // 람다식
Function<Integer, int[]> f2 = int[]::new; // 메서드 참조
profile
개발자 준승

0개의 댓글