람다식의 도입 -> 자바는 객체지향언어+함수형 언어
메서드를 하나의 식(expression)으로 표현한 것
메서드의 이름x, 반환값x == 익명 함수(anonymous function)
반환타입 메서드이름(매개변수 선언){
문장들
}
⬇️
(매개변수 선언) -> {
문장들
}
ex)
int max(int a, int b){
return a > b ? a : b;
}
⬇️
(a, b) -> { a > b ? a : b }
;
) 생략(int a, b) -> a > b ? a : b
(x)(a) -> a * a
-> a -> a * a
(a, b) -> { a > b ? a : b }
-> (a, b) -> a > b ? a : b
ex)
매개변수가 없는 경우
int roll(){
return (int)(Math.random()*6);
}
-> () -> (int)(Math.random()*6)
👽 자바에서 모든 메서드는 클래스 내에 포함되어야 한다
=> 람다식은 익명 클래스의 객체와 동등하다
(int a, int b) -> a > b ? a : b
↔️
new Object() {
int max(int a, int b){
return a > b ? a : b;
}
}
👽 객체를 가리키는 참조변수가 있어야 호출이 가능하다
참조형이므로 그 타입은 클래스/인터페이스
타입 f = (int a, int b) -> a > b ? a : b
MyFunction
인터페이스 내에 max()
라는 메서드가 정의되어 있다면
interface MyFunction {
public abstract int max(int a, int b);
}
이 인터페이스를 구현한 익명 클래스의 객체 생성은 아래와 같이 할 수 있다.
타입 f = (int a, int b) -> a > b ? a : b
에서 타입이 MyFunction, 람다 함수 대신 익명 클래스
MyFunction f = new MyFunction(){
public int max(int a, int b){
return a > b ? a : b;
}
};
// 익명 객체의 메서드 호출
int big = f.max(5, 3);
↔️
MyFunction f = (int a, int b) -> a > b ? a : b; // 익명 객체를 람다식으로 대체
int big = f.max(5, 3); // 익명 객체의 메서드를호출
람다식을 다루기 위한 인터페이스(ex.
MyFunction
)
@FunctionalInterface
= 메서드를 호출할 때 람다식을 참조하는 참조변수 / 람다식 자체를 매개변수로 지정
ex)
@Functionallnterface
interface FunctionalInterface{ // 함수형 인터페이스 정의
void method();
}
void call(method arg){
arg.method();
}
...
FunctionalInterface f = () -> System.out.println("method()");
call(f); // call(() -> System.out.println("method()")); 람다식을 직접 매개변수로 지정도 가능
람다식의 타입 함수형 인터페이스의 타입
단지 함수형 인터페이스로 람다식을 참조할 수 있는 것
-> 대입연산자의 양변의 타입을 일치시키기 위해서는 형변환이 필요
& 람다식은 오직 함수형 인터페이스로만 형변환이 가능
익명클래스와 동일
final
이 붙지 않아도)자주 쓰이는 형식의 메서드를 함수형 인터페이스로 정의해 둔 것
ex)
Predicate<String> isEmptyStr = s -> s.length () == 0;
String s = "";
if(isEmptyStr.test (s)) // if (s.length () == 0)
System.out.println ("This is an empty String.");
매개변수가 두 개인 함수형 인터페이스 : Bi~
컬렉션 프레임원과 함수형 인터페이스
IntSupplier
, IntConsumer
, .. ex)
Function<String, Integer> f = (s) -> Integer.parselnt(s, 16);
Function<Integer, String> g = (i) -> Integer.toBinaryString(i);
Function<String,String> h = f.andThen(g);
== 여러 조건식을 논리 연산자로 연결
논리연산자 | Predicate |
---|---|
&&(and) | and() |
||(or) | or() |
!(not) | negate() |
종류 | 람다 | 메서드 참조 |
---|---|---|
static메서드 참조 | (x) -> ClassName.method(x) | ClassName::method |
인스턴스메서드 참조 | (obj.x) -> obj.method(x) | ClassName::method |
특정 객체 인스턴스메서드 참조 | (x) -> obj.method(x) | obj::method |
ex)
Function<String, Integer〉 f = (String s) -> Integer.parselnt(s);
⬇️
Function<String, Integer〉 f = (String s) -> Integer::parselnt(s);
Supplier<MyClass> s = () -> new MyClass(); // 람다식
Supplier<MyClass> s = MyClass::new; // 메서드참조
매개변수가 있는 생성자는 매개변수의 개수에 따라 알맞은 함수형 인터페이스 사용
Functior<Integer, MyClass> f = (i) ->newMyClass(i); //람다식
Functior<Integer, MyClass> f2 = MyClass::new; // 메서드 참조
BiFunctior<Integer, String, MyClass〉 bf = (i, s) -> new MyClass(i, s);
BiFunctior<Integer, String, MyClass> bf2 = MyClass::new; // 메서드 참조
데이터 소스를 추상화하고 데이터를 다루는데 자주 사용되는 메서드들을 정의해 놓은 것
데이터 소스 추상화-> 데이터 소스가 무엇이던 간어 같은 방식으로 다를 수 있게함
List<String> sortedList = strStream2.sorted().collect(Collectors.toList()); //정렬된 결과를 List에 담아서 반환
for(String str : strList)
System.out.println(str);
⬇️stream.forEach(System.out::println)
연산(operation) : 스트림에 정의된 메서드 중에서 데이터 소스를 다루는 작업을 수행하는 것
여러개의 중간 연산을 연속해서 연결할 수 있음
중간 연산 : 연산 결과가 스트림인 연산
ex)
IntStream
, LongStream
, DoubleStream
parallel()
호출(이 메서드 취소시에는 sequential()
)Stream<T> Collection.stream()
ex)
List<Integer> list = Arrays.asList(1,2,3,4,5); // 가변인자
Stream<Integer〉 intStream = list.stream(); // list를 소스로 하는 컬렉션 생성
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.of
, LongStream
...
IntStream IntStream.range(int begin, int end)
IntStream IntStream.rangeClosed(int begin, int end)
난수(랜덤값)
무한 스트림(infinite stream) : 반환하는 스트림의 크기가 정해져 있지x
-> limit()
로 크기 제한
IntStream intStream = newRandom().ints();//무한 스트
intStream.limit(5).forEach(System.out::println); // 5개의 요소만 출력
유한 스트림
IntStream ints(long streamSize)
LongStream longs(long streamSize)
DoubleStream doubles(long streamSize)
IntStream intStream=newRandom().ints(5);//크기가 5인 난수스트림을 반환
지정된 범위의 난수를 발생
IntStream ints(int begin, int end)
LongStream longs(long begin, long end)
DoubleStream doubles(double begin, double end)
IntStream ints(long streamSize, int begin, int end)
LongStream longs(long streamSize, long begin, long end)
DoubleStream doubles(long streamSize, double begin, double end)
람다식 : iterate()
, generate()
람다식을 매개변수로 받아서 이 람다식에 의해 계산되는 값들을 요소로 하는 무한 스트림 생성
iterate()
: static <T> Stream<T> iterate(T seed, UnaryOperator<T> f)
generate()
: static <T> Stream<T> generate(Supplier<T> s)
파일
Stream<Path> Files.list(Path dir)
: 디렉토리(dir)에 있는 파일의 목록을 소스로 하는 스트림 반환빈 스트림 : null을 반환하는 것 보다 나음
Stream.empty();
두 스트림 연결 : Stream의 static 메서드 concat()
String[] strl = {"123", "456", "789"};
String[] str2 = {"ABC", "abc", "DEF"};
Stream<String> strsl = Stream.of(strl);
Stream<String> strs2 = Stream.of(str2);
Stream<String> strs3 = Stream.concat (strsl, strs2);
skip()
, limit()
filter()
, distinct()
sorted()
map()
map()
의 연산 결과를 기본형 스트림으로 변환 : mapTpInt()
, mapToLong()
, mapToDouble()
peek()
ex)
fileStream.map (File: : getName) // Stream<File> ->Stream<String)
.filter(s -> s. indexof ('.')! =-1) //확장자가 없는 것은 제외
.peek(s -> system.out.printf("flename = %s%n", s)) // 파일명 출력
.map(s -> s.substring (s.indexof('.')+1)) // 확장자만 추출
.peek (s->system.out.printf ("extension=%s%n", s)) // 확장자를 출력한다.
.forEach (System.out::println);
ex)
Stream<Stream<String>> strStrStrm = strArrStrm.map(Arrays::stream);
⬇️
Stream<String> strStrm = strArrStrm.flatMap(Arrays::stream);
Optional<T>
: 지네릭 클래스, T 타입의 객체를 감싸는 래퍼 클래스
isNull()
, nonNull()
, requireNonNull()
)of()
, ofNullable()
of()
vs ofNullable()
ofNullable()
: 참조변수의 값이 null일 가능성이 있는 경우of()
: null이면 NullPointerException
발생empty()
(null도 가능하지만 비추천)get()
NoSuchElementException
발생orElse()
/ 대체할 값을 반환하는 람다식 지정 : orElseGet()
/ 예외 발생 : orElseThrow()
filter()
, map()
, flatMap()
사용 가능(==Stream)
isPresent()
: Optional객체의 값이 null이면 false, 아니면 true를 반환
ifPresent(Consumer<T) block)
: 값이 있으면 주어진 람다식을 실행, 없으면 아무 일도 하지 않음
findAny()
, findFirst()
와 같이 optional<T>
를 반환하는 최종 연산과 잘 어울림: OptionalInt
, OptionalLong
, OptionalDouble
최종 연산후에는 스트 림이 닫히게 되고 더 이상 사용할 수 없음
void forEach(Consumer<? super T> action)
allMatch()
,anyMatch()
,noneMatch()
,findFirst()
,findAny()
count()
,sum()
,average()
,max()
, min()
reduce()
collect()
: 스트림의 요소를 수집하는 최종 연산수집 방법 : collector (매개변수로 collector 필요)
Collector
인터페이스, 컬렉터는 이 인터페이스를 구현해야 한다. Collectors
클래스, static메서드로 미리 작성된 컬렉터를 제공2.7 Collector 구현하기
2.8 스트림의 변환