int max(int a, int b) { return a > b ? a : b;}(a, b) -> a > b ? a : b
익명 함수(이름이 없는 함수, annonymous function)
반환 타입, 함수 이름 제거
화살표 삽입
함수와 메서드의 차이
함수는 일반적 용어, 메서드는 객체지향개념 용어
함수는 클래스에 독립적, 메서드는 클래스에 종속적
람다식 작성하기
메서드의 이름과 반환타입을 제거하고 ‘→’ 를 블록 앞에 추가
반환값이 있는 경우, 식이나 값만 적고 return문 생략 가능
매개변수의 타입이 추론 가능하면 생략 가능
주의사항
매개변수가 하나인 경우, 괄호() 생략 가능
블록 안의 문장이 하나일 경우, 괄호{} 생략 가능
람다식의 예
(a, b) -> a > b ? a : b(name, i) -> System.out.println(name + "=" + i)x -> x * x() -> (int)(Math.random() * 6)
람다식은 익명 객체
람다식(익명 객체)을 다루기 위한 참조변수 필요
5~6. 함수형 인터페이스
함수형 인터페이스
단 하나의 추상 메서드만 선언된 인터페이스
interface MyFuction { public abstract int max(int a, int b);}MyFunction f = new MyFunction() { public int max(int a, int b) { return a > b ? a : b; }};
함수형 인터페이스 타입의 참조변수로 람다식을 참조할 수 있음
단, 함수형 인터페이스의 메서드와 람다식의 매개변수 개수와 반환타입이 일치해야 함
MyFuction f = (a, b) -> a > b ? a : b;int value = f.max(3, 5); // 실제로는 람다식이 호출됨
함수형 인터페이스 - 예시
익명 객체를 람다식으로 대체
List<String> list = Arrays.asList("abc", "aaa", "bbb", "ddd", "aaa");@FunctionalInterfaceinterface Comparator<T> { int compare(T o1, T o2);}Collections.sort(list, new Comparator<String>() { public int compare(String s1, String s2) { return s2.compareTo(s1); }});Collections.sort(list, (s1, s2) -> s2.compareTo(s1));
Supplier<Integer> f = () -> (int)(Math.random() * 100) + 1;Consumer<Integer> f = i -> System.out.print(i + ", ");Predicate<Integer> f = i -> i%2==0;Function<Integer, Integer> f = i -> i/10*10;
매개변수가 2개인 함수형 인터페이스
함수형 인터페이스
메서드
설명
BiConsumer<T, U>
void accept(T t, U u)
두 개의 매개변수만 있고 반환값 없음
BiPredicate<T, U>
boolean test(T t, U u)
두 개의 매개변수를 받아서 boolean을 반환
BiFunction<T, U, R>
R apply(T t, U u)
두 개의 매개변수를 받아서 하나의 결과 반환
// 매개변수가 3개 이상인 함수형 인터페이스가 필요하면 직접 작성하여 사용@FunctionalInterfaceinterface TriFunction<T, U, V, R> { R apply(T t, U u, V v);}
매개변수 타입과 반환 타입이 일치하는 함수형 인터페이스
함수형 인터페이스
메서드
설명
UnaryOperator
T apply(T t)
Function의 자손. 매개변수와 결과의 타입이 같음
BinaryOperator
T apply(T t, T t)
BiFunction의 자손. 매개변수와 결과의 타입이 같음
9~12. Predicate의 결합, CF
Predicate의 결합
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 >= 100Predicate<Integer> all = notP.and(q.or(r)); // 100 <= i && i < 200 || i%2 == 0Predicate<Integer> all2 = notP.and(q.or(r)); // 100 <= i && (i < 200 || i%2 == 0)System.out.println(all.test(2)); // trueSystem.out.println(all2.test(2)); // false
and()or()negate() 로 두 Predicate를 하나로 결합
Predicate<String> p2 = Predicate.isEqual(str1);boolean result = p2.test(str2); // str1과 str2가 같은지 비교한 결과를 반환
등가비교를 위한 Predicate의 작성에는 isEqual()를 사용(static 메서드)
컬렉션 프레임웍과 함수형 인터페이스
list.forEach(i -> System.out.print(i + ", "));list.removeIf(x -> x%2 == 0 || x%3 == 0);list.replaceAll(i -> i*10);// map의 모든 요소를 {k,v} 형식으로 출력map.forEach((k,v) -> System.out.print("{" + k + "," + v + "},"));
함수형 인터페이스를 사용하는 컬렉션 프레임웍의 메서드
13~14. 메서드, 생성자의 메서드 참조
메서드 참조
하나의 메서드만 호출하는 람다식은 ‘메서드 참조’로 더 간단히 할 수 있음
종류
람다
메서드 참조
static 메서드 참조
(x) → ClassName.method(x)
ClassName::method
인스턴스 메서드 참조
(obj, x) → obj.method(x)
ClassName::method
특정 객체 인스턴스 메서드 참조
(x) → obj.method(x)
obj::method
Integer method(String s) { return Integer.parseInt(s);}Function<String, Integer> f = (String s) -> Integer.parseInt(s);Function<String, Integer> f = Integer::parseInt;
static 메서드 참조
생성자의 메서드 참조
Supplier<MyClass> s = () -> new MyClass();Supplier<MyCalss> s = MyClass::new;Function<Integer, MyClass> s = (i) -> new MyClass(i);Function<Integer, MyClass> s = MyClass::new;
생성자의 메서드 참조
Function<Integer, int[]> f = x -> new int[x];Function<Integer, int[]> f2 = int[]::new;
IntStream IntStream.of(int... values) // Stream이 아니라 IntStreamIntStream IntStream.of(int[])IntStream Arrays.stream(int[])IntStream Arrays.stream(int[] array, int startInclusive, int endExclusive)
기본형 배열로부터 스트림 생성하기
스트림 만들기 - 임의의 수
IntStream intStream = new Random().ints(); // 무한 난수 스트림 생성intStream.limit(5).forEach(System.out::println); // 5개의 요소만 출력IntStream intStream = new Random().ints(5); // 5개짜리 유한 난수 스트림 생성IntStream intStream = new Random().ints(5, 1, 11); // (1, 10)사이 5 요소 유한 난수 스트림
특정 범위의 정수를 요소로 갖는 스트림 생성하기 (IntStream, LongStream)
스트림 만들기 - 람다식 iterate(), generate()
// iterate()는 이전 요소를 seed로 해서 다음 요소를 계산 (이전 요소에 종속적)Stream<Integer> evenStream = Stream.iterate(0, n -> n+2);// generate는 seed를 사용하지 않음 (이전 요소에 독립적)Stream<Double> randomStream = Stream.generate(Math::random);Stream<Integer> oneStream = Stream.generate(() -> 1);
람다식을 소스로 하는 스트림 생성하기
스트림 만들기 - 파일과 빈 스트림
Stream<Path> Files.list(Path dir); // Path는 파일 또는 디렉토리Stream<String> Files.lines(Path dir);Stream<String> Files.lines(Path dir, Charset cs);Stream<String> lines(); // BufferedReader 클래스의 메서드
파일을 소스로 하는 스트림 생성하기
Stream emptyStream = Stream.empty(); // empty()는 빈 스트림을 생성해서 반환long count = emptyStream.count(); // count 값은 0
비어있는 스트림 생성하기
23~25. 스트림의 연산
스트림의 연산 - 중간 연산
// 중복 제거Stream<T> distinct()// 조건에 안 맞는 요소 제외Stream<T> filter(Predicate<T> predicate)// 스트림의 일부를 잘라냄Stream<T> limit(long maxSize)// 스트림의 일부를 건너뜀Stream<T> skip(long n)// 스트림의 요소에 작업 수행Stream<T> peek(Consumer<T> action)// 스트림의 요소를 정렬Stream<T> sorted()Stream<T> sorted(Comparator<T> comparator)// 스트림의 요소 변환Stream<R> map(Function<T,R> mapper)DoubleStream mapToDouble(ToDoubleFunction<T> mapper)IntStream mapToInt(ToIntFunction<T> mapper)LongStream mapToLong(ToLongFunction<T> mapper)Stream<R> flatMap(Function<T,Stream<R>> mapper)DoubleStream flatMapToDouble(Function<T, DoubleStream> m)IntStream flatMapToInt(Function<T, IntStream> m)LongStream flatMapToLong(Function<T, LongStream> m)
스트림의 연산 - 최종 연산
// 각 요소에 지정된 작업 수행void forEach(Consumer<? super T> action)void forEachOrdered(Consumer<? super T> action)// 스트림의 요소의 개수 반환long count()// 스트림의 최대/최소값 반환Optional<T> max(Comparator<? super T> comparator)Optional<T> min(Comparator<? super T> comparator)// 스트림의 요소 하나 반환Optional<T> findAny() // 아무거나 하나Optional<T> findFirst() // 첫번째 요소// 주어진 조건을 모든 요소가 만족시키는지 확인boolean allMatch(Predicate<T> p) // 모두 만족하는지boolean anyMatch(Predicate<T> p) // 하나라도 만족하는지boolean noneMatch(Predicate<T> p) // 모두 만족하지 않는지// 스트림의 모든 요소를 배열로 반환Object[] toArray()A[] toArray(IntFunction<A[]> generator)// 스트림의 요소를 하나씩 줄여가면서 계산Optional<T> reduce(BinaryOperator<T> accumulator)T reduce(T identity, BinaryOperator<T> accumulator)U reduce(U identity, BiFunction<U,T,U> accumulator BinaryOperator<T> combiner)// 스트림의 요소를 수집. 주로 요소를 그룹화하거나 분할한 결과를 컬렉션에 담아 반환R collect(Collector<T,A,R> collector)R collect(Supplier<R> supplier, BiConsumer<R,T> accumulator, BiConsumer<R,R> combiner)