티스토리 뷰

 

 


스트림을 배우기 전에 function 패키지도 같이 배워
 보기 위해서 작성하게 되었다.

어떻게 사용하는지를 배우고 나서 실제 예시 코드 순서로 공부하도록 하자!

 

 

 

function 패키지: 함수형 프로그래밍의 활용

 

JAVA API인 java.util.function 패키지는 이후에 함수형 프로그래밍을 하기 위해서 도입된 함수형 인터페이스입니다.


앞으로 배울 것들을 앞서 미리 배워야 하는 함수형 인터페이스입니다.

이렇게 알아두시면 좋습니다.


이건 인터페이스이므로 이 자리에는 내용물있는 함수(=구현체)가 와서 뭘 실행하겠구나라고 생각해 주세요! 

 

함수형  인터페이스 메서드 설 명
Runnable [  void run()  ]  매개변수도 없고, 반환 값도 없다.
Supplier<T> [  T get()  ] → T 매개변수는 없고, 반환 값만 있다.
Consumer<T> T  →  [  void accept(T t)  ] 매개변수만 있고, 반환 값은 없다.
Function<T, R> T  → [  R apply(T t)  ]  →  R  일반적인 함수이다.
하나의 매개변수를 받아서 결과를 반환한다.
Predicate<T> T  →  [  boolean test(T t)  ]  →  boolean 조건식을 표현하는데 사용된다.
매개변수는 하나이고 반환 타입은 Boolean 값이다.

마동석님
팡팡 터지는 마동석님

 

 

 

 

 

스트림 (Stream)

 

스트림이란 자바 8 (= JAVA 1.8)부터 도입된 기능으로 컬렉션(List, Set, Map)과 배열 등의
다양한 데이터를 다루는 연산을 간단하고 효율적으로 처리할 수 있게 하는 기능입니다.

 

예를 들어 List를 정렬 할 때 Collections.sort()를 사용했던 것을 스트림은 데이터를 추상화하고, 정렬하게 합니다.
즉, 스트림은 데이터를 다루는데 자주 사용되는 메서드를 정의해 놓아서 문제점을 해결한 기능입니다.

 

 

 

스트림 적용 전

 

List<String> strList = Arrays.asList(new String[]{"aa", "bb", "cc"});
for(String str : strList) {
    if(str.length() < 5) {
        System.out.println(str);
    }
}
// 출력
// aa
// bb
// cc

 

 

 

 

스트림 적용 후

 

List<String> strList = Arrays.asList(new String[]{"aa", "bb", "cc"});
strList.stream().filter(str -> str.length() < 5).forEach(System.out::println);

// 출력
// aa
// bb
// cc

놀랜 고양이
놀랜 고양이

 

 

뭔가가 3,4줄로 작성하던 것이 한 줄로 끝냈다고? 
연산된 데이터를 if으로 쓰고 또 가공하고를 스트림으로 한 번에 처리할 수 있다니 되게 좋아졌네요~!
하.지.만 스트림을 쓴다해서 성능이 좋아지는 것은 아닌 것을 꼭 기억해 주시고 가독성을 향상시키기 위해 사용한다는 것을 인지해 주세요!

 

 

 

 

 

스트림의 특징

 

1. 원본 데이터 소스를 변경을 안 한다고?

스트림은 데이터 소스로 부터 데이터를 읽기만 할 뿐. 원래 데이터 소스를 변경하지 않는다는 차이가 있습니다.

즉, 변경된 값(= 정렬된 값) sortedList와 원본데이터 strStream은 다릅니다.
왜냐하면! strStream에 있는 데이터는 변경되지 않았기 때문입니다.

// String을 담은 리스트를 스트림을 만든 strStream이 있다고 하자
List<String> sortedList = strStream.sorted().collect(Collectors.toList());

sortedList.stream() != strStream

 

 

2. 1회용이라구?

스트림은 Iterator처럼 일회용으로 사용합니다. 스트림을 한번 사용하면 닫혀서 다시 사용할 수 없게 됩니다.

// String을 담은 리스트를 스트림을 만든 strStream이 있다고 하자
strStream.sorted().forEach(System.out::println);	// 반복문을 이용해서 스트림을 이미 출력!
int numOfStr = strStream.count();		                 // Error! 스트림이 닫혔다!

 

 

3. 최종 연산 하기 전까지는 중간연산이 수행되질 않아!

중간연산을 수행하면서 데이터를 변환하고 최종 연산을 바로 주는 것이 아닌 지연된 연산으로 최종 연산 때 중간 연산이 수행한다.

 

 

4. 기본형 스트림을 사용하자

오토박싱&언박싱의 비효율을 제거하기 위해 Stream<Integer>보다는 IntStream을 사용한다.
LongStream, DoubleStream도 포함이 된다.

 

 

 

 

 

스트림의 연산 구조

 

Tip) Collection에 Stream이 정의되어 있어서 스트림은 컬렉션을 소스로 한 것으로 생성합니다.!

 

 

중간 연산 : 연산 결과가 스트림인 연산이다. 스트림에 연속해서 중간 연산할 수 있다.

