JAVA/JAVA8 관련
[더 자바 8] 함수형 인터페이스와 람다 표현식
JUMP개발자
2022. 2. 4. 00:48
1. 함수형 인터페이스
- 추상메서드가 하나만 존재하는 인터페이스
- 다른 Static / default 메서드는 있어도 됨.
- @FunctionalInterface를 선언하여 함수형 인터페이스를 견고하게 관리 가능하다.
(함수형 인터페이스 아닐 시에 컴파일 에러를 냄)
// 함수형 인터페이스
// -> 추상 메서드를 인터페이스당 1개만 사용가능
@FunctionalInterface
public interface RunSomething {
void doIt();
// void doitAgain();
}
2. 익명 내부 클래스
public class Foo {
public static void main(String[] args) {
// 자바 8 이전에 사용하던 방식
// 익명 내부 클래스 - anoymous inner class
RunSomething runSomething = new RunSomething() {
@Override
public void doIt() {
System.out.println("do it!!");
}
};
// 자바 8에서 새로 지원하는 방식
RunSomething runSomething2 = () -> {System.out.println("do it!!");};
}
}
3. 순수함수
- 함수 밖에 있는 값 변경 X
- 입력 받은 값이 동일한 경우, 결과값이 같아야 한다. ( 이를 보장하지 못하면 함수형 프로그래밍이 아님)
위를 보장 받지 못하는 경우 :
- 함수 외부의 변수를 사용하는 경우
- 외부에 있는 값을 변경하는 경우
// 인터페이스
@FunctionalInterface
public interface RunSomthing {
int doIt(int number);
}
// 클래스
public class Foo {
public static void main(String[] args) {
RunSomthing runSomthing1 = new RunSomthing() {
int baseNumber = 10;
@Override
public int doIt(int number) {
baseNumber++; // 2 : 외부에 있는 값을 변경
return number + baseNumber; // 1 : 함수 외부의 값을 사용
}
};
}
}
4. 고차함수
함수가 함수를 매개변수로 받고. 리턴할 수 있음.
5. 자주 사용하는 함수 인터페이스
- 위와같이 직접 함수 인터페이스를 만드는 경우보다 JAVA에서 제공하는 함수 인터페이스를 사용하는 경우가 많음.
- Function<T, R> : T를 받아서 R을 리턴
- apply, andThen, compose 등을 사용함.
- 입력값과 결과값이 같으면 UnaryOperator를 사용할 수 있다
ex:) Function<Integer, Integer> == UnaryOperator<Integer>
// 방법1 : 클래스로 구현해서 사용
public class Plus10 implements Function<Integer, Integer> {
@Override
public Integer apply(Integer number) {
return number + 10;
}
}
// 방법 1 사용
public class Foo {
public static void main(String[] args) {
Plus10 plus10 = new Plus10();
System.out.println(plus10.apply(1));
}
}
// 방법2 : 람다식을 사용하는 방식
public class Foo {
public static void main(String[] args) {
Function<Integer, Integer> plus10 = (i) -> i + 10;
System.out.println(plus10.apply(2));
Function<Integer,Integer> multiply2 = (i) ->i*2;
System.out.println(multiply2.apply(2)); //4
}
}
andThen : 함수를 먼저 실행하고, 입력값을 실행 (실행함수 우선 실행)
compose : 입력값을 실행한후, 함수를 실행. (입력함수 우선 실행)
public class Foo {
public static void main(String[] args) {
Function<Integer,Integer> plus10 = (i) ->i+10;
System.out.println(plus10.apply(2)); //12
Function<Integer,Integer> multiply2 = (i) ->i*2;
System.out.println(multiply2.apply(2)); //4
// 1. andThen
Function<Integer, Integer> plus10Andmultiply2 = plus10.andThen(multiply2);
System.out.println(plus10Andmultiply2.apply(2)); // (2 + 10) * 2 = 24
// 2. compose
Function<Integer,Integer> multiply2AndPlus10 = plus10.compose(multiply2);
System.out.println(multiply2AndPlus10.apply(2)); // (2*2)+10= 14
}
}
- Consumer<T> : T타입을 받아서 아무값도 리턴하지 않는 함수 인터페이스
public class Foo {
public static void main(String[] args) {
Consumer<Integer> printT = (i) ->System.out.println(i);
printT.accept(10);
}
}
- Supplier<T> : T타입의 값을 제공하는 함수 인터페이스
public class Foo {
public static void main(String[] args) {
Supplier<Integer> get10 = () ->10;
System.out.println(get10.get()); // 10
}
}
- Predicate<T> : T타입을 받아서 boolean을 리턴하는 함수 인터페이스