๐ ๏ธBackend/โJava
[Java] ์๋ฐ ์คํธ๋ฆผ(Stream) ๊ฐ๋ + ์์ ์ด์ ๋ฆฌ ๐
junbin2
2025. 6. 3. 02:11
โ 1. ์ธ๋ถ๋ฐ๋ณต๊ณผ ๋ด๋ถ๋ฐ๋ณต
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// ์ธ๋ถ ๋ฐ๋ณต: for-each๋ฌธ
for (String name : names) {
System.out.println(name);
}
// ๋ด๋ถ ๋ฐ๋ณต: Stream + forEach
names.stream().forEach(name -> System.out.println(name));
(1) ์ธ๋ถ๋ฐ๋ณต
- ๊ฐ๋ฐ์๊ฐ ๋ฃจํ ๊ตฌ์กฐ๋ฅผ ์ง์ ์์ฑํด์ ์์๋ฅผ ํ๋์ฉ ์ฒ๋ฆฌํ๋ ๋ฐฉ์์ ์๋ฏธํ๋ค.
- ์ฝ๊ฒ ๋งํด, for๋ฌธ while๋ฌธ Iterator ๊ฐ์ ๋ฐ๋ณต๋ฌธ์ ์ง์ ์ฌ์ฉํด์ ์ด๋ป๊ฒ ๋ฐ๋ณตํ ์ง ์ง์ ๋ช ์ํด์ ์ ์ดํ๋ ๊ฒฝ์ฐ์ด๋ค.
(2) ๋ด๋ถ๋ฐ๋ณต
- ๋ฐ๋ณต์ ์ ์ด๋ฅผ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ํ๋ ์์ํฌ์๊ฒ ๋งก๊ธฐ๊ณ , ๊ฐ๋ฐ์๋ ๋ฌด์์ ํ ์ง๋ง ์ ๋ฌํ๋ ๋ฐฉ์์ ์๋ฏธํ๋ค.
- ๋ํ์ ์ผ๋ก๋ ์๋ฐ์ Stream API๊ฐ ๋ด๋ถ ๋ฐ๋ณต์ ์ฌ์ฉํ๊ณ ์์.
- ์ฆ, ์ด๋ป๊ฒ ๋ฐ๋ณตํ ์ง๋ ๋ฉ์๋๋ฅผ ํตํด ํธ์ถํ๊ณ , ์ด๋ค๊ฑธ ๋ฐ๋ณตํ ์ง๋ง ๋๊ฒจ์ฃผ๋ฉด ๋๋ ๋ฐฉ์์ด๋ค.
- ๋ค์ํ ๋ฐ๋ณต์ ์ฝ๋๋ก ๋ฏธ๋ฆฌ ๋ง๋ค์ด์ ๋ฉ์๋๋ก ์ ๊ณต์ ํด์ฃผ๊ธฐ ๋๋ฌธ์ ๊ตฌํ์์ด ํธ๋ฆฌํ๊ฒ ํธ์ถ๋ง์ผ๋ก ๊ฐ๋ฅ
- ์ฆ, ๋ค์ํ ๋ฉ์๋๋ฅผ ํตํด ์ง์ ๊ตฌํํ์ง ์๊ณ ๊ตฌํ ๋ ๋ฐ๋ณต๋ฌธ ์ฝ๋๋ฅผ ํธ์ถ ํ ์ ์๋ค.
โ 2. Stream API
// Stream
public interface Stream<T> extends BaseStream<T, Stream<T>> {
Stream<T> filter(Predicate<? super T> predicate);
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
void forEach(Consumer<? super T> action);
...
}
// Collection - List, Set, Map ...
public interface Collection<E> extends Iterable<E> {
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
}
- Java 8๋ถํฐ ๋์ ๋ ๊ธฐ๋ฅ์ผ๋ก ๋ฐ๋ณต, ํํฐ๋ง, ๋งคํ, ์ ๋ ฌ, ์ง๊ณ ๋ฑ์ ์ ์ธ์ ์ผ๋ก ์ํํ ์ ์๊ฒ ๋์์ฃผ๋ API์ด๋ค.
- ์ฝ๊ฒ๋งํด, ์ปฌ๋ ์ ์ ํฌํจ์ด ๋์ด์๋๊ฒ ์๋ JRE์ ํฌํจ ๋ ์๋ฐ API์ด๋ค.
- ๋ณดํต ํจ์ํ ์คํ์ผ ์ฆ, ๋๋ค์ ์ฒ๋ฆฌ๋ฅผ ์ง์ํ๋ฉฐ, ๋ํ์ ์ผ๋ก๋ ์ปฌ๋ ์ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃฐ ๋ ๋ง์ด ์ฌ์ฉ ๋จ.
- Stream API๋ ์ธํฐํ์ด์ค๋ก ์ ๊ณต์ด ๋๋ฉฐ, ํด๋น ํด๋์ค๋ฅผ ๋ด๋ถ์ ์ผ๋ก ๊ตฌํํ ํด๋์ค ๋ํ ์ ๊ณต์ ํด์ค๋ค.
- ๋ํ์ ์ผ๋ก ๋ด๋ถ ๊ตฌํ ํด๋์ค๋ก๋ ReferencePipeline ํด๋์ค๋ฅผ ์ ๊ณตํด์ค๋ค.
- ํด๋น StreamSupport ํด๋์ค์ stream() ๋ฉ์๋๋ฅผ ํตํด ๊ตฌํ ํด๋์ค์ธ ReferencePipeline์ Stream์ผ๋ก ๋ฐํํด์ค.
- ์ปฌ๋ ์ ๋ด๋ถ์์๋ StreamSupport ํด๋์ค์ stream() ๋ฉ์๋๋ฅผ ํตํด ํด๋์ค๋ฅผ ์ด์ฉํจ.
- ์ฆ, ์ปฌ๋ ์ ์ด Stream ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋๊ฒ ์๋, ์ด๋ฏธ ๊ตฌํ ๋ Stream ๊ตฌํ ํด๋์ค๋ฅผ ํธ์ถํด์ ์ด์ฉํจ.
- ํต์ฌ์ ์ปฌ๋ ์ ๋ฐ ๋ฐฐ์ด ๊ฐ์ ๋ฐ์ดํฐ ์์ค๋ฅผ ์ ์ธํ์ผ๋ก ์ฒ๋ฆฌํ ์ ์๋๋ก ๋์์ฃผ๋ ๋๊ตฌ(API)์ด๋ค.
โ 3. ๊ธฐ๋ณธ์๋ฃํ ์คํธ๋ฆผ
// IntStream ์ฌ์ฉ ์์
IntStream.of(1, 2, 3).sum(); // 6
IntStream.range(1, 4).forEach(System.out::println); // 1, 2, 3
IntStream.rangeClosed(1, 3).average(); // OptionalDouble[2.0]
// ๋ฐฐ์ด๊ณผ IntStream ์ฌ์ฉ ์์
int[] numbers = {1, 2, 3, 4, 5};
int sum = IntStream.of(numbers).sum(); // ํฉ๊ณ: 15
double avg = IntStream.of(numbers).average().orElse(0); // ํ๊ท : 3.0
int[] numbers = {5, 1, 3, 9, 7};
IntStream.of(numbers) // ๋ฐฐ์ด์ ์คํธ๋ฆผ์ผ๋ก
.sorted() // ์ ๋ ฌ
.forEach(System.out::println);
- IntStream, LongStream, DoubleStream ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํด์ค.
- ๊ธฐ๋ณธํ int, long, doubleํ์ ์์๋ก ์ด๋ฃจ์ด์ง ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃจ๊ธฐ ์ํ ์คํธ๋ฆผ์ด๋ค.
- ๊ธฐ๋ณธ Stream์ ๊ฐ์ฒด ํ์ ๋ง ๋ค๋ฃจ๊ธฐ ๋๋ฌธ์ int, long, dobule ๊ฐ์ ๊ธฐ๋ณธํ์ ์คํ ๋ฐ์ฑ/์ธ๋ฐ์ฑ์ด ํ์ํจ.
- ์ด ๊ณผ์ ์์ ์คํ ๋ฐ์ฑ, ์ธ๋ฐ์ฑ์ ์ฑ๋ฅ ์ ํ์ ์์ธ์ด ๋๋ฏ๋ก, ๊ธฐ๋ณธํ ์ ์ฉ Stream์ ์ ๊ณตํ๋ ๊ฒ์.
โ 4. ๋ฐฐ์ด ์คํธ๋ฆผ
// ๊ธฐ๋ณธํ ๋ฐฐ์ด
int[] nums = {1, 2, 3, 4, 5};
int sum = Arrays.stream(nums).sum(); // 15
int[] intArr = { 1, 2, 3 };
IntStream intStream = Arrays.stream(intArray);
intStream.forEach(item -> System.out.println(item));
// ์ฐธ์กฐ(๊ฐ์ฒด) ๋ฐฐ์ด
String[] words = {"a", "bb", "ccc"};
long count = Arrays.stream(words)
.filter(w -> w.length() >= 2)
.count(); // 2 ("bb", "ccc")
String[] strArr = {"ํ๊ธธ๋","์ด์์ ","๊น์ ์ "};
Stream<String> strem = Arrays.stream(strArray);
strem.forEach(item -> System.out.println(item));
- ๋ฐฐ์ด์ Stream์ผ๋ก ๋ฐ๊พธ๋ ํ์ค์ ์ธ ๋ฐฉ๋ฒ์ ์๋ฏธํ๋ค.
- ์ปฌ๋ ์ ํด๋์ค๋ค์ .stream()์ ๋ฐ๋ก ์ธ ์ ์์ง๋ง, ๋ฐฐ์ด์ Arrays.stream()์ ์จ์ผ ์ด์ฉ์ด ๊ฐ๋ฅํจ.
- ์ฆ, ๋ฐฐ์ด์ ์คํธ๋ฆผ์ ํธ๋ฆฌํ ๊ธฐ๋ฅ์ ํ์ฉํ๊ธฐ ์ํด ์คํธ๋ฆผ์ผ๋ก ๋ง๋๋ ๊ฒฝ์ฐ์.
โ 5. ํ์ผ ์คํธ๋ฆผ
Path path = Paths.get("c:\\data\\data.txt");
Stream<String> fileStream = Files.lines(path);
fileStream.forEach(line -> System.out.println(line));
fileStream.close();
- File.lines(path)์ ์ฌ์ฉํ์ฌ ํ ์คํธ ํ์ผ๋ก๋ถํฐ ํ ๋จ์ ๋ฌธ์์ด๋ก ๊ตฌ์ฑ๋ ์คํธ๋ฆผ์ ์์ฑํ ์ ์์.
- ์ด์ฒ๋ผ ์ปฌ๋ ์ ๋ฟ ์๋๋ผ ๋ค์ํ ๊ณณ์์ Stream API๋ฅผ ํ์ฉํ๊ณ ์์.
โ 6. ์ปฌ๋ ์ ์คํธ๋ฆผ
List<String> list = List.of("apple", "banana", "cherry");
list.stream()
.filter(s -> s.startsWith("b"))
.forEach(System.out::println); // "banana"
- Collection ์ธํฐํ์ด์ค์์ stream()๊ณผ parallelStream() ๋ฉ์๋๋ฅผ ์ ๊ณต์ ํด์ค.
- ํด๋น ๋ฉ์๋๋ฅผ ํตํด Stream API๋ก ์ปฌ๋ ์ ๋ฐ์ดํฐ๋ฅผ Stream์ ๋ฉ์๋๋ก ์ฒ๋ฆฌ ํ ์ ์๊ฒ ๋จ.
- ์ฆ, ์ปฌ๋ ์ ์ ์คํธ๋ฆผ์ผ๋ก ๋ฐ๊ฟ ๋ฐ๋ณต๋ฌธ ์์ด map, filter, collect ๊ฐ์ ์ ์ธํ ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํด์ง.
- parallelStream()์ ๋ณ๋ด์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํ ์คํธ๋ฆผ์ ๋ฆฌํดํด์ค.
- ์ฆ, stream()์ ๋๊ธฐ์ + ์์ฐจ ์ฒ๋ฆฌ, parallelStrem()์ ๋๊ธฐ์ + ๋ณ๋ ฌ์ฒ๋ฆฌ(๋ฉํฐ์ค๋ ๋) ์ผ๋ก ์ฒ๋ฆฌ๋ฅผ ํด์ค.
- ์ฝ๊ฒ๋งํด, ์ผ๋ฐ ์คํธ๋ฆผ์ ๋จ์ผ ์ค๋ ๋๋ก ๋๊ธฐ์ ์ผ๋ก ์ฒ๋ฆฌ๋ฅผ ํด์ค.
- parallelStrem()์ ๋๊ธฐ์ ์ผ๋ก ์ฒ๋ฆฌ๋ฅผ ํด์ฃผ์ง๋ง, ๋ฉํฐ์ค๋ ๋๋ก ๋ณ๋ ฌ๋ก ์ฒ๋ฆฌ๋ฅผ ํด์ค.
(1) ์ปฌ๋ ์ - ์ผ๋ฐ ์คํธ๋ฆผ & ๋ณ๋ ฌ ์คํธ๋ฆผ
Set<Integer> set = new HashSet<>();
for (int i = 0; i < 10; i++) {
set.add(i);
}
// ์ผ๋ฐ ์คํธ๋ฆผ ์ฌ์ฉ : stream()
Stream<Integer> stream = set.stream();
stream.forEach(item -> System.out.println(item)); // ๊ฒฐ๊ณผ: 0123456789 ์์ฐจ์ ์ผ๋ก ์ถ๋ ฅ
// ๋ณ๋ ฌ ์คํธ๋ฆผ ์ฌ์ฉ : parallelStream()
Stream<Integer> stream = set.parallelStrema();
stream.forEach(item -> System.out.println(item)); // ๊ฒฐ๊ณผ: ์ค์ผ์ค๋ฌ์ ์ํด ๋๋ค์ฒ๋ผ ์ถ๋ ฅ๋จ.
// ์ฆ, 1204356789 ์ด๋ฐ์์ผ๋ก ์ถ๋ ฅ๋จ ๊ฐ ์ซ์๋ ํ๋์ ์ค๋ ๋๊ฐ ๋งก์์ ์ฒ๋ฆฌ๋ฅผ ํจ.
- ๋ณ๋ ฌ ์คํธ๋ฆผ์ parallelStream() ๋ฉ์๋๋ฅผ ์ด์ฉํ์ฌ ์ฒ๋ฆฌ๋ฅผ ํ ์ ์์.
- ํด๋น ๋ฉ์๋๋ฅผ ์ด์ฉํ๋ฉด ์คํธ๋ฆผ ๋ฉ์๋๋ฅผ ํตํด ํํฐ๋ ๋ค์ํ ๋ฉ์๋๋ฅผ ์ด์ฉํ๊ฒ ๋๋ฉด ๋ณ๋ ฌ๋ก ์ฒ๋ฆฌ๊ฐ ๋จ.
- ์ฆ, ๋ณ๋ ฌ์ฒ๋ฆฌ ์ฌ๋ฌ ์ค๋ ๋๋ฅผ ๋ง๋ค์ด์ ๋ณ๋ ฌ๋ก ์ฒ๋ฆฌ๋ฅผ ํ๋ ๊ฒ์ ์๋ฏธํ๋ฉฐ, ์ซ์๊ฐ ๋๋ค์ฒ๋ผ ๋ณด์ผ ์ ์์.
- ์ด์ ๋, cpu์ ์ฝ์ด ์์ ๋ง๊ฒ ์ฒ๋ฆฌ๊ฐ ๋๋ฉฐ, ์ด์์ฒด์ ์ ์ค์ผ์ค๋ฌ์ ์ํด ์ฒ๋ฆฌ๊ฐ ๋๋ฏ๋ก ๋๋ค์ฒ๋ผ ๋ณด์.
- ์ฆ, ์ค๋ ๋๋ฅผ ์ฌ๋ฌ๊ฐ ๋ง๋ค์ด์ ์ฒ๋ฆฌ๋ฅผ ํ๊ฒ ๋๋ฉด CPU ์ฝ์ด๋ฅผ ํ์ฉ ํ ์ ์๋ค๋ ๋๋์.
โ 7. ์คํธ๋ฆผ ํ์ดํ๋ผ์ธ๊ณผ ์ค๊ฐ & ์ต์ข ์ฐ์ฐ
- ์คํธ๋ฆผ ํ์ดํ๋ผ์ธ์ ์ปฌ๋ ์ , ๋ฐฐ์ด, ๋๋ ํ์ผ๋ก๋ถํฐ ์์ฑ๋ ์คํธ๋ฆผ์ ์ด๋ค ์ฒ๋ฆฌ๋ฅผ ์ํํ๊ณ ์๋ก์ด ์คํธ๋ฆผ์ด ๋ง๋ค์ด์ง๋ฉฐ, ๊ณ์ํด์ ์ด๋ฌํ ์ฒ๋ฆฌ ๊ณผ์ ์ ๋ฐ๋ณตํ๋ ๊ฒ์ ์๋ฏธํ๋ฉฐ, ๋ฉ์๋ ์ฒด์ด๋์ ์ฌ์ฉํ์ฌ ํ์ดํ๋ผ์ธ์ ๊ตฌ์ถํ ์ ์๋ค.
- ํด๋น ํ์ดํ๋ผ์ธ์์ ์ ๊ณตํด์ฃผ๋ ๋ฉ์๋๋ค์ ์ค๊ฐ์ฐ์ฐ๊ณผ ์ต์ข ์ฐ์ฐ์ผ๋ก ๋๋๋ฉฐ, ์ค๊ฐ ์ฐ์ฐ๋ง์ผ๋ก๋ ์๋ฌด ์ผ๋ ์ผ์ด๋์ง ์๋๋ค. ๋ํ, ์ต์ข ์ฐ์ฐ์ด ํธ์ถ๋ ๋ ์ค๊ฐ ์ฐ์ฐ๋ค์ด ํจ๊ป ์คํ์ด ๋๋ฉฐ ์ด๊ฑธ ์ง์ฐ ์ฐ์ฐ์ด๋ผ๊ณ ํ๋ค.
List<String> words = List.of("apple","banana", "cherry", "Avocado");
long count = words.stream() // ์๋ณธ ์คํธ๋ฆผ
.map(String::toUpperCase) // ์ค๊ฐ์ฐ์ฐ
.filter(word -> word.startsWith("A")) // ์ค๊ฐ์ฐ์ฐ - A๋ก ์์ํ๋ ์์๋ง
.count(); // ์ต์ข
์ฐ์ฐ - ์ต์ข
๋ฆฌ์คํธ์ ์์ ๊ฐ์๋ฅผ ๋ฆฌํดํด์ค.
System.out.println(count); // 2๊ฐ ์ถ๋ ฅ๋จ
(1) ์ค๊ฐ์ฐ์ฐ
- ํด๋น ์คํธ๋ฆผ์ ๊ฐ๊ณตํ๊ฑฐ๋ ํํฐ๋ง์ ํ๋ ๋จ๊ณ์ด๋ค.
- ํญ์ ์๋ก์ด ์คํธ๋ฆผ์ ๋ฐํํ๋ฉฐ, ์ฐ์์ ์ผ๋ก ์ฒด์ด๋์ ํ๋ฉฐ ๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉฐ ํํฐ, ์ ๋ ฌ ๋ฑ์ ์ ์ฉ ํ ์ ์์.
- ์๋ณธ ์คํธ๋ฆผ์์ ๋ฐ์ดํฐ๋ฅผ ๋ณํํ๊ฑฐ๋ ํํฐ๋ง ๋ฑ์ผ๋ก ์๋ก์ด ์คํธ๋ฆผ์ ์์ฑํ๋ ์ฐ์ฐ
- ์ค๊ฐ์ฐ์ฐ์์ ์์ฑ๋ ์คํธ๋ฆผ์ ๋ค์ ์ฐ์ฐ์ผ๋ก ์ฐ๊ฒฐ๋์ด ํ์ดํ๋ผ์ธ์ ํ์ฑํจ
- filter(), map(), sorted() ๋ฑ์ ์ฐ์ฐ
(2) ์ต์ข ์ฐ์ฐ(์ข ๋ฃ์ฐ์ฐ)
- ์คํธ๋ฆผ ์ฒ๋ฆฌ์ ๋ง์ง๋ง ๋จ๊ณ๋ฅผ ์๋ฏธํ๋ฉฐ, ๋ฉ์๋๋ก ์ ๊ณต์ด ๋จ.
- ์ค๊ฐ ์ฐ์ฐ์ด ์ ์ํ ์์ ์ ์ค์ ๋ก ์คํํ๋ ์ญํ ์ ๊ฐ์ง๋ฉฐ, ์ต์ข ์ฐ์ฐ์ด ์ํ๋๋ฉด ์ดํ ์คํธ๋ฆผ์ ์ฌ์ฌ์ฉ ๋ถ๊ฐ๋จ.
- collect(), forEach(), count(), anyMatch() ... ๋ฑ์ด ์์.
- ์ค๊ฐ์ฐ์ฐ์ ๊ฑฐ์น ์คํธ๋ฆผ์ ๋ํด ์ต์ข ์ ์ธ ๊ฒฐ๊ณผ๋ฅผ ๋ง๋ค๊ฑฐ๋ ๋์์ ์ํํ๋ ๋ถ๋ถ์.
- ์คํธ๋ฆผ ํ์ดํ๋ผ์ธ์์ ๋ง์ง๋ง์ ํ ๋ฒ๋ง ์ํ์ด ๋จ.
โ 8. ์ค๊ฐ์ฐ์ฐ
(1) ํํฐ๋ง
- ์ปฌ๋ ์ ์์๋ค ์ค์์ ์ค๋ณต์ ์ ๊ฑฐํ๊ฑฐ๋ ํน์ ์กฐ๊ฑด์ ๋ง์กฑํ๋ ์์๋ง ์ถ์ถํ์ฌ ์๋ก์ด ์คํธ๋ฆผ์ ์์ฑํ๋ ์์
- distinct(): ์ค๋ณต ์ ๊ฑฐ๋ฅผ ํด์ฃผ๋ ๋ฉ์๋์ด๋ฉฐ, ์ค๋ณต๋ ๋ฐ์ดํฐ๋ฅผ ํ๋๋ก ๋ง๋ค๊ณ ๋๋จธ์ง๋ ๊ฑธ๋ฌ์ฃผ๋ ์ญํ ์ ํจ.
- filter(): ์กฐ๊ฑด์ ํตํด ๋ฐฐ์ด์ ๊ฐ์ ๊ฑธ๋ฌ๋ด๊ธฐ ์ํด ์ฌ์ฉํ๋ ๋ฉ์๋ ( ํจ์ํ ์ธํฐํ์ด์ค๋ก ์์ฉ )
(2) ๋งคํ
- ์์๋ค์ ๋ค๋ฅธ ์์๋ก ๋ณํํ์ฌ ์๋ก์ด ์คํธ๋ฆผ์ ์์ฑํ๋ ์์ ์ ์๋ฏธํ๋ค.
- ์คํธ๋ฆผ์ ์์๋ฅผ ๋ค๋ฅธ ํํ๋ก ๋ณํํ๋ ์์ ์ ์๋ฏธํ๋ค.
- ์ฆ, ๊ธฐ์กด ์คํธ๋ฆผ์ ๊ฐ ์์์ ํจ์๋ฅผ ์ ์ฉํด์ ์๋ก์ด ์คํธ๋ฆผ์ ์์ฑํ๋ ๊ณผ์ ์ ์๋ฏธํ๋ค.
[1] map()
- ํ๋์ ์ ๋ ฅ์ ํ๋์ ์ถ๋ ฅ์ผ๋ก ๋งคํ ์ฆ, ์์๋ฅผ ์ผ๋์ผ๋ก ๋ณํํ ๋ ์ฌ์ฉ์ด ๋จ.
List<String> names = List.of("jason", "emily", "michael");
List<String> upperNames = names.stream()
.map(String::toUpperCase) // ๊ฐ ์์๋ฅผ ๋๋ฌธ์๋ก ๋ณํ
.collect(Collectors.toList());
System.out.println(upperNames); // [JASON, EMILY, MICHAEL]
[2] flatMap()
- ํ๋์ ์ ๋ ฅ์ ์ฌ๋ฌ ์ถ๋ ฅ์ผ๋ก ํผ์นจ ์ฆ, ์์ ํ๋๋ฅผ ์ฌ๋ฌ ์์๋ก ํผ์ณ์ ์คํธ๋ฆผ์ ์์ฑํ ๋ ์ฌ์ฉ์ด ๋จ.
List<String> words = List.of("Java", "Stream");
List<String> characters = words.stream()
.flatMap(word -> Arrays.stream(word.split(""))) // ๊ฐ ๋จ์ด๋ฅผ ๊ธ์๋ก ๋ถํดํด์ ํผ์นจ
.collect(Collectors.toList());
System.out.println(characters); // [J, a, v, a, S, t, r, e, a, m]
[3] ๊ฐ์ฒด ํ๋ ๋งคํ๋ ๊ฐ๋ฅ
- ์คํธ๋ฆผ์ ๊ฐ ์์๋ฅผ ํจ์์ ์ ์ฉํด์ ๋ค๋ฅธ ๊ฐ์ฒด๋ก ๋ณํํ ๋๋ ์ฌ์ฉ์ด ๋ ์ ์์.
class User {
private String name;
public User(String name) { this.name = name; }
public String getName() { return name; }
}
List<User> users = List.of(new User("Alice"), new User("Bob"));
List<String> names = users.stream()
.map(User::getName) // User ๊ฐ์ฒด์์ ์ด๋ฆ๋ง ์ถ์ถ
.collect(Collectors.toList());
System.out.println(names); // [Alice, Bob]
// ํด๋น ํจ์ ์ธํฐํ์ด์ค ์ฌ์ฉ์ด ๋จ.
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
(2) ์ ๋ ฌ
- ์คํธ๋ฆผ์ ์์๋ค์ ์ค๋ฆ์ฐจ์ ๋๋ ๋ด๋ฆผ์ฐจ์์ผ๋ก ์ ๋ ฌํ์ฌ ์๋ก์ด ์คํธ๋ฆผ์ ์์ฑํ๋ ์์ ์ ์๋ฏธํ๋ค.
- Stream<T> ์์ sorted() ๋ฉ์๋๋ฅผ ์ฌ์ฉํด์ ์ ๋ ฌ์ ํ ์ ์์.
- ์ ๋ ฌ์ด ๋๋ ํด๋์ค์์๋ Comparable ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํด compareTo() ๋ฉ์๋๋ฅผ ์ค๋ฒ๋ผ์ด๋ฉ์ ํด์ผ ์ฌ์ฉ์ด ๊ฐ๋ฅํจ.
List<String> names = List.of("Charlie", "Alice", "Bob");
List<String> sorted = names.stream()
.sorted() // ๊ธฐ๋ณธ ์ ๋ ฌ: ์ํ๋ฒณ ์ -> String์ด Comparable์ ๊ตฌํํ๊ณ ์์ด์ ๊ฐ๋ฅํจ.
.collect(Collectors.toList());
System.out.println(sorted); // [Alice, Bob, Charlie]
- ์ด ์ฝ๋๋ ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ฉฐ, ์ด์ ๋ String ํด๋์ค๊ฐ Comparable์ ๊ตฌํํ๊ณ ์๊ธฐ์ ๊ฐ๋ฅํจ.
class User implements Comparable<User> {
private String name;
private int age;
// ๊ธฐ๋ณธ ์ ๋ ฌ ๊ธฐ์ค ์ ์ (age ๊ธฐ์ค ์ค๋ฆ์ฐจ์)
@Override
public int compareTo(User other) {
return Integer.compare(this.age, other.age);
}
}
List<User> users = List.of(
new User("Alice", 30),
new User("Bob", 25),
new User("Charlie", 35)
);
List<User> sortedUsers = users.stream()
.sorted() // compareTo ๊ธฐ์ค(age ๊ธฐ์ค)์ผ๋ก ์ ๋ ฌ
.collect(Collectors.toList());
System.out.println(sortedUsers); // [Bob(25), Alice(30), Charlie(35)]
- ํด๋น ์ฝ๋๋ ์ฌ์ฉ์ ์ ์๋ก ์ง์ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํด์ ์ฌ์ฉ์ด ๊ฐ๋ฅํจ
- ์ฆ, sorted() ๋งค์๋๋ก ์ ๋ ฌ์ ํ๊ธฐ ์ํด์๋ ํด๋น ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํด์ผํจ.
- ํ์ง๋ง, ์ง์ ๊ตฌํํ์ง ์๊ณ ๋ ํ ์ ์๋ ๋ฐฉ๋ฒ์ด ์์.
List<User> sortedByName = users.stream()
.sorted(Comparator.comparing(User::getName)) // ์ด๋ฆ ๊ธฐ์ค ์ค๋ฆ์ฐจ์
.collect(Collectors.toList());
List<User> sortedByAgeDesc = users.stream()
.sorted(Comparator.comparing(User::getAge).reversed()) // ๋์ด ๋ด๋ฆผ์ฐจ์
.collect(Collectors.toList());
- Cinoarator์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ์ง ์์๋ ๋๋ค. ์ธ๋ถ์์ ์ ๋ ฌ ๊ธฐ์ค์ ์ ๊ณตํ๋ ๋ฐฉ์์ด๋ค.
โ 9. ์ข ๋ฃ์ฐ์ฐ
- ์ค๊ฐ์ฒ๋ฆฌ๋ฅผ ๊ฑฐ์น ์คํธ๋ฆผ์ ๋ํด ์ง๊ณ๋ ๊ฒฐ๊ณผ ์ถ๋ ฅ ๋ฑ์ ์ต์ข ์ฒ๋ฆฌ๋ฅผ ์ํํ๋ ๊ฒ์ ์ต์ข ์ฐ์ฐ์ด๋ผ๊ณ ํ๋ค.
- ์ง๊ณ(ํฉ๊ณ, ํ๊ท , ์ต๋, ์ต์ ๋ฑ), ๋งค์นญ, ์์ง ๋ฑ์ ์์ ์ ์ํํจ
- ์คํธ๋ฆผ ํ์ดํ๋ผ์ธ์ ๋ง์ง๋ง ๋จ๊ณ์์ ์ฌ์ฉ์ด๋๋ฉฐ, ์คํธ๋ฆผ์ ๋ค์ ์ฌ์ฉํ ์ ์๊ฒ ๋ง๋ ๋ค.
- ์ข ๋ฃ์ฐ์ฐ์ด ์ํ๋๊ธฐ ์ ๊น์ง๋ ์คํธ๋ฆผ ํ์ดํ๋ผ์ธ์ด ์ค์ ๋ก ์คํ์ด ๋์ง๋ ์๋๋ค ( ์ง์ฐ ์ฐ์ฐ )
- ์ง์ฐ ํ๊ฐ๋ฅผ ํตํด ์คํธ๋ฆผ ํ์ดํ๋ผ์ธ์ ํจ์จ์ ์ผ๋ก ๊ตฌ์ฑํ๋ฉฐ ํ์ํ ๊ฒฐ๊ณผ๋ฅผ ์ป๋๋ค.
(1) ๋ฃจํ
- ์คํธ๋ฆผ์ ๊ฐ ์์๋ฅผ ์ํํ๋ฉด์ ์ด๋ค ๋์์ ์ํํ๋ ๊ฒ์ ์๋ฏธํ๋ค.
- ์ฝ๊ฒ ๋งํด, ์คํธ๋ฆผ์ forEach() ๊ฐ์ ๋ฉ์๋๋ฅผ ์๋ฏธํ๋ค. ํด๋น ๋ฉ์๋๋ ์์์ ์ ์ฒด๋ฅผ ์ํํ๋ ์์ ์ ์ ๊ณตํด์ค
- peek() ๋ฉ์๋๋ ๊ฐ ์์๋ฅผ ์ํํ๋ฉด์ ์ฃผ์ด์ง ๋์(๋๋ค์)์ ์ํํ๋ ์ค๊ฐ ์ฐ์ฐ์ผ๋ก ๋๋ฒ๊น ์ด๋ ๋ก๊น ์ ์์ฃผ ์ด์ฉ๋จ.
- forEach() : ์ข ๋ฃ์ฐ์ฐ / peek() : ์ค๊ฐ์ฐ์ฐ
(2) ๋งค์นญ
[1] allMatch (Predicate)
List<Integer> numbers = List.of(2, 4, 6, 8);
boolean allEven = numbers.stream().allMatch(n -> n % 2 == 0); // true
- ์คํธ๋ฆผ์ ๋ชจ๋ ์์๊ฐ ์กฐ๊ฑด์ ๋ง์กฑํ๋ฉด true, ํ๋๋ผ๋ ๋ง์กฑํ์ง ์์ผ๋ฉด false
- ๋ง์ฝ ์ด๋ค ์์๊ฐ ์กฐ๊ฑด์ ๋ง์กฑํ์ง ์์ผ๋ฉด ์ฆ์ false ๋ฅผ ๋ฐํํ๊ณ ํ์์ ์ข ๋ฃํ๋ค.
[2] anyMatch (Predicate)
List<Integer> numbers = List.of(1, 3, 5, 6);
boolean hasEven = numbers.stream().anyMatch(n -> n % 2 == 0); // true (6์ด ์ง์)
- ์คํธ๋ฆผ์ ์์ ์ค ํ๋๋ผ๋ ์กฐ๊ฑด์ ๋ง์กฑํ๋ฉด true, ์๋๋ฉด false
- ์กฐ๊ฑด์ ๋ง์กฑํ๋ ์์๋ฅผ ์ฐพ์ผ๋ฉด ์ฆ์ true ๋ฅผ ๋ฐํํ๊ณ ํ์์ ์ข ๋ฃํ๋ค.
[3] noneMatch (Predicate)
List<Integer> numbers = List.of(1, 3, 5);
boolean noEven = numbers.stream().noneMatch(n -> n % 2 == 0); // true
- ์คํธ๋ฆผ์ ์ด๋ค ์์๋ ์กฐ๊ฑด์ ๋ง์กฑํ์ง ์์ผ๋ฉด true, ํ๋๋ผ๋ ๋ง์กฑํ๋ฉด false
- ์กฐ๊ฑด์ ๋ง์กฑํ๋ ์์๋ฅผ ์ฐพ์ผ๋ฉด ์ฆ์ false ๋ฅผ ๋ฐํํ๊ณ ํ์์ ์ข ๋ฃํ๋ค.
(3) ์์ง
// List
List<String> names = List.of("ํ๊ธธ๋", "์๊บฝ์ ", "์ฅ๋ณด๊ณ ");
List<String> result = names.stream()
.filter(name -> name.length() >= 3)
.collect(Collectors.toList());
// Set
Set<String> upperNames = names.stream()
.map(String::toUpperCase)
.collect(Collectors.toSet());
- ์คํธ๋ฆผ์ ์์๋ค์ ๋ค๋ฅธ ํํ๋ก ๋ชจ์์ ๋ณํํ๋ ์ต์ข ์ฐ์ฐ์ ์๋ฏธํ๋ค.
- ๊ฐ์ฅ ๋ํ์ ์ผ๋ก Collectiors ์ ํธ๋ฆฌํฐ ํด๋์ค์ ํจ๊ป ์ฌ์ฉ์ด ๋๋ค.
- ์ฆ, ๋ง์ง๋ง์ ๊ฐ๊ณตํ ๋ฐ์ดํฐ๋ฅผ "์ํ๋ ์๋ฃํ ๋ฐ์ค(List,Set,Map ๋ฑ)์ ๋ด๋ ๊ฒ์ ์๋ฏธํ๋ค.
- ์ฝ๊ฒ ๋งํด, ์คํธ๋ฆผ์์ ํํฐ ๋ฑ์ ๋ฐ๋ผ ๋ณํ ๋ ๋ฐ์ดํฐ ๋ชจ์์ ๊ฐ์ฒด๋ก ๋ด์์ ์ ๋ฌ์ ํด์ฃผ๊ธฐ ์ํด ์ฌ์ฉ์ ํจ.