2. 함수형 인터페이스 도입 이유
함수형 프로그래밍을 하기 위해!
함수형 프로그래밍의 장점
• 함수를 First Class Object 로 사용 가능
• 순수 함수(Pure Function)
• 고차 함수(High-Order Function)
3. 함수형 인터페이스 도입
@FunctionalInterface - 명시해주기
@FunctionalInterface
public interface RunSomething {
int run(int a, int b);
}
함수형 인터페이스는 추상 메서드가 “하나”만 있어야 한다!!
SAM = Single Abstract Method
디폴트 메서드나, 스태틱 메서드는 있어도 됨
public static void main(String[] args) {
RunSomething runSomething = new RunSomething() {
@Override
public int run(int a, int b) {
return a + b;
}
};
}
함수형 인터페이스 정의 익명 클래스를 통해 구현
4. 함수형 인터페이스 도입
람다 사용
public static void main(String[] args) {
RunSomething runSomething = new RunSomething()
{
@Override
public int run(int a, int b) {
return a + b;
}
};
}
람다를 활용하면 코드의 가독성을 높일 수 있다.
public static void main(String[] args) {
RunSomething runSomething = (a, b) -> a + b;
int run = runSomething.run(3, 4);
System.out.println("run = " + run);
}
익명 클래스를 통해 구현 람다를 통해 구현
5. 자바8에서 제공해주는 인터페이스
맨날 만들기 번거롭잖아
Function<Integer, Integer> sum = a -> a + 5;
Function<Integer, Integer> multiply = a -> a * 2;
System.out.println(sum.apply(10)); // 15
System.out.println(multiply.apply(10)); // 20
System.out.println(sum.compose(multiply).apply(10)); // 25
System.out.println(sum.andThen(multiply).apply(10)); // 30
UnaryOperator<Integer> sumU = a -> a + 6;
UnaryOperator<Integer> multiplyU = a -> a * 2;
System.out.println(sumU.apply(10)); // 16
System.out.println(multiplyU.apply(10)); //20
System.out.println(sumU.compose(multiplyU).apply(10)); // 26
System.out.println(sumU.andThen(multiplyU).apply(10)); // 32
Function<T, R> - 타입 T를 입력받아 R로 반환, UnaryOperator<T> - T를 받아 T로 반환
6. 자바8에서 제공해주는 인터페이스
맨날 만들기 번거롭잖아
Consumer<Integer> consumer = a -> System.out.println(a + 10);
consumer.accept(20);
Supplier<String> supplier = () -> "HELLO";
System.out.println(supplier.get());
Predicate<String> predicate = s -> s.contains("hello");
boolean result = predicate.test("seokju says bye");
System.out.println(result);
Consumer<T> - T를 입력받아 , Supplier<T> - T를 반환
Predicate<T> - boolean 반환
이 인터페이스들이 Stream에서 아주 요긴하게 쓰인다!
7. 인터페이스 변화
Default Method & Static Method
• 과거 인터페이스는 추상 메서드로만 구성되어 있어야 함.
Concrete Class에서 구현해줘야 함.
• 공통되는 부분이 있음에도, 각각 구현해서 만들어줘야 했음
• 자바8부터는 Default 메서드를 통해 공통된 메서드를 제공하고, 스태틱 메서드
를 통해 편의 기능도 제공할 수 있다.
10. 스트림 종류
걸러내기
• Filter(Predicate)
• 예) 이름이 3글자 이상인 데이터만 새로운 스트림으로
변경하기
• Map(Function) 또는 FlatMap(Function)
• 예) 각각의 Post 인스턴스에서 String title만 새로운 스트림으로
• 예) List<Stream<String>>을 String의 스트림으로
생성하기
• generate(Supplier) 또는 Iterate(T seed, UnaryOperator)
• 예) 10부터 1씩 증가하는 무제한 숫자 스트림
• 예) 랜덤 int 무제한 스트림
제한하기
• limit(long) 또는 skip(long)
• 예) 최대 5개의 요소가 담긴 스트림을 리턴한다.
• 예) 앞에서 3개를 뺀 나머지 스트림을 리턴한다.
11. 스트림 종류
스트림에 있는 데이터가 특정 조건을 만족하는지 확인
• anyMatch(), allMatch(), nonMatch()
• 예) k로 시작하는 문자열이 있는지 확인한다. (true 또는 false를 리턴한다.)
• 예) 스트림에 있는 모든 값이 10보다 작은지 확인한다.
개수 세기
• count()
• 예) 10보다 큰 수의 개수를 센다.
스트림을 데이터 하나로 뭉치기
• reduce(identity, BiFunction), collect(), sum(), max()
• 예) 모든 숫자 합 구하기
• 예) 모든 데이터를 하나의 List 또는 Set에 옮겨 담기
12. 스트림 테스트
List<OnlineClass> springClasses = new ArrayList<>();
springClasses.add(new OnlineClass(1, "spring boot", true));
springClasses.add(new OnlineClass(2, "spring data jpa", true));
springClasses.add(new OnlineClass(3, "spring mvc", false));
springClasses.add(new OnlineClass(4, "spring core", false));
springClasses.add(new OnlineClass(5, "rest api development", false));
System.out.println("spring 으로 시작하는 수업");
springClasses.stream().filter(i -> i.getTitle().startsWith("spring")).forEach(s -> System.out.println(s.getTitle()));
System.out.println("close 되지 않은 수업");
// springClasses.stream().filter(i -> !i.isClosed()).forEach(s -> System.out.println(s.getTitle()));
springClasses.stream().filter(Predicate.not(OnlineClass::isClosed)).forEach(s -> System.out.println(s.getTitle()));
System.out.println("수업 이름만 모아서 스트림 만들기");
springClasses.stream().map(OnlineClass::getTitle).forEach(System.out::println);