- 함수(메서드)를 간단한 '식(expression)'으로 표현하는 방법
- 익명 함수(이름이 없는 함수, anonymous function)
- 함수와 메서드의 차이
- 근본적으로는 동일. 함수는 일반적인 용어, 메서드는 객체지향개념 용어
- 함수는 클래스에 독립적, 메서드는 클래스에 종속적
- 메서드의 이름과 반환타입을 제거하고 '->'를 블록{} 앞에 추가한다.
- 반환값이 있는 경우, 식이나 값만 적고 return문 생략 가능(끝에 ';'안 붙임)
- 매개변수의 타입이 추론 가능하면 생략가능(대부분의 경우 생략가능)
- 주의사항
- 매개변수가 하나인 경우, 괄호() 생략가능(타입이 없을 때만)
- 블록 안의 문장이 하나뿐 일 때, 괄호{} 생략가능(끝에 ';' 안 붙임)
- 단, 하나뿐인 문장이 return문일 경우 괄호{} 생략 불가
- 람다식은 익명 함수가 아니라 익명 객체이다.
- 람다식(익명 객체)을 다루기 위한 참조변수가 필요. 참조변수의 타입은 무엇으로? → 함수형 인터페이스로 다루어야 한다.
- 함수형 인터페이스 : 단 하나의 추상 메서드만 선언된 인터페이스
@FunctionalInterface interface MyFunction { public abstract int max(int a , int b); } ///////////////////////////////////////// My Function f = new MyFunction() { public int max(int a, int b) { return a > b ? a: b ; } }; //////////////////////////////////////// int value = f.max(3, 5); // OK.
<함수형 인터페이스 타입의 매개변수와 반환타입>
- 함수형 인터페이스 타입의 매개변수
- 함수형 인터페이스 타입의 반환타입
- 람다식은 익명 객체이기 때문에, 타입이 없다. → 대입 연산자를 사용하기 위해 형변환을 하는데, 생략이 가능하다.
- 람다식은 객체이지만 Object타입으로 형변환 할 수 없다. → 굳이 하려면 함수형 인터페이스로 먼저 형변환 후에 형변환해야 한다.
- 람다식 내에서 참조하는 지역변수는 final이 붙지 않아도 상수로 간주되기 때문에 변경 불가이다.
- 외부 지역변수와 같은 이름의 람다식 매개변수는 허용되지 않는다.
- 자주 사용하는 다양한 함수형 인터페이스를 제공. → 표준화 할 수 있다.
- Function의 결합
- Function타입의 두 람다식을 하나로 합성 – andThen( )
- Function타입의 두 람다식을 하나로 합성 – compose( )
- Predicate의 결합
- and(), or(), negate()로 두 Predicate를 하나로 결합(default메서드)
- 등가비교를 위한 Predicate의 작성에는 isEqual()를 사용(static메서드)
- 하나의 메서드만 호출하는 람다식은 '메서드 참조'로 간단히 할 수 있다.
- static메서드 참조
- 생성자와 메서드 참조
- 다양한 데이터 소스(컬렉션, 배열)를 표준화된 방법으로 다루기 위한 것
- 스트림이 제공하는 기능
- 중간 연산 - 연산결과가 스티림인 연산. 반복적으로 적용가능
- 최종 연산 - 연산결과과 스트림이 아닌 연산. 단 한번만 적용가능(스트림의 요소를 소모)
- 스트림의 특징
- 데이터 소스로부터 데이터를 읽기만할 뿐 변경하지 않는다.
- Iterator처럼 일회용이다.(필요하면 다시 스트림을 생성해야하 함)
- 최종 연산 전까지 중간연산이 수행되지 않는다. - 지연된 연산
- 작업을 내부 반복으로 처리한다.
- 작업을 병렬로 처리 - 병렬스트림
- 기본형 스트림 - IntStream, LongStream, DoubleStream
- 오토박싱&언박싱의 비효율이 제거됨(Stream< Integer>대신 IntStream사용)
- 숫자와 관련된 유용한 메서드를 Stream보다 더 많이 제공
- 중간연산
- 최종연산
- Collection인터페이스의 stream()으로 컬렉션을 스트림으로 변환
Stream<E> stream() // Collection에 stream()이 정의되어 있다. → List와 Set을 구현한 컬렉션 클래스들은 모두 이 메서드로 steram 생성 가능
- 객체 배열로부터 스트림 생성하기
Stream<T> Stream.of(T... values) // 가변인자 Stream<T> Stream.of(T[]) Stream<T> Arrays.stream(T[]) Stream<T> Arrays.stream(T[] array, int startInclusive, int endExclusive)
- 기본형 배열로부터 스트림 생성하기
IntStream IntStream.of(int... valuse) IntStream IntStream.of(int[]) IntStream Arrays.stream(int[]) IntStream Arrays.stream(int[] array, int startInclusive, int endExclusive)
- 난수를 요소로 갖는 스트림 생성하기
- 지정된 범위의 난수를 요소로 갖는 스트림을 생성하는 메서드(Random클래스)
- 특정 범위의 정수를 요소로 갖는 스트림 생성하기(IntStream, LongStream)
- 람다식을 소스로 하는 스트림 생성하기
// 무한 스트림 static <T> Steram<T> iterate(T seed, UnaryOpearator<T> f) // 이전 요소에 종속적, seed : 초기 값 static <T> Steram<T> generate(Supplier<T> a) // 이전 요소에 독립적
- iterate()는 이전 요소를 seed로 해서 다음 요소를 계산한다.
- generate()는 seed를 사용하지 않는다.
- 파일을 소스로 하는 스트림 생성하기
`StreamFiles.list(Path dir) // Path는 파일 또는 디렉토리 Stream<String> Files.lines(Path path) // 파일 내용을 라인 단위로 Stream<string>으로 바꿈 Stream<String> Files.lines(Path path, Charset cs) Stream<String> lines() // BufferedReader클래스의 메서드
- 비어 있는 스트림 생성하기
Stream emptyStream = Stream.empty(); // empty()는 빈 스트림을 생성해서 반환한다. long count = emptyStream.count(); // count의 값은 0
<스트림의 요소 걸러내기 - filter(), distinct()>
<스트림 정렬하기 - sorted()>
- Comparator의 comparing()으로 정렬 기준을 제공
comparing(Function<T, U> keyExtractor) comparing(Function<T, U> keyExtractor, Comparator<U> keyComparator) //////////////////////////////////////////////////// studentStream.sorted(Comparator.comparing(Student::getBan) // 반별로 정렬 .forEach(System.out::println);
- 추가 정렬 기준을 제공할 때는 thenComparing()을 사용
thenComparing(Comparator<T> other) thenComparing(Function<T, U> keyExtractor) thenComparing(Function<T, U> keyExtractor, Comparator<U> keyComp) ////////////////////////////////////////////////////////////// studentStream.sorted(Comparator.comparing(Student::getBan) // 반별로 정렬 .thenComparing(Student::getTotalScore) // 총점별로 정렬 .thenComparing(Student::getName) // 이름별로 정렬 .forEach(System.out::println);
- Stream< T >타입의 스트림을 기본형 스트림으로 변환할 때 사용
- Stream< String > IntStream 변활할 때, mapToInt(Integer::parseInt)
- Stream< Integer > IntStream 변활할 때, mapToInt(Integer::intValue)
T타입 객체의 래퍼클래스
public final class Optional<T> { private final T value; // T타입의 참조변수(모든 종류의 객체, null까지도 저장 가능) -> 간접적으로 null를 다룸으로써 위험성 감소 ... }
- null대신 빈 Optional< T >객체를 사용하자
Optional<String> optVal = null; // 널로 초기화. 바람직하지 않음 Optional<String> optVal = Optional.<String>empty(); // 빈 객체로 초기화(<String> 생략가능)
- isPresent() – Optional객체의 값이 null이면 false, 아니면 true를 반환
- 기본형 값을 감싸는 래퍼클래스(성능 때문에 쓴다)
- OptionalInt의 값 가져오기 - int getAsInt()
- 빈 Optionial객체와의 비교
- 스트림의 모든 요소에 지정된 작업을 수행 - forEach(), forEachOrdered()
- 조건 검사
- 조건에 일치하는 요소 찾기
- 스트림의 요소를 하나씩 줄여가며 누적(accumulator)연산 수행
- 매개변수의 타입이 BinaryOperator< T > → 처음 두 요소를 가지고 연산한 결과를 가지고 그 다음 요소와 연산
- collect()는 Collector를 매개변수로 하는 스트림의 최종연산
- reduce() : 전체 리듀싱
- collect() : 그룹별 리듀싱
- Collector는 수집(collect)에 필요한 메서드를 정의해 놓은 인터페이스
- Collectors클래스는 다향한 기능의 컬렉터(Collector를 구현한 클래스)를 제공
- collect() : 스트림의 최종연산, 매개변수로 컬렉터를 필요로 한다.
- Collector : 인터페이스, 컬렉터는 이 인터페이스를 구현해야한다.
- Collectors : 클래스, static 메서드로 미리 작성된 컬렉터를 제공한다.
- 스트림을 컬렉션으로 변환 - toList(), toSet(), toMap(), toCollection()
- 스트림을 배열로 변환 - toArray() ( 배열의 반환타입을 정하지 않으면 Object[] 타입으로 반환)
Student[] stuNames = studentStream.toArray(Student[]::new); // OK Student[] stuNames = studentStream.toArray(); // 에러 Object[] stuNames = studentStream.toArray() ; // OK
- 스트림의 통계정보를 제공 - counting( ), summingInt( ), maxBy( ), minBy( ), …
- 그룹별로 리듀싱이 가능
- partitioningBy()는 스트림의 요소를 2분할 한다.
- groupingBy()는 스트림의 요소를 n분할 한다.