스트림이란
여러가지 다양한 데이터 소스 접근하여 데이터를 처리하는 방법을 표준화
- 배열, 리스트, 집합 등 다양한 데이터에 동일한 데이터 처리 적용 가능
데이터 소스 => 스트림 생성 => 중간 처리 => 최종 연산
- 모든 연산은 최종 연산 시 한 번에 이뤄진다.
- 중간 처리와 최종 연산 시 함수평 프로그래밍 기법이 자주 사용된다.
스트림 API 예시
Filter
- 스트림 요소를 주어진 조건에 따라 필터링

numbers를 스트림화 한다.(스트림 생성)
filter 해준다.
Map
- 스트림의 각 요소에 함수를 적용하여 반환
내가 원하는 형태로 다시 맵핑 한다.

Reduce
- 스트림의 요소를 결합하여 하나의 값으로 반환
- 예제 : 숫자 리스트의 총합 구하기

Collect
예제1 | 리스트를 콤마로 구분된 문자열로 변환하기

예제2 : 이름이 "C"로 시작하는 요소만 필터링하여 리스트로 반환하기

- 연습 : 이름이 "C"로 시작하지 않는 요소만 필터링
public class CollectExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Edward");
List<String> filteredNames = names.stream().filter(name->!name.startsWith("C"))
.filter(name->!name.startsWith("c"))
.collect(Collectors.toList());
System.out.println(filteredNames);
}
}
예제 3 | 이름을 Key로, 이름의 길이를 value로 하는 맵 형태로 반환하기

ForEach
Sorted
예제 | 문자열 리스트를 알파벳순으로 정렬하기

Limit
예제 | 리스트에스 5개의 데이터를 뽑기

FindFirst
- 스트림에서 생성된 요소 중 첫 번째 요소를 반환
예제 | 리스트에서 첫 번째 짝수 반환하기

AnyMatch
- 스트림 요소 중 하나라도 조건을 만족하는지 검
예제 | 리스트에 짝수가 있는지 확인하기

과정

왜 스트림 API 쓰는가?
- 간결한 코드 ➡️ 높은 가독성
- 코드 분량 적다 ➡️ 높은 생산성
- 실수 발생할 확률이 적다 ➡️ 디버깅 시간 최소화

코테에서도 중요하지만, 현업에서 더더욱 많이 쓰인다!
스트림 API 특징
- 원본 데이터 변겅하지 않는다.
- 스트림은 일회용이다.
- 내부 반복으로 작업을 처리한다.


Optional
- 값의 존재 여부를 표현하는 객체
- 스트림 API의 최종연산은 Optional을 반환할 수 있고 그렇지 않을 수도 있음
예제

StringBuilder
- StringBuilder은 가변객체, 문자열 결합 시 새로운 객체를 생성하지 않고 기존 버퍼에 추가
- String은 불변 객체, 따라서 += 연산을 사용할 때마다 새로운 문자열 객체 생성
- 즉, StringBuilder을 사용하면 메모리 효율성 향상 및 가비지 컬렉션의 부하를 대폭 줄일 수 있다.
c.f Stream API ) map, filter, foreach 자주 쓴다.