Lambda & Stream

Heeeoh·2024년 3월 4일
0

JAVA

목록 보기
1/2
post-thumbnail

✔️ lambda(람다)


람다식은 메서드로 전달할 수 있는 익명 함수를 단순화한 코드 블록
() -> {}
() : 파라미터
-> : 화살표
{} : 실행문

  • 람다식은 함수 자체를 전달 인자로 보내거나 변수에 저장하는 것이 가능

  • 람다식에서 타입이 예측가능하다면 생략 가능

  • 특정 람다식을 사용하여 변수에 담는데 그 변수의 타입은 함수형 인터페이스 타입이다.


함수형 인터페이스 : 하나의 추상 메서드를 갖는 인터페이스
함수 디스크립터 : 함수형 인터페이스의 추상 메서드 시그니처
메소드 시그니쳐 : 메소드의 이름 + 메소드의 파라미터 + 파라미터의 수

함수형 인터페이스함수 디스크립터기본형 특화
Predicate<T>T -> booleanIntPredicate, LongPredicate, DoublePredicate
Consumer<T>T -> voidIntConsumer, LongConsumer, DoubleConsumer
Function<T, R>T -> RIntFunction<T>, IntToDoubleFinction, ...
Supplier<T>() -> TBooleanSupplier, IntSupplier

더 있지만 자세한 건 강의 참조

기본형 특화의 경우 wrapper 클래스와 primitive 타입의 오토 언박싱을 문제없이 처리해주기 위해 특화된 것이다.



✔️ 함수형 인터페이스를 알아야 하는 이유


람다 표현식은 함수 자체를 전달 인자 or 변수 저장하는게 가능하다 하였는데

그렇다면 전달 인자나 변수의 타입이 정의되어야하기 때문이다.
그렇기에 함수형 인터페이스를 변수의 타입이나 전달 인자에 명시해주면 된다.

람다식이 가능한 Stream의 filter 매개변수를 확인해 보니 진짜로 함수형 인터페이스를 매개변수로 받고 있다.


〰️ Stream


컬렉션이나 배열 등 데이터를 처리하는 기술
중간 연산을 통해 가공된 스트림은 마지막으로 최종 연산을 통해 요소를 소모하여 결과를 출력
한 번 생성한 스트림은 사용 후 재사용 불가, 전체 데이터에 대한 처리가 이루어지면 종료 -> 다시 스트림을 생성해야 함

Collection의 Stream은 이미 데이터가 모여있는 형태의 스트림 객체 생성


Collection의 stream() 메서드는 default로 정의하고 있다.
List, Set, Queue, (Map.value() -> map.value().stream()) 에서 사용가능

Array의 stream 은 Arrays.stream(arr[])로 사용

Stream 사용방법


1. Stream.builder

Stream.Builder<String> builder = Stream.builder();
builder.accept("123");
builder.accept("456");

List<Integer> collect = builder.build().map(Integer::parseInt).toList();
for (Integer i : collect) {
    System.out.println("i = " + i);
}

Stream 객체의 생성방식은 자체적으로 데이터 생성, 처리 가능 (많이 사용하지는 않는다.)


2. 람다식 사용

List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);


int[] array = list.stream().filter(x -> x < 3).mapToInt(x -> x).toArray();
        
for (int i : array) {
    System.out.println("i = " + i);
}

스트림 연산 처리

  1. 스트림 객체 생성
  2. 중간 연산
  3. 최종 연산

중간 연산

연산반환 형태연산 인수
filterStream<T>Predicate<T>
mapStream<T>Function<T, R>
limitStream<T>
sortedStream<T>Comparator<T>
distinctStream<T>
peekStream<T>Consumer<T>
skipStream<T>

중간 연산은 결과물이 Stream 이기에 반드시 최종 연산으로 결과를 반환해야한다.


최종 연산

중간 연산을 통해 가공된 스트림을 최종 연산을 통해 각 요소를 소모하여 결과를 출력

연산반환 형태
forEach스트림의 각 요소를 소비하며 람다 적용, void 반환
count스트림 요소의 수를 Long 타입으로 반환
collectList, Map 형태의 컬렉션 반환
sum스트림의 모든 요소에 대한 합을 반환
reduce스트림의 요소를 하나씩 줄여가며 연산 수행 후 결가 반환, Optional 반환

더 많이 있으니 찾아보자

Stream() 에서 sum을 사용하려면 숫자 연산 관련 자료형에 mapToInt등으로 스트림을 숫자 관련 자료형으로 Mapping 해주고 사용

mapToInt -> toArray() 가능,
List 나 Collection 으로 사용 불가능
왜냐하면 int 형으로 mapping 되었기에 wrapper 클래스 타입을 받는 Collection을 사용할 수 없기 때문이다.


🟰 병렬 스트림


말 그대로 병렬로 처리한다.
2개의 스레드로 처리해서 속도가 높아지지만 중복 제거의 경우 문제가 생길 수 있음 -> eqauls() 사용

// List
list.parallelStream()

// Array
Arrays.stream(arr[]).parallel()

정렬

sorted()를 이용한 정렬 : 반드시 대상 객체들이 Comparable 인터페이스를 구현한 클래스
즉, 비교가 가능한 객체여야 한다.

혹은 sorted(Comparator.comparing(E))를 사용해서 정리


✔️ Mapping


스트림이 관리하는 데이터를 다른 형태의 데이터로 변환

map, mpaToInt(), mapToDouble() 등

연산반환 형식
allMatch파라미터로 전달되는 람다식 기준으로 스트림 데이터가 모두 일치하는지 확인
anyMatch파라미터로 전달되는 람다식 기준으로 스트림 데이터가 하나라도 일치하는지를 확인
noneMatch파라미터로 전달되는 람다식 기준으로 스트림 데이터가 모두 일치하지 않는지를 확인
findFirst스트림 데이터 중에서 가장 첫번째 데이터를 변환
reduce스트림 데이터 중에서 임의의 데이터를 변환

🔖 학습 참조

유튜브 나무소리

profile
열심히 살자

0개의 댓글