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);
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;
System.out.println(max.getMax(10, 20));
- @FunctionalInterface 애노테이션을 사용하면 메서드를 하나 이상 선언하면 오류 발생
@FunctionalInterface
public interface MyNumber {
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);
3.1.2. 람다식으로 인터페이스 구현
String s1 = "HELLO";
String s2 = "WORLD"
StringConcat concat2 = (s, v) -> System.out.println(s + "," + v);
concat2.makeString(s1, s2);
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) -> {
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){
p.showString("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.Runnable | void 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;
f = i -> System.out.print(i);
f = i -> i % 2 == 0;
f = i -> i / 10 * 10;
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) | 두 개의 매개변수를 받아서 결과를 반환 |
5. Function의 합성과 Predicate의 결합
5.1. Function의 합성
메서드 | 설명 |
---|
andThen() | f.andThen(g)는 함수 f를 먼저 적용하고 g 적용 |
compose() | f.compose(g)는 함수 g를 먼저 적용하고 f 적용 |
identity() | 함수를 적용하기 이전과 이후가 동일한 항등 함수 필요 시 사용 (1 넣으면 1 나옴) |
Function<Integer, Integer> f = i -> i * i;
Function<Integer, Integer> g = i -> i + 2;
Function<Integer, Integer> h = f.andThen(g);
System.out.println(h.apply(5));
Function<Integer, Integer> f = i -> i * i;
Function<Integer, Integer> g = i -> i + 2;
Function<Integer, Integer> h = f.compose(g);
System.out.println(h.apply(5));
Function<String, String> f = Function.identity();
System.out.println(h.apply(A));
5.2. Predicate의 결합
- 논리 연산자의 &&(and), ||(or), !(not)을 뜻함
메서드 | 설명 |
---|
and() | &&(and)와 동일 |
or() | ||(or)와 동일 |
negate() | !(not)과 동일 |
isEqual() | 두 대상을 비교 |
Predicate<Integer> p = i -> i < 100;
Predicate<Integer> q = i -> i < 200;
Predicate<Integer> r = i -> i%2 == 0;
Predicate<Integer> notP = p.negate();
Predicate<Integer> all = notP.and(q.or(r));
System.out.println(all.test(150));
Predicate<String> p = Predicate.isEqual(str1);
boolean result = p.test(str2);
boolean result = Predicate.isEqual(str1).test(str2);
6. 메서드 참조
- 하나의 메서드만 호출하는 람다식은 '메서드 참조'로 간단히 가능
- 클래스명::메서드명 또는 참조변수::메서드명
Function<String, Integer> f = (String s) -> Integer.parseInt(s);
Funcation<String, Integer> f = Integer::parseInt;
- 생성자를 호출하는 람다식도 메서드 참조로 변환 가능
Supplier<MyClass> s = () -> new MyClass();
Supplier<MyClass> s = MyClass::new;
Funcation<Integer, MyClass> s = (i) -> new MyClass(i);
Funcation<Integer, MyClass> s = MyClass::new;
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;