일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
Tags
- gpt
- 딥러닝
- LG Aimers 4th
- Machine Learning
- GPT-4
- 지도학습
- AI
- 머신러닝
- LG Aimers
- 티스토리챌린지
- PCA
- LG
- ChatGPT
- 회귀
- 분류
- LLM
- 오블완
- OpenAI
- 해커톤
- deep learning
- supervised learning
- regression
- Classification
Archives
- Today
- Total
SYDev
[이것이 자바다] Chapter 17. 스트림 요소 처리 본문
1. 스트림이란?
- Java 8부터 컬렉션 및 배열의 요소를 반복 처리하기 위해 스트림 사용 가능
- List 컬렉션의 stream() method로 Stream 객체를 얻고, forEach() method로 요소를 어떻게 처리할지를 람다식으로 제공
- Iterator와 차이점
- 내부 반복자이므로, 처리 속도가 빠르고 병렬 처리에 효율적
- 람다식으로 다양한 요소 처리를 정의 가능
- 중간 처리와 최종 처리를 수행하도록 파이프 라인 형성 가능
Stream<String> stream = list.stream();
stream.forEach( item -> item 처리 );
- 예제
package ch17.sec1.exam1;
import java.util.*;
import java.util.stream.Stream;
public class StreamExample {
public static void main(String[] args) {
// Set collection 생성
Set<String> set = new HashSet<>();
set.add("홍길동");
set.add("신용권");
set.add("감자바");
// stream을 이용한 요소 반복 처리
Stream<String> stream = set.stream();
stream.forEach( name -> System.out.println(name));
}
}
2. 내부 반복자
- 외부 반복자: 요소를 collection 바깥쪽으로 반복해서 가져와 처리 - for 문, Iterator
- collection의 요소를 외부로 가져오는 코드, 처리하는 코드를 모두 개발자 코드가 가지고 있어야 함
- 요소를 하나씩 순차적으로 처리
- 내부 반복자: 요소 처리 방법을 collection 내부로 주입시켜, 요소를 반복 처리 - stream
- 개발자 코드에서 제공한 데이터 처리 코드(람다식)를 가지고 컬렉션 내부에서 요소를 반복 처리
- 요소들을 분배시켜 병렬 작업 -> 멀티 코어 CPU를 최대한 활용
- 예제
package ch17.sec2;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class ParallelStreamExample {
public static void main(String[] args) {
// List Collection 생성
List<String> list = new ArrayList<>();
list.add("name1");
list.add("name2");
list.add("name3");
list.add("name4");
list.add("name5");
// 병렬 처리
Stream<String> parallelStream = list.parallelStream(); // 병렬 스트림 얻기
parallelStream.forEach( name -> {
System.out.println(name + ": " + Thread.currentThread().getName());
} );
}
}
3. 중간 처리와 최종 처리
- stream은 하나 이상 연결될 수 있고, 이를 Stream Pipelines라 부름
- 오리지널 스트림과 집계 처리 사이의 중간 스트림들은 최종 처리를 위해 요소를 걸러내거나(필터링), 요소를 변환시키거나(매핑), 정렬하는 작업을 수행
- 최종 처리는 중간 처리에서 정제된 요소들을 반복하거나, 집계(카운팅, 총합, 평균) 작업을 수행
- mapToInt(): 객체를 int 값으로 매핑해서, IntStream으로 변환
- 어떤 객체를 어떤 int 값으로 매핑할 것인지는 람다식으로 제공
- IntStream.average(): 요소들의 평균 값 계산
// Student Stream
Stream<Student> studentStream = list.stream();
// score Stream
IntStream scoreStream = studentStream.mapToInt( student -> student.getScore() );
// average
double avg = scoreStream.average().getAsDouble();
- 메소드 체이닝 패턴을 이용하여 간결화 가능
- 스트림 파이프라인으로 구성할 때, 파이프라인의 맨 끝에는 반드시 최종 처리 부분이 존재해야 함
doube avg = list.stream()
.mapToInt(student -> student.getScore())
.average()
.getAsDouble();
- 예제
package ch17.sec3;
public class Student {
private String name;
private int score;
public Student (String name, int score) {
this.name = name;
this.score = score;
}
public String getName() { return name; }
public int getScore() { return score; }
}
package ch17.sec3;
import java.util.Arrays;
import java.util.List;
public class StreamPipeLineExample {
public static void main(String[] args) {
List<Student> list = Arrays.asList(
new Student("name1", 10),
new Student("name2", 20),
new Student("name3", 30)
);
double avg = list.stream()
.mapToInt( student -> student.getScore())
.average()
.getAsDouble();
System.out.println(avg);
}
}
4. 리소스로부터 스트림 얻기
4.1. 컬렉션으로부터 스트림 얻기
- java.util.Collection interface는 stream과 parallelStream() method를 가짐 -> 자식 인터페이스인 List와 Set 인터페이스를 구현한 모든 Collection에서 객체 스트림을 얻을 수 있음
- 예제
package ch17.sec4.exam1;
public class Product {
private int pno;
private String name;
private String company;
private int price;
public Product(int pno, String name, String company, int price) {
this.pno = pno;
this.name = name;
this.company = company;
this.price = price;
}
public int getPno() { return pno; }
public String getName() { return name; }
public String getCompany() { return company; }
public int getPrice() { return price; }
@Override
public String toString() {
return new StringBuilder()
.append("{")
.append("pno: " + pno + ", ")
.append("name: " + name + ", ")
.append("company: " + company + ", ")
.append("price: " + price + ", ")
.append("}")
.toString();
}
}
package ch17.sec4.exam1;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class StreamExample {
public static void main(String[] args) {
// List collection 생성
List<Product> list = new ArrayList<>();
for(int i = 1; i <= 5; i++) {
Product product = new Product(i, "상품" + i, "멋진 회사 ", (int)(10000 * Math.random()));
list.add(product);
}
// 객체 스트림 얻기
Stream<Product> stream = list.stream();
stream.forEach(p -> System.out.println(p));
}
}
4.2. 배열로부터 스트림 얻기
- java.util.Arrays 클래스를 이용하면 다양한 종류의 배열로부터 스트림을 얻을 수 있음
- 예제
package ch17.sec4.exam2;
import java.util.Arrays;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class StreamExample {
public static void main(String[] args) {
String[] strArray = { "name1", "name2", "name3" };
Stream<String> strStream = Arrays.stream(strArray);
strStream.forEach(item -> System.out.print(item + ","));
System.out.println();
int[] intArray = { 1, 2, 3, 4, 5 };
IntStream intStream = Arrays.stream(intArray);
intStream.forEach(item -> System.out.print(item + ","));
System.out.println();
}
}
4.3. 숫자 범위로부터 스트림 얻기
- IntStream 혹은 LongStream의 static method인 range()와 rangeClosed() method -> 특정 범위의 정수 스트림을 얻을 수 있음
- 끝 수를 포함하면 range(), 포함하지 않으면 rangeClosed()
package ch17.sec4.exam3;
import java.util.stream.IntStream;
public class StreamExample {
public static int sum;
public static void main(String[] args) {
IntStream stream = IntStream.rangeClosed(1, 100);
stream.forEach(a -> sum += a);
System.out.println("sum: " + sum);
}
}
4.4. 파일로부터 스트림 얻기
- java.nio.file.Files의 lines() method-> 텍스트 파일의 행 단위 스트림을 얻을 수 있음
- 예제
package ch17.sec4.exam4;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;
public class StreamExample {
public static void main(String[] args) throws Exception {
Path path = Paths.get(StreamExample.class.getResource("data.txt").toURI());
Stream<String> stream = Files.lines(path, Charset.defaultCharset());
stream.forEach(line -> System.out.println(line));
stream.close();
}
}
5. 요소 걸러내기(필터링)
- distinct(): 요소의 중복 제거
- 객체 스트림(Stream)일 경우, equals() method의 리턴값이 true이면 동일한 요소로 판단
- IntStream, LongStream, DoubleStream일 경우, 값은 값이면 중복 제거
- filter(): 매개값으로 주어진 Predicate가 true를 리턴하는 요소만 필터링
- Predicate: 함수형 인터페이스로, 매개값을 조사한 후 boolean을 리턴하는 test() method를 가짐
Predicate<T>를 람다식으로 표현하면 아래와 같음
T -> { ... return true }
T -> true; // return 문만 있을 경우, 중괄호와 return 키워드 생략 가능
package ch17.sec5;
import java.util.List;
import java.util.ArrayList;
public class FilteringExample {
public static void main(String[] args) {
// List Collection 생성
List<String> list = new ArrayList<>();
list.add("name1"); list.add("name2");
list.add("name3"); list.add("name2"); list.add("name5");
list.add("name3"); list.add("name23");
// 중복 요소 제거
list.stream()
.distinct()
.forEach(n -> System.out.println(n));
System.out.println();
// 3으로 끝나는 요소만 필터링
list.stream()
.filter(n -> n.endsWith("3"))
.forEach(n -> System.out.println(n));
System.out.println();
// 중복 요소를 먼저 제거하고, 3으로 끝나는 요소만 필터링
list.stream()
.distinct()
.filter(n -> n.endsWith("3"))
.forEach(n -> System.out.println(n));
}
}
6. 요소 변환(매핑)
- mapping: 스트림의 요소를 다른 요소로 변환하는 중간 처리 기능
- mapXxx(), asDoubleStream(), asLongStream(), boxed(), flatMapXxx(), ...
6.1. 요소를 다른 요소로 변환
- mapXxx(): 요소를 다른 요소로 변환한 새로운 스트림을 리턴
- 매개타입인 Function은 함수형 인터페이스로, 다음과 같은 종류가 존재
- applyXxx(): 매개값을 리턴값으로 매핑(변환)
T -> { ... return R; }
T -> R; // return 문만 있을 경우, 중괄호와 return 키워드 생략 가능
- 예제
package ch17.sec6.exam1;
public class Student {
private String name;
private int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
public String getName() { return name; }
public int getScore() { return score; }
}
package ch17.sec6.exam1;
import java.util.List;
import java.util.ArrayList;
public class MapExample {
public static void main(String[] args) {
// List collection 생성
List<Student> studentList = new ArrayList<>();
studentList.add(new Student("name1", 85));
studentList.add(new Student("name1", 92));
studentList.add(new Student("name1", 87));
// Student를 score 스트림으로 변환
studentList.stream()
.mapToInt(s -> s.getScore())
.forEach(score -> System.out.println(score));
}
}
기본 타입 간의 변환이거나, 기본 타입 요소를 Wrapper 객체 요소로 변화하려면 다음 간편화 메소드 사용
6.2. 요소를 복수 개의 요소로 변환
- flatMapXxx(): 하나의 요소를 복수 개의 요소들로 변환한 새로운 스트림 리턴
- 예제
package ch17.sec6.exam3;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class FlatMappingExample {
public static void main(String[] args) {
// 문장 스트림을 단어 스트림으로 변환
List<String> list1 = new ArrayList<>();
list1.add("this is java");
list1.add("i am a best developer");
list1.stream().
flatMap(data -> Arrays.stream(data.split(" ")))
.forEach(word -> System.out.println(word));
System.out.println();
// 문자열 숫자 목록 스트림을 숫자 스트림으로 변환
List<String> list2 = Arrays.asList("10, 20, 30", "40, 50");
list2.stream()
.flatMapToInt(data -> {
String[] strArr = data.split(",");
int[] intArr = new int[strArr.length];
for(int i = 0; i < strArr.length; i++) {
intArr[i] = Integer.parseInt(strArr[i].trim());
}
return Arrays.stream(intArr);
})
.forEach(number -> System.out.println(number));
}
}
7. 요소 정렬
7.1. Comparable 구현 객체의 정렬
- 스트림의 요소가 객체일 경우, 객체가 Comparable을 구현한 상태여야 sorted() method를 사용하여 정렬이 가능
- 그렇지 않다면 ClassCastException 발생
- 내림차순으로 정렬하고 싶은 경우, Comparator.reverseOrder() method가 리턴하는 Comparator를 매개값으로 제공
Stream<Xxx> reverseOrderedStream = stream.sorted(Comparator.reverseOrder());
- 예제
package ch17.sec7.exam1;
import java.util.List;
import java.util.ArrayList;
import java.util.Comparator;
public class SortingExample {
public static void main(String[] args) {
// List collection 생성
List<Student> studentList = new ArrayList<>();
studentList.add(new Student("name1", 30));
studentList.add(new Student("name2", 10));
studentList.add(new Student("name3", 20));
// 점수를 기준으로 오름차순으로 정렬한 새 스트림 얻기
studentList.stream()
.sorted()
.forEach(s -> System.out.println(s.getName() + ": " + s.getScore()));
System.out.println();
// 점수를 기준으로 내림차순으로 정렬한 새 스트림 얻기
studentList.stream()
.sorted(Comparator.reverseOrder())
.forEach(s -> System.out.println(s.getName() + ": " + s.getScore()));
}
}
7.2. Comparator를 이용한 정렬
- 요소 객체가 Comparable을 구현하고 있지 않다면, 비교자를 제공하면 요소 정렬 가능
- 비교자: Comparator interface를 구현한 객체
sorted((o1, o2) -> { ... })
- 예제
package ch17.sec7.exam2;
public class Student {
private String name;
private int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
public String getName() { return name; }
public int getScore() { return score; }
}
package ch17.sec7.exam2;
import java.util.List;
import java.util.ArrayList;
public class SortingExample {
public static void main(String[] args) {
// List collection 생성
List<Student> studentList = new ArrayList<>();
studentList.add(new Student("name1", 30));
studentList.add(new Student("name2", 10));
studentList.add(new Student("name3", 20));
// 점수 기준 오름차순 새 스트림 얻기
studentList.stream()
.sorted((s1, s2) -> Integer.compare(s1.getScore(), s2.getScore()))
.forEach(s -> System.out.println(s.getName() + ": " + s.getScore()));
System.out.println();
// 점수 기준 오름차순 새 스트림 얻기
studentList.stream()
.sorted((s1, s2) -> Integer.compare(s2.getScore(), s1.getScore()))
.forEach(s -> System.out.println(s.getName() + ": " + s.getScore()));
}
}
8. 요소를 하나씩 처리(루핑)
- looping: 스트림에서 요소를 하나씩 반복해서 가져와 처리하는 것
- looping methods peek(), forEach()
- peek(): 중간 처리 메소드, 최종 처리가 뒤에 붙지 않으면 동작 X
- forEach(): 최종 처리 메소드
- 매개타입 Consumer는 함수형 인터페이스로, 아래와 같은 종류 존재
- accept(): 매개값을 처리(소비)
T -> { ... }
T -> 실행문; // 하나의 실행문만 있을 경우 중괄호 생략
- 예제
package ch17.sec8;
import java.util.Arrays;
public class LoopingExample {
public static void main(String[] args) {
int[] intArr = { 1, 2, 3, 4, 5 };
// 잘못 작성한 경우
Arrays.stream(intArr)
.filter(a -> a % 2 == 0)
.peek(n -> System.out.println(n)); // 최종 처리가 없으므로 동작 X
// 중간 처리 메소드 peek()을 이용하여 반복 처리
int total = Arrays.stream(intArr)
.filter(a -> a % 2 == 0)
.peek(n -> System.out.println(n))
.sum(); // 최종 처리
System.out.println("sum: " + total);
// 최종 처리 메소드 forEach()를 이용해서 반복 처리
Arrays.stream(intArr)
.filter(a -> a % 2 == 0)
.forEach(n -> System.out.println((n))); // 최종 처리이므로 동작함
}
}
9. 요소 조건 만족 여부(매칭)
- Matching: 요소들이 특정 조건에 만족하는지 여부를 조사하는 최종 처리 기능
10. 요소 기본 집계
- Aggregate: 최종 처리 기능으로, 요소들을 처리해서 카운팅, 합계, 평균값, 최대값, 최소값 등과 같이 하나의 값으로 산출하는 것
- 대량의 데이터를 가공해서 하나의 값으로 축소하는 reduction
10.1. 스트림이 제공하는 기본 집계
long count = Arrays.stream(arr)
.filter(n -> n % 2 == 0)
.average()
.getAsDouble();
10.2. Optional 클래스
- Optional, OptionalDouble, OptionalInt, OptionalLong 클래스는 단순히 집계값만 저장하는 것이 아니라, 집계값이 존재하지 않을 경우 디폴트 값을 설정하거나 집계값을 처리하는 Consumer를 등록 가능
- 컬렉션에 요소가 존재하지 않으면 집계 값을 산출할 수 없으므로 NoSuchElementException 예외 발생
- 예외 발생을 막는 3가지 방법
1) isPresent() method가 true를 리턴할 때만 집계값을 얻는다.
OptionalDouble optional = stream
.average();
if(optional.isPresent()) {
System.out.println("평균: " + optional.getAsDouble());
} else {
System.out.println("평균: 0.0");
}
2) orElse() method로 집계값이 없을 경우를 대비해서 디폴트 값을 정해놓는다.
double avg = stream
.average()
.orElse(0.0);
System.out.println("평균: " + avg);
3) ifPresent() method로 집계값이 있을 경우에만 동작하는 Consumer 람다식을 제공
stream
.average()
.ifPresent(a -> System.out.println("평균: " + a));
11. 요소 커스텀 집계
- 스트림은 기본 집계 메소드인 sum(), average(), count(), max(), min()을 제공하지만, 다양한 집계 결과물을 만들 수 있도록 reduce() method도 제공
- 매개값인 BinaryOperator()는 함수형 인터페이스
- apply(): 두 개의 매개값을 받아 하나의 값을 리턴
(a, b) -> { ... return 값 }
(a, b) -> 값 // return 문만 있을 경우 중괄호와 return 키워드 생략 가능
- reduce()는 스트림에 요소가 없을 경우 예외 발생, but identity 매개값이 주어지면 이 값을 디폴트로 리턴
int sum1 = studentList.stream()
.mapToInt(Student :: getScore)
.reduce(0, (a, b) -> a + b); // .sum()과 동일
12. 요소 수집
- collect(): 요소들을 필터링 또는 매핑한 후 요소들을 수집하는 최종 처리 메소드
- 필요한 요소만 collection에 담을 수 있고, 요소들을 grouping한 후에 집계도 가능
12.1. 필터링한 요소 수집
- Stream의 collect(Collector<T, A, R> collector) method: 필터링 또는 매핑된 요소들을 새로운 컬렉션에 수집하고, 이 컬렉션을 리턴
- Collector: 어떤 요소를 어떤 컬렉션에 수집할 것인지 결정
- T: 요소
- A: 누적기(accumulator)
- R: 요소가 저장될 collection
- T 요소를 A 누적기가 R에 저장
- Collector의 구현 객체는 다음과 같이, Collectors class의 static method로 얻을 수 있음
- A(누적기)가 ?로 설정된 경우 -> Collector가 List, Set, Map collection에 요소를 저장하는 방법을 알고 있어 별도의 누적기 필요 X
List<Student> maleList = totalList.stream()
.filter(s -> s.getSex().equals("남"))
.collect(Collectors.toList());
Map<String, Integer> map = totalList.stream()
.collect(
Collectors.toMap(
s -> s.getName(), // Student 객체에서 키가 될 부분 리턴
s -> s.getScore() // Student 객체에서 값이 될 부분 리턴
)
);
Java 16부터는 좀 더 편리하게 요소 스트림에서 List collection을 얻을 수 있음 -> Stream의 toList() method
List<Student> maleList = totalList.stream()
.filter(s -> s.getSex().equals("남"))
.toList();
12.2. 요소 그룹핑
- collect() method 요소들을 그룹핑해서 Map 객체를 생성하는 기능 제공 -> Collectors.groupingBy() method에서 얻은 Collector를 collect() method를 호출할 때 제공
- T를 K로 매핑
- K를 키로 해 List<T> 값으로 갖는 Map Collection 생성
Map<String, List<Student>> map = totalList.stream()
.collect(
Collectors.groupingBy(s -> s.getSex()) // grouping key return
);
List<Student> maleList = map.get("남");
maleList.stream().forEach(s -> System.out.println(s.getName()));
System.out.println();
List<Student> femaleList = map.get("여");
femaleList.stream().forEach(s -> System.out.println(s.getName()));
- Collectors.groupingBy() method는 grouping 이후 매핑 및 집계(평균, 카운팅, 연결, 최대, 최소, 합계)를 수행할 수 있도록 두 번째 매개값인 Collector를 가질 수 있음
- 다음은 두 번재 매개값으로 사용될 Collectors를 얻을 수 있는 Collectors의 static methods
Map<String, Double> map = totalList.stream()
.collect(
Collectors.groupingBy(
s -> s.getSex(),
Collectors.averagingDouble(s -> getScore())
)
);
System.out.println(map);
13. 요소 병렬 처리
- Parallel Operation: 멀티 코어 CPU 환경에서 전체 요소를 분할해서 각각의 코어가 병렬적으로 처리하는 것
- java는 parallel operation을 위해 parallel stream을 제공
13.1. 동시성과 병렬성
- 동시성(Concurrency): multi-threads가 하나의 core에서 번갈아 가며 실행
- 병렬성(Parallelism): multi-core를 각각 이용해서 병렬로 실행
- 데이터 병렬성: 전체 데이터를 분할해서 서브 데이터셋으로 만들고, 이 서브 데이터셋들을 병렬 처리해서 작업을 빨리 끝내는 것
- 자바 병렬 스트림은 데이터 병렬성을 구현한 것
- 작업 병렬성: 서로 다른 작업을 병렬 처리
13.2. 포크조인 프레임워크
- 자바 병렬 스트림은 요소들을 병렬처리하기 위해 ForkJoin Framework를 사용
- ForkJoin Framework
- 포크 단계에서 전체 요소들을 서브 요소셋으로 분할
- 각각의 서브 요소셋을 멀티 코어에서 병렬로 처리
- 조인 단계에서 서브 결과를 결합해서, 최종 결과를 만들어냄
- ForkJoin Framework는 병렬 처리를 위해 ThreadPool을 사용
- 각각의 코어에서 서브 요소셋을 처리하는 것은 worker thread이므로, thread 관리가 필요
- ForkJoin Framework는 Executor의 구현 객체인 ForkJoinPool을 사용하여 worker thread 관리
13.3. 병렬 스트림 사용
- parallelStream(): collection(List, Set)을부터 병렬 스트림을 바로 리턴
- parallel(): 기존 스트림을 병렬 처리 스트림으로 변환
- 예제
package ch17.sec13;
import java.util.*;
import java.util.stream.Stream;
public class ParallelExample {
public static void main(String[] args) {
Random random = new Random();
// 1억 개의 Integer 객체 저
List<Integer> scores = new ArrayList<>();
for(int i = 0; i < 100000000; i++) {
scores.add(random.nextInt(101));
}
double avg = 0.0;
long startTime = 0;
long endTime = 0;
long time = 0;
// 일반 스트림으로 처
Stream<Integer> stream = scores.stream();
startTime = System.nanoTime();
avg = stream
.mapToInt(i -> i.intValue())
.average()
.getAsDouble();
endTime = System.nanoTime();
time = endTime - startTime;
System.out.println("avg: " + avg + ", 일반 스트림 처리 시간: " + time + "ns");
Stream<Integer> parallelStream = scores.parallelStream();
startTime = System.nanoTime();
avg = parallelStream
.mapToInt(i -> i.intValue())
.average()
.getAsDouble();
endTime = System.nanoTime();
time = endTime - startTime;
System.out.println("avg: " + avg + ", 일반 스트림 처리 시간: " + time + "ns");
}
}
13.4. 병렬 처리 성능
병렬 처리에 영향을 미치는 3가지 요인
1) 요소의 수와 요소당 처리 시간
- 컬렉션에 전체 요소의 수가 적고, 요소당 처리 시간이 짧으면 일반 스트림이 병렬 스트림보다 빠를 수 있음
- 병렬 처리는 포크 및 조인 단계 존재하고, threadPool을 생성하는 추가적 비용 발생하기 때문
2) 스트림 소스의 종류
- ArrayList와 배열: index로 요소를 관리하기 때문에, 포크 단계에서 요소를 쉽게 분리할 수 있어 병렬 처리 시간이 절약
- HashSet, TreeSet, LinkedList: 요소 분리가 쉽지 않아, 상대적으로 병렬 처리가 늦음
3) 코어의 수
- CPU core의 수가 많을수록 병렬 스트림의 성능은 좋아짐
- CPU core의 수가 적을 경우, 일반 스트림이 더 빠를 수 있음
- 병렬 스트림은 threads 수가 증가 -> 동시성(concurrency)이 많이 일어나므로, 오히려 느려짐
참고자료
'Programming Lang > Java' 카테고리의 다른 글
[이것이 자바다] Chapter 19. 네트워크 입출력 (0) | 2025.02.07 |
---|---|
[이것이 자바다] Chapter 18. 데이터 입출력 (0) | 2025.02.06 |
[이것이 자바다] Chapter 16. 람다식 (2) | 2025.02.02 |
[이것이 자바다] Chapter 15. 컬렉션 자료구조 (0) | 2025.02.02 |
[이것이 자바다] Chapter 14. 멀티 스레드 (1) | 2025.02.01 |