스트림의 연산에 대해 알아보겠습니다.
프로젝트를 진행할 때, for 문과 같은 코드를 Stream 으로 리팩토링을 했는데, 자바의 정석 강의를 통해 다시 한번 정리해보고자 합니다.
자바8 이후 Stream 을 사용할 수 있게 되면서, 길고 복잡했던 코드를 단순하고 가독성 좋게 사용할 수 있기 때문에,
낯설더라도 프로젝트에 적용하면 빠르게 배울 수 있을 거 같습니다.
먼저 어떠한 종류가 있는지 확인해보겠습니다. 기본적인 메서드만 정리했으며, 많은 메서드가 있습니다.
중간 연산은 0~n 개를 사용할 수 있습니다.
중간 연산 | 설명 |
Stream<T> distinct() | 종복제거 |
Stream<T> filter( 조건식 ) | 조건에 안맞는 요소는 제외 |
Stream<T> limit() | 스트림의 일부를 잘라내기 |
Stream<T> skip() | 스트림의 일부를 건너뛰기 |
Stream<T> sortd() | 스트림의 요소 정렬 |
Stream<T> map() | 스트림의 요소를 변환 |
최종연산의 메서드를 알아보겠습니다. 최종연산은 1개만 사용가능합니다.
최종연산 | 설명 |
void forEach() | 각 요소에 지정된 작업 수행 |
long count() | 스트림의 요소의 개수 반환 |
Optional<T> max() Optional<T> min() |
스트림의 최댓값 반환 스트림의 최솟값 반환 |
Optional<T> findAny() Optional<T> findFirst() |
스트림 요소를 하나 반환 (아무거나 하나) 스트림 요소를 하나 반환 (첫번째 요소) |
boolean allMatch(Predicate<T> p) boolean anyMatch(Predicate<T> p) boolean noneMatch(Predicate<T> p) |
요소를 만족시키는지 확인 (모두 만족) 요소를 만족시키는지 확인 (하나라도 만족) 요소를 만족시키는지 확인 (모두 만족X) |
Object[ ] toArray() | 스트림의 모든 요소를 배열로 반환 |
Optional<T> reduce | 스트림의 요소를 하나씩 줄여가면서 계산 |
R collect | 스트림의 요소 수집 |
skip() 과 limit() 의 예제입니다.
3개를 건너뛰고 5개를 출력합니다.
IntStream intStream = IntStream.rangeClosed(1, 10); // 1 ~ 10
intStream.skip(3).limit(5).forEach(System.out::print);
// 결과값
45678
distinct() 와 filter() 의 예제입니다.
distinct() 는 중복을 제거하고 filter() 는 괄호 안에 있는 조건에 맞는 요소를 필터링합니다.
IntStream intStream = IntStream.of(1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 7);
intStream.distinct().forEach(System.out::print);
// 결과값
1 2 3 4 5 6 7
IntStream intStream = IntStream.rangeClosed(1, 10); // 1 ~ 10
intStream.filter(i -> i % 2 == 0).forEach(System.out::print);
// 결과값
2 4 6 8 10
IntStream intStream = IntStream.rangeClosed(1, 10); // 1 ~ 10
intStream.filter(i -> i % 2 == 0).filter(i -> i % 3 == 0).forEach(System.out::print);
// 결과값
6
sorted() 의 예제입니다. 괄호안에 정렬기준을 설정할 수 있습니다.
Stream<String> strStream = Stream.of("dd", "aa", "bc", "bb");
strStream.sorted((o1, o2) -> o1.compareTo(o2)).forEach(System.out::print);
// 결과값
aabbbcdd
Stream<String> strStream = Stream.of("dd", "aa", "bc", "bb");
strStream.sorted((o1, o2) -> o2.compareTo(o1)).forEach(System.out::print);
//strStream.sorted(Comparator.reverseOrder()).forEach(System.out::print);
// 결과값
ddbcbbaa
map() 을 사용하는 예제입니다. File 타입의 객체를 String 타입으로 변환할 수 있습니다.
File[] fileArr = {new File("Ex1.java"),
new File("Ex1.bak"),
new File("Ex2.java"),
new File("Ex1"),
new File("Ex1.txt")};
Stream<File> fileStream = Stream.of(fileArr);
// map() 으로 Stream<File> 을 Stream<String> 으로 변환
Stream<String> filenameStream = fileStream.map(f -> f.getName());
filenameStream.forEach(System.out::println);
//결과값
Ex1.java
Ex1.bak
Ex2.java
Ex1
Ex1.txt
최종연산 (1번만 사용가능) 에 대해 알아보겠습니다.
먼저 가장 기본적인 forEach() 입니다. 루프를 들면서 출력합니다.
IntStream.range(1,10).forEach(System.out::print);
IntStream.range(1,10).parallel().forEach(System.out::print); // 병렬 처리 -> 순서보장X
IntStream.range(1,10).parallel().forEachOrdered(System.out::print); // 병렬 처리 시 순서보장
//결과값
123456789
657948213
123456789
anyMatch() 입니다. 괄호안에는 조건식이 들어가며, 아래는 100 점 이하의 학생이 있는지 확인하는 예제입니다.
boolean hasFailedStu = studentStream.anyMatch( s-> s.getTotalScore() <= 100);
// 결과값
존재하면 true
findFirst() 와 findAny() 의 사용예제입니다. filter 조건이랑 같이 사용됩니다.
findFirst 는 앞에서부터 하나씩 조회하며 필터조건에 의해 찾으면 그 값을 반환(첫번째 요소) 합니다.
값이 없을 수도 있기 때문에 Optional 입니다.
findAny() 는 병렬처리 시 사용합니다.
필터조건에 맞는 값을 반환하며, 병렬 처리 시 나누어 찾기 때문에 Any를 사용합니다.
값은 먼저 찾는 값을 반환합니다.
Optional<Student> result = studentStream.filter( s-> s.getTotalScore() <= 100).findFirst();
Optional<Student> result = paralleStream.filter( s-> s.getTotalScore() <= 100).findAny();
reduce() 는 요소를 하나씩 줄여가며 누적연산을 수행합니다.
Optional<T> reduce (BinaryOperator<T> accumulator) : 초기값이 없으니 null 이 반환 될 수 있습니다.
T reduce(T identity, BinaryOperator<T> accumulator) : 초기값을 설정하며, 실행되지 않으면 초기값을 반환합니다.
초기값을 설정해주고, 실행할 연산을 적어줍니다.
int count = intStream.reduce(0, (a,b) -> a+1); //count
int sum = intStream.reduce(0, (a,b) -> a+b); //sum
int max = intStream.reduce(Integer.MIN_VALUE, (a,b) -> a > b ? a : b); //max
int min = intStream.reduce(Integer.MAX_VALUE, (a,b) -> a < b ? a : b); //min
sum 의 코드는 풀어서 작성하면 아래와 같습니다.
int a = identity;
for(int b : stream)
a = a + b;
최종연산 reduce() 의 예제를 총 예제로 알아보겠습니다.
String[] strArr = {"aaa", "bbbb", "cc", "dd", "e"};
IntStream intStream1 = Stream.of(strArr).mapToInt(String::length);
IntStream intStream2 = Stream.of(strArr).mapToInt(String::length);
IntStream intStream3 = Stream.of(strArr).mapToInt(String::length);
IntStream intStream4 = Stream.of(strArr).mapToInt(String::length);
int count = intStream1.reduce(0, (a, b) -> a + 1);
int sum = intStream2.reduce(0, (a, b) -> a + b);
OptionalInt max = intStream3.reduce(Math::max);
OptionalInt min = intStream4.reduce(Math::min);
System.out.println("count = " + count);
System.out.println("sum = " + sum);
System.out.println("max = " + max.getAsInt());
System.out.println("min = " + min.getAsInt());
//결과값
count = 5
sum = 12
max = 4
min = 1
collect() 는 그룹별로 리듀싱할때 사용합니다.
Object collect(Collerctor collector)
List<String> names = studentStream.map(Student::getName).collect(Collectors.toList());
ArrayList<String> list = names.stream().collect(Collectors.toCollection(ArrayList::new));
Map<String,Person> map = personStream.collect(Collectors.toMap(p->p.getRegId(), p->p));
'Language > JAVA' 카테고리의 다른 글
[JAVA] 깊은 복사 vs 얕은 복사 (0) | 2023.08.20 |
---|---|
Optional + orElse 와 orElseGet 메서드 비교 테스트 (0) | 2023.08.15 |
스트림(Stream) 의 특징 (0) | 2023.02.13 |
람다식과 함수형 인터페이스 (0) | 2023.02.13 |
쓰레드 동기화(Synchronization) (0) | 2023.02.13 |
댓글