Stream이란?
- Java 8부터 Stream이 Java에 도입되었다.
- Stream의 주 목적은 복잡한 데이터 처리 간소화, 코드 가독성 향상, 쉬운 병렬 처리 적용이다.
- Stream의 사전적 의미는 흐르다이다. 어떠한 것이 흐르는 것이 아니고 데이터의 흐름을 말한다.
[스트림의 데이터 흐름 참고 사진]
[Stream의 데이터 흐름]
1. 위 그림은 어부가 물고기를 그물로 잡고, 여러 마리를 일정한 기준으로 모아서 상자에 넣고,
이들을 하나로 모은 뒤 트럭에 실어서 운반하는 과정을 나타내고 있다.
2. 위 그림에서의 물고기와 같은 어류의 이동을 stream이라고 정의할 수 있다.
3. 어부가 어류 중에서도 고등어를 잡고 싶어서 그물로 고등어를 잡았다.
이 행위를 filter라고 하고, 이 연산자를 중간 연산자라고 합니다.
4. 그리고 고등어를 포장하지 않고 생으로 팔 수는 없기 때문에 상자에 담아야 합니다.
이 행위를 map이라고 하고, 이 연산자도 마찬가지로 중간 연산자라고 합니다.
5. 마지막으로, 고등어가 실린 수많은 상자를 운반하여 다른 곳으로 이동하면서 끝이 난다.
이 행위를 collect라고 하고, 이 연선자는 최종 연산자라고 합니다.
6. 요약하자면, 스트림은 수 많은 데이터의 흐름 속에서 각각의 원하는 값을 가공하여
최종 소비자에게 제공하는 역할을 한다고 보면 된다.
Stream 특징
- Stream은 데이터 자체를 저장하지 않고, 데이터를 처리하는 파이프라인을 제공한다. map(), filter() 등을 사용해 데이터를 변환하고 필터링하는데에 유리하다.
- Stream은 지연 평가 방식이다. 예를 들어, filter()와 같은 중간 연산을 여러개 정의하더라도 최종적으로 collect()와 같은 최종 연산이 호출될 때까지 연산은 실행되지 않는다. 이는 성능 최적화에 도움을 준다.
- Stream은 불변성을 가지고있다. Stream은 원본 데이터를 변경 하지않고, 변환 후의 결과를 새로운 스트림으로 반환한다. 안전한 동시성을 보장한다.
- 데이터 가공전의 Stream 자체는 재사용이 불가능하다.
Stream 사용 예제
public class StreamTest {
public static void main(String[] args) {
// 1. Stream 사용 전
List<Person> people = new ArrayList<>();
people.add(new Person("Kevin", 200));
people.add(new Person("John", 140));
people.add(new Person("Neko", 100));
people.add(new Person("Dan", 60));
List<Person> hundredClub = new ArrayList<>();
for(Person p : people) {
if(p.money >= 100) {
hundredClub.add(p);
}
}
System.out.println("======== person.name ========");
hundredClub.forEach(person -> System.out.println(person.name));
}
static class Person {
String name;
int money;
public Person(String name, int money) {
this.name = name;
this.money = money;
}
}
}
결과 :
======== person.name ========
Kevin
John
Neko
public class StreamTest {
public static void main(String[] args) {
// 2. Stream 사용 후
List<Person> people = new ArrayList<>();
people.add(new Person("Kevin", 200));
people.add(new Person("John", 140));
people.add(new Person("Neko", 100));
people.add(new Person("Dan", 60));
// filter
List<Person> hundredClub = people.stream()
.filter(person -> person.money >= 100)
.collect(Collectors.toList());
System.out.println("======== filterList ========");
hundredClub.forEach(person -> System.out.println(person.name));
// sorted
List<Person> sortedList = people.stream()
.sorted(Comparator.comparing(person -> person.name))
.collect(Collectors.toList());
System.out.println("======== sortedList ========");
sortedList.forEach(person -> System.out.println(person.name));
// filter + sorted
List<Person> hundredSortedClub = people.stream()
.filter(person -> person.money >= 100)
.sorted(Comparator.comparing(person -> person.name))
.collect(Collectors.toList());
System.out.println("======== filterList + sortedList ========");
hundredSortedClub.forEach(person -> System.out.println(person.name));
// map : Person의 이름만 추출하여 리스트로 변환
List<String> names = people.stream()
.map(person -> person.name)
.collect(Collectors.toList());
System.out.println("======== Person Names ========");
names.forEach(System.out::println);
// map 사용 예제 2: Person의 money를 10% 더해서 새로운 리스트로 생성
List<Integer> updatedMoney = people.stream()
.map(person -> person.money + (int)(person.money * 0.1))
.collect(Collectors.toList());
System.out.println("======== Updated Money (10% added) ========");
updatedMoney.forEach(System.out::println);
}
static class Person {
String name;
int money;
public Person(String name, int money) {
this.name = name;
this.money = money;
}
}
}
결과 :
======== filterList ========
Kevin
John
Neko
======== sortedList ========
Dan
John
Kevin
Neko
======== filterList + sortedList ========
John
Kevin
Neko
======== Person Names ========
Kevin
John
Neko
Dan
======== Updated Money (10% added) ========
220
154
110
66
package com.example.test.Stream;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class StreamTest {
public static void main(String[] args) {
// 3. 데이터 가공 전의 Stream은 재사용 불가능
List<Person> people = new ArrayList<>();
people.add(new Person("Kevin", 200));
people.add(new Person("John", 140));
people.add(new Person("Neko", 100));
people.add(new Person("Dan", 60));
Stream<Person> personStream = people.stream();
// 첫 번째 사용: 정상 동작
personStream.filter(person -> person.money >= 100)
.forEach(person -> System.out.println(person.name));
// 두 번째 사용: 에러 발생 (스트림은 한 번만 사용 가능)
personStream.forEach(person -> System.out.println(person.name));
}
static class Person {
String name;
int money;
public Person(String name, int money) {
this.name = name;
this.money = money;
}
}
}
결과 :
Exception in thread "main" java.lang.IllegalStateException:
stream has already been operated upon or closed
'Java' 카테고리의 다른 글
[Java] Thread와 Runnable의 개념 및 사용법 (1) | 2024.11.28 |
---|---|
[Java] 람다식(Lambda) 개념 및 사용 예제 (0) | 2024.10.16 |
[Java] 자료구조 HashMap의 특징 및 핵심 원리 (0) | 2024.09.18 |
[Java] 자바 접근제어자(public, protected, default, private) (1) | 2024.09.16 |
[Java] Quartz Scheduler 사용 해보기 (0) | 2024.09.03 |