스트림(Stream)은 자바 8부터 추가된 기능으로, 데이터 처리에 있어서 간결하고 효율적인 코드 작성을 가능하게 해준다
스트림을 이용하면 컬렉션(List, Set 등)이나 배열에 저장된 요소들을 반복문 없이도 간단하게 필터링(filter), 변환(map), 정렬(sorted) 등의 작업을 적용할 수 있다.
특히 스트림은 중간 연산과 최종 연산을 구분하며, 지연 연산(lazy evaluation)을 통해 불필요한 연산을 최소화한다.
스트림은 일반적으로 한 번 사용하면 재사용할 수 없다(소진되면 끝). 따라서, stream() 으로 얻은 스트림을 여러 번 순회하려면, 다시 스트림을 생성해야 한다.

public class CreateStreamMain {
public static void main(String[] args) {
System.out.println("1. 컬렉션으로부터 생성");
List<String> list = List.of("a", "b", "c");
Stream<String> stream1 = list.stream();
stream1.forEach(System.out::println);
System.out.println("2. 배열로부터 생성");
String[] arr = {"a", "b", "c"};
Stream<String> stream2 = Arrays.stream(arr);
stream2.forEach(System.out::println);
System.out.println("3. Stream.of() 사용");
Stream<String> stream3 = Stream.of("a", "b", "c");
stream3.forEach(System.out::println);
System.out.println("4. 무한 스트림 생성 - iterate()");
// iterate: 초기값과 다음 값을 만드는 함수를 지정
Stream<Integer> infiniteStream = **Stream.iterate(0, n -> n + 2);**
infiniteStream.limit(3).forEach(System.out::println);
System.out.println("5. 무한 스트림 생성 - generate()");
// generate: Supplier를 사용하여 무한하게 생성
Stream<Double> randomStream = **Stream.generate(Math::random);**
randomStream.limit(3).forEach(System.out::println);
}
}
결과가 즉시 생성되지 않고, 최종 연산이 호출될 때 한꺼번에 처리된다는 특징이 있다(지연 연산).

map 은 각 요소를 하나의 값으로 변환하지만, flatMap 은 각 요소를 스트림(또는 여러 요소)으로 변환한 뒤, 그 결과를 하나의 스트림으로 평탄화(flatten)해준다.
[
[1, 2],
[3, 4], -> [1, 2, 3, 4, 5, 6]
[5, 6]
]
// map -> 결과적으로 List<List<Integer>> List<Stream<Integer>> 가 되었다. 이것은 우리가 기대한 결과가 아
니다
List<Stream<Integer>> mapResult = outerList.stream()
.map(list -> list.stream())
.toList();
System.out.println("mapResult = " + mapResult);
// flatMap
// flatMap 을 쓰면 내부의 Stream 들을 하나로 합쳐 List<Integer> 를 얻을 수 있다.
// flatMap 은 중첩 구조(컬렉션 안의 컬렉션, 배열 안의 배열 등)를 일차원으로 펼치는 데 사용된다
List<Integer> flatMapResult = outerList.stream()
.flatMap(list -> list.stream())
.toList();
System.out.println("flatMapResult = " + flatMapResult);
최종 연산(Terminal Operation)은 스트림 파이프라인의 끝에 호출되어 실제 연산을 수행하고 결과를 만들어낸다. 최종 연산이 실행된 후에 스트림은 소모되어 더 이상 사용할 수 없다.