최종 연산 : 연산 결과가 스트림이 아닌 연산이다. 스트림의 요소를 소모하므로 단 한 번만 가능하다.

 

 

 

 

 

중간 연산 목록

 

중간 연산 설명
Stream<T> distinct() 중복을 제거한다.
Stream<T> filter(Predicate<T> predicate) 조건에 안맞는 요소는 제외한다.
Stream<T> limit(long maxSize) 스트림의 일부를 잘라낸다.
Stream<T> skip(long n) 스트림의 일부를 건너뛴다.
Stream<T> peek(Consumer<T> action) 스트림의 요소에 작업을 수행한다. (스트림 내용 변경x)
보통 디버깅이나 로깅정도로 사용됩니다.
Stream<T> sorted(Comparator<T> comparator)  스트림의 요소를 정렬
Stream<R> map(Function<T,R> mapper) 스트림의 요소를 변환한다. (스트림 내용 변경 o)

 

 

 

 

 

 

최종 연산 목록

 

최종 연산 설명
void forEach(Consumer<? super T> action
void forEachOrdered(Consumer<? super T> action)
각 요소에 지정된 작업 수행한다.
long count() 스트림의 요소의 개수 반환한다.
Optional<T> max(Comparator<? super T> comparator)
Optional<T> min(Comparator<? super T> comparator)
스트림의 최대값/최소값을 반환한다.
Optional<T> findAny()
Optional<T> findFirst()
아무거나 하나 반환한다.
첫 번째 요소를 반환한다.
boolean allMatch(Predicate<T> p)
boolean anyMatch(Predicate<T> p)
boolean noneMatch(Predicate<> p)
모두 만족하는지 확인한다.
하나라도 만족하는지 확인한다.
모두 만족하지 않는지 확인한다.
Object[] toArray()
List toList()
Set toSet
스트림의 모든 요소를 배열로 반환한다.
스트림의 모든 요소를 List로 반환한다.
스트림의 모든 요소를 Set로 반환한다.
Optional<T> reduce(BinaryOperator<T> accumulator) 스트림의 요소를 하나씩 줄여가면서 (리듀싱) 계산한다.
R collect(Collector<T,A,R> collector)
ex) collect(Collectors.toSet())
스트림의 요소를 수집한다.

 

 

 

스트림은 앞으로 코딩테스트와 Collection데이터를 정리할 때 자주 사용하게 될 것입니다.

어떻게 사용하는지 그리고 코드를 봤을 때 이해만 할 수 있는 정도면 됩니다!!

 

무야호 아저씨
출저 : 무한도전

 

이제 조금 어려운 부분을 상세하게 배워 볼까요?

그러곤 사용 예시 코드들을 보여주겠습니다!

 

 

 

 

 

 

최종 연산 reduce()

스트림의 요소를 하나씩 줄여가며 누적연산을 수행하는 메서드입니다.

 

 

reduce메서드 구조

T reduce(T identity, BinaryOperator<T> accumulator)
  • identity : 초기값
  • accumulator : 이전 연산 결과와 스트림의 요소에 수행할 연산

 

 

reduce메서드 사용 예시

int count = intStream.reduce(0, (a, b) -> a + 1);		// count()
int sum = intStream.reduce(0, (a, b) -> a + b);			// sum()
/*   sum() 내부 상황
    int a = identity;
    for(int b : stream)
        a = a + b;
*/
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()

 

 

 

 

 

최종 연산 collect()

 

결국에는 스트림의 요소들을 수집하여 원하는 형태로 변환하거나 그룹화하는 데 사용되는 최종 연산입니다.
즉, 스트림의 요소들을 수집하여 컬렉션(List, Set, Map)이나 배열, 그룹화하여 집계된 결과를 얻을 때 유용하게 사용합니다.

 

 

collect 메서드 구조

Object collect(Collector collector)

 

 

Collector 인터페이스에 들어올 것들

 

  • 컬렉션으로 변환 : Collectors.toList(), Collectors.toSet(), Collectors.toMap()
  • 통계 : counting(), summingInt(), averagingInt()
  • 문자열 결합 : joining()
  • 그룹화 분할 : groupingBy(), partitioningBy()

 

 

스트림을 컬렉션으로 변환

Student객체로 이루어진 스트림이 있다고 가정하자!

import java.util.stream.Collectors;
import java.util.stream.Stream;

// ----------------경우 1
// 스트림 -> 리스트로 변환
List<String> names = studentStream.map(Student::getName).collect(Collectors.toList());

// 리스트에서 틀정 컬렉션으로 변환
ArrayList<String> list = names.stream().collect(Collectors.toCollection(ArrayList::new));


// ---------------- 경우 2
// 스트림에서 맵으로 변환
Map<String, Student> map = studentStream.collect(Collectors.toMap(p -> p.getId(), p -> p));

 

 

통계

List<Integer> numbers = List.of(1, 2, 3, 4, 5);

// 요소 개수 ( counting() )
long count = numbers.stream().collect(Collectors.counting());

// 합계 ( summingInt() )
int sum = numbers.stream().collect(Collectors.summingInt(Integer::intValue));

