[영상후기] [10분 테코톡] 차리의 Stream

박철현·2023년 3월 24일
0

영상후기

목록 보기
56/160

movie

스트림

  • 데이터의 흐름
  • 자바 스트림 API : 스트림 데이터를 어떻게 다룰 것인가 논하는 일종의 파이프라인

구조

  • 생성, 가공, 소비 구조

생성

  • 리스트, 맵 같은 컬랙션, 배열, 파일로 부터 생성 가능
    • 컬렉션과 다르게 무한으로 만들 수도 있음
    • 별도 서드파티 라이브러리 활용할 수 있음

가공 : 중간 연산자

  • filter, map, limit 등 소스로부터 얻어낸 값들을 입맛대로 가공하는 역할
    • 결과 : 새로운 스트림 반환(lazy evaluation 가능)
      • lazy evaluation : 최종 연산 전까지 중간 연산은 실제로 실행되지 않음
      • 새로은 스트림 인스턴스를 돌려주만 함
      • 루프 퓨전, 쇼트 서킷 테크닉 활용 가능

루프 퓨전

  • 개별적 요소가 하나씩 단계를 순차적으로 거쳐가는 모습이 반복문이 합쳐진 것 같아 불림

쇼트 서킷

  • 일련의 논리연산을 진행할 때 모든 연산을 수행하지 않고 결과가 확실할 때 나머지 연산을 수행하지 않는 것을 의미
IntStream.range(0, 10_000)
	.limit(5)
    .... => 5번만 실행함

중간연산자 구분 : stateless(독립적), stateful(종속적)

  • stateless : filter, map, peek 등
    • 특정 행위 수행 시 다른 요소에 대해 독립적
    • map : 현재 바라보고 있는 값에만 신경
  • stateful : sorted, distinct, limit 등 선행된 연산에 영향을 받음
    • 자기 자신 이외의 값은 무엇이었는지 등에 대해 특정 상태를 알고 신경을 써야함

소비 : 최종 연산자

  • 결과를 생성하거나 사이드 이펙트를 만들기 위해 사용
    • collect, findAny, findFirst 등
      • collect의 경우 collectors를 이용하면 활용성이 다양

주의점

  • 최종 연산자 수행되고 나면 스트림 파이프라인은 소비된 것으로 간주

    • 다시 사용하려면 새로운 스트림 생성 필요
  • 사이드 이펙트를 통해서만 동작할 수 있는 연산들은 신중하게 사용해야 함

    • forEach : 로그나 디버깅을 위한 출력에만 사용하는 것을 권장

    • 이펙티브 자바에서 forEach가 덜 스트림 스럽다 라고 이야기

      public static List<String> discouragedVersion(Stream<String> stream, Pattern pattern) {
      	List<String> results = new ArrayList<>();
         stream.filter(s -> pattern.matcher(s).matches())
         // forEach 내부에서 값을 할당하며 사용할 경우 불필요한 sideEffect -> 외부 상태 변경(외부 선언 리스트)
         .forEach(results::add);
         return results;
      }
      
      public static List<String> discouragedVersionWithParallel(Stream<String> stream, Pattern pattern) {
      	List<String> results = new ArrayList<>();
         stream.parallel()
         .filter(s -> pattern.matcher(s).matches())
         // 병렬처리 추가될 경우 올바른 결과값 기대 어렵
         // 요소 추가하려는데 누군가는 접근하려고 할 경우 등
         .forEach(results::add);
         return results;
      }
      
      public static List<String> encouragedVersion(Stream<String> stream, Pattern pattern) {
         return stream
         .filter(s -> pattern.matcher(s).matches())
         // sideEffect X
         .collect(Collectors.toList());
      }

스트림 장점

  • 가독성 증가
  • 코드의 변경이 쉽다(유연) : 메서드의 순서 변경
    • filter를 먼저 적용하고 이후에 함수 적용하고 싶다 하면 메소드 순서만 바꾸면 됨
    • 기존 코드의 경우 어디 손봐야할지 고민
    • 병렬처리 간단하기 해결 가능 : parallel 키워드

스트림 단점

컴퓨팅 비용

  • 내부적 다양한 조건과 상황에 따라 연산을 처리하기 때문에 생성하는데 적지 않은 비용이 발생
    • 성능이 core하다면 스트림 사용 한번 더 고려 필요

인지에 대한 비용

  • 외부 반복 : 직접 값을 꺼내와서 사용
  • 내부 반복 : 스트림 내부 연산
    • GOF 디자인 패턴 중 하나, 코드 정상적으로 동작하지 않은 경우 내부에서 반복이 어떻게 동작하는지 명확하게 알고있어야 함(루프 퓨전 등)
    • 병렬처리 시 더욱 주의 필요
.distinct() .limit(10) => distinct()로 중복값 제거하고 01이 반복적으로 들어오면 limit(10)에 걸릴 일이 없음 => 무한 루프
--> ex) .limit(10) 한 뒤에 distinct() 해야 10번걸림
profile
비슷한 어려움을 겪는 누군가에게 도움이 되길

0개의 댓글

관련 채용 정보