컴퓨터, 알고리즘을 공부하면서 항상 기초 문법와 자료구조를 위주로 사용해서 스트림은 항상 지나쳤었다. 특히 코테에서 시간이나 메모리 효율이 떨어져서 더 등한시한 것 같다. 하지만 알고 안 쓰는 것과 모르고 못 쓰는건 다르고 언제 뭐가 어떻게 필요할지 모르니 겸손한 자세로 다시 공부 해 본다.


1. 스트림(Stream)이란?

  • 데이터를 “흐름”처럼 다루는 API (자바 8부터 도입)

  • 배열이나 컬렉션(List, Set 등)을 스트림으로 바꾸면, 데이터를 선언적(declarative), 함수형 스타일로 가공할 수 있음.

  • 반복문(for, while)을 직접 쓰지 않고, filter, map, reduce 같은 메서드를 “파이프라인”처럼 연결해서 처리.

  • 한 마디로 스트림 = 데이터를 한 줄로 흘려보내면서, 원하는 방식대로 걸러내고 변환하고 모으는 것.

2. 스트림의 3단계

  1. 생성 (Create)
    → .stream(), Stream.of(), Arrays.stream(), IntStream.range()

  2. 중간 연산 (Intermediate, 계속 Stream 반환)
    → filter, map, sorted, distinct, limit, skip, …

  3. 최종 연산 (Terminal, Stream 소모 & 결과 반환)
    → forEach, collect, reduce, count, min, max, anyMatch, …

3. 스트림 주요 메서드

.stream()

  • 컬렉션 → 스트림으로 변환

  • 예시:

.filter(Predicate<T>)

  • 조건에 맞는 요소만 통과시킴

  • 매개변수: Predicate<T> (T → boolean)

  • 예시:

.map(Function<T,R>)

  • 요소를 다른 값으로 변환

  • 매개변수: Function<T,R> (T → R)

  • 예시:

.forEach(Consumer<T>)

  • 요소를 하나씩 소비(출력, 저장 등)

  • 매개변수: Consumer<T> (T → void)

  • 예시:

.reduce(BinaryOperator<T>)

  • 요소들을 하나로 축약(누적 계산)

  • 매개변수: BinaryOperator<T> (T,T → T)

  • 예시:

종류메서드받는 함수형 인터페이스설명예시 코드
생성.stream()컬렉션 → 스트림list.stream()
Stream.of(T...)값들로 스트림 생성Stream.of(1,2,3)
IntStream.range(1,10)1~9 int 스트림IntStream.range(1,5)
---------------------------------------------------------------------------------------------------------------------
중간 연산.filter()Predicate<T>조건 맞는 값만 통과list.stream().filter(x -> x>3)
.map()Function<T,R>T → R 변환list.stream().map(String::length)
.mapToInt()ToIntFunction<T>T → int 변환list.stream().mapToInt(String::length)
.sorted()Comparator<T>정렬list.stream().sorted()
.distinct()중복 제거list.stream().distinct()
.limit(n)앞에서 n개만list.stream().limit(3)
.skip(n)앞의 n개 건너뜀list.stream().skip(2)
.peek()Consumer<T>중간에 찍기list.stream().peek(System.out::println)
---------------------------------------------------------------------------------------------------------------------
최종 연산.forEach()Consumer<T>요소 소비list.stream().forEach(System.out::println)
.collect()Collector<T,A,R>모으기list.stream().toList()
.reduce()BinaryOperator<T>누적 계산list.stream().reduce(0, Integer::sum)
.count()개수 반환list.stream().count()
.min()/max()Comparator<T>최소/최대 요소list.stream().max(Integer::compare)
.anyMatch()Predicate<T>조건 만족 요소 있는지list.stream().anyMatch(x->x>3)
.allMatch()Predicate<T>전부 조건 만족?list.stream().allMatch(x->x>0)
.noneMatch()Predicate<T>조건 만족 요소 없는지list.stream().noneMatch(x->x<0)
.findFirst()첫 번째 요소 반환list.stream().findFirst()
.findAny()아무 요소 반환list.stream().findAny()

이 밖에도 표에 다 담지도 못할 정도로 매우매우 많다..

4. Stream활용 기초 코테 풀기

1. 프로그래머스 - 홀짝에 따라 다른 값 반환하기
문제 설명 : 양의 정수 n이 매개변수로 주어질 때, n이 홀수라면 n 이하의 홀수인 모든 양의 정수의 합을 return 하고 n이 짝수라면 n 이하의 짝수인 모든 양의 정수의 제곱의 합을 return 하는 solution 함수를 작성해 주세요.

2. 프로그래머스 - 문자열 돌리기
문제 설명 : 문자열 str이 주어집니다.
문자열을 시계방향으로 90도 돌려서 아래 입출력 예와 같이 출력하는 코드를 작성해 보세요.

3. 프로그래머스 - 나누어 떨어지는 숫자 배열
문제 설명 : array의 각 element 중 divisor로 나누어 떨어지는 값을 오름차순으로 정렬한 배열을 반환하는 함수, solution을 작성해주세요.
divisor로 나누어 떨어지는 element가 하나도 없다면 배열에 -1을 담아 반환하세요.

4. 프로그래머스 - 두 정수 사이의 합
문제 설명 : 두 정수 a, b가 주어졌을 때 a와 b 사이에 속한 모든 정수의 합을 리턴하는 함수, solution을 완성하세요.
예를 들어 a = 3, b = 5인 경우, 3 + 4 + 5 = 12이므로 12를 리턴합니다.


🔹오늘의 나는 무엇을 잘했는가?
겸손한 마음으로 빈번하게 쓰이지 않을지 몰라도 유용하게 쓰일 수 있는 내용을 꼼꼼하게 학습했다.

🔹어떤 문제를 겪었고, 어떻게 해결했나?
아는 메서드가 거의 없으니까 문제 해결방법이 stream 메서드로는 전혀 생각이 안났다. 내가 생각하는 역할을 하는 메서드가 있는지 찾아보고 어떻게 사용하는지 찾아보면서 학습했다.

🔹오늘 배운 것
stream이 확실히 알고리즘을 푸는데 시간 소요는 많이 되어도 알고리즘이 한 줄로 쓰이면서 문제 해결의 방법이 명료하게 보였고 무엇보다 코드가 굉장히 짧았다는 점에서 유연하고 간결한 데이터처리에 유용하다는 것을 알았다.

🔹나만의 팁 or 복습 방법
나는 오늘 학습한 내용을 알고리즘 문제에 바로 적용해보면서 학습했다. 글로만 정리했을 때에는 어느정도 이해했다고 생각했는데, 막상 직접 사용해보려고 하니 어디서부터 손을 써야하는지 모르겠고 막막했다. 이렇듯 어떤 내용을 학습했다면 바로 넘어가지 말고 배운 내용을 알고리즘이나 프로젝트 등 어딘가에 직접 적용을 해보면 훨씬 더 많은 도움이 된다고 생각한다.

0개의 댓글