// 평균 ( averagingInt() )
double average = numbers.stream().collect(Collectors.averagingInt(Integer::intValue));

// 통계 요약 정보 ( summarizingInt() )
IntSummaryStatistics stats = numbers.stream()
			.collect(Collectors.summarizingInt(Integer::intValue));

 

 

문자열 결합

String 으로 이루어진 List 컬렉션이 있다고 가정하자

// 문자열 결합
String joined = stringList.stream().collect(Collectors.joining(", "));

 

 

그룹화 분할

// 점수에 따른 학생 그룹화
Map<String, List<Student>> scoreGroup = students.stream()
		.collect(Collectors.groupingBy(student -> student.getScore() >= 90 ? "A" : "B"));


// 점수에 따른 학생 분할
Map<Boolean, List<Student>> passingFailing = students.stream()
		.collect(Collectors.partitioningBy(student -> student.getScore() >= 70));

 

 

 

 

스트림 사용해 보기

 

reduce를 사용하여 문자열을 하나의 문자열로 합치기

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

List<String> words = Arrays.asList("apple", "banana", "orange", "grape", "pear");

Optional<String> combined = words.stream().reduce((result, word) -> result + ", " + word);
                            
combined.ifPresent(System.out::println);

// 출력 (아래로 한개씩 출력)
// apple, banana, orange, grape, pear

 

 

 

 

collect를 사용하여 글자 길이가 5보다 큰 단어를 리스트로 모으기

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

List<String> words = Arrays.asList("apple", "banana", "orange", "grape", "pear");

List<String> longWords = words.stream()
                             .filter(word -> word.length() > 5)     // 중간 연산
                             .collect(Collectors.toList());              // 최종 연산

System.out.println("5글자보다 큰단어 : " + longWords);

// 출력
// 5글자보다 큰단어 : [banana, orange]

 

 

 

 

findAny를 사용하여 글자 길이가 5보다 큰 단어 찾기

import java.util.Arrays;
import java.util.List;
import java.util.Optional;


Optional<String> anyLongWord = words.stream()
                                   .filter(word -> word.length() > 5)       // 중간 연산
                                   .findAny();                      // 최종 연산

anyLongWord.ifPresent(System.out::println);
// 출력
// banana

 

 

 

 

 

allMatch를 사용하여 모든 단어가 글자 길이 3보다 큰지 확인

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

List<String> words = Arrays.asList("apple", "banana", "orange", "grape", "pear");

List<String> longWords = words.stream()
                             .filter(word -> word.length() > 5)       // 중간 연산
                             .collect(Collectors.toList());                // 최종 연산

System.out.println("5글자보다 큰단어 : " + longWords);

// 출력
// 5글자보다 큰단어 : [banana, orange]

 

 

 

 

 

map과 collect를 사용하여 단어 길이 리스트 만들기

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

List<String> words = Arrays.asList("apple", "banana", "orange", "grape", "pear");

List<Integer> wordLengths = words.stream()
                                .map(String::length)                       // 중간 연산
                                .collect(Collectors.toList());           // 최종 연산

System.out.println("Word lengths: " + wordLengths);

// 출력
// Word lengths: [5, 6, 6, 5, 4]

 

 

 

 

스트림의 변환

 

변환에는 어떤 메서드를 써야 하는지 정리해놓은 표입니다.
IntStream만 있는 곳은 Long, Double도 사용할 수 있습니다.

 

From 변환 메서드 To
1. 스트림 → 기본형 스트림
Stream<T> mapToInt (ToIntFunction mapper)
mapToLong (ToLongFunction mapper)
mapToDouble (ToDoubleFunction<T> mapper)
IntStream
LongStream
DoubleStream
2. 기본형 스트림 → 스트림
IntStream
LongStream
DoubleStream
boxed () Stream<Integer>
Stream<Long>
Stream<Double>
3. 기본형 스트림 → 기본형 스트림
IntStream
LongStream
DoubleStream
asLongStream ()
asDoubleStream ()
LongStream
DoubleStream
4. 스트림 → 부분 스트림
Stream<T> skip (long n)
limit (long maxSize)
Stream<T>
5. 두 개의 스트림 → 스트림
Stream<T>, Stream<T> concat(Stream<T> a, Stream<T> b) Stream<T>
IntStream, IntStream concat(IntStream a, IntStream b)  IntStream
6. 스트림 → 병렬 스트림  &  병렬 스트림 → 스트림
Stream<T>
IntStream
parallel()  //  스트림 →  병렬 스트림
sequential()   //  병렬 스트림 → 스트림
Stream<T>
IntStream
7. 스트림 → 컬렉션
Stream<T> collect (Collectors.toCollection (Supplier factory)) Collection<T>
collect (Collectors.toList()) List<T>
collect (Collectors.toSet()) Set<T>
8. 컬렉션 → 스트림
Collection<T> stream() Stream<T>
9. 컬렉션 → 스트림
Stream<T> collect (Collectors.toMap(Function Key, Function value)) Map<K, V>

 

 

 

감사합니다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
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
29 30 31
글 보관함