๐Ÿ› ๏ธ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 ๋“ฑ)์— ๋‹ด๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.
  • ์‰ฝ๊ฒŒ ๋งํ•ด, ์ŠคํŠธ๋ฆผ์—์„œ ํ•„ํ„ฐ ๋“ฑ์— ๋”ฐ๋ผ ๋ณ€ํ™” ๋œ ๋ฐ์ดํ„ฐ ๋ชจ์Œ์„ ๊ฐ์ฒด๋กœ ๋‹ด์•„์„œ ์ „๋‹ฌ์„ ํ•ด์ฃผ๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ์„ ํ•จ.