[Java] Stream 공부

YoungHo-Cha·2021년 9월 22일
5

Java

목록 보기
1/7
post-thumbnail

리팩토링을 하며, 스트림의 필요성을 알게되었다.
오늘은 스트림에 대해서 공부를 해볼 것이다.


🚗목차

  • 스트림이란?
  • 스트림 생성
  • 스트림 연산

🤔스트림이란?

List, Set, Map과 같은 Java Collection을 똑같은 방식으로 다루기 위한 객체

🔎왜 사용하는가?

다음 코드 두개로 바로 이해해보자.

ArrayList -> 중복 제거 -> 정렬 -> 출력

기존 Java Code

ArrayList<Integer> arr = new ArrayList<Integer>();
arr.add(10);
arr.add(5);
arr.add(6);
arr.add(5);

//중복 제거 로직
//for() ~~~

//정렬 로직
//for() ~~~

//출력 로직
//for() ~~~

Stream을 이용한 Java Code

List<String> arr = new List<String>();
arr.add("o");
arr.add("c");
arr.add("a");
arr.add("o");

Stream<String> listStream = arr.stream();
listStream.distinct().sorted().forEach(System.Out::println);
// = arr.stream().distinck().sorted()...

단 한 줄로도 많은 로직을 대체 할 수가 있다.

  • 코드를 보기 쉽다.
  • 코드를 쓰기 편하다.
  • 오류를 방지할 수 있다.
  • 안귀찮다.

🔎스트림 특징

  1. 스트림을 생성하고 최종 연산을 수행하면 해당 스트림은 사라진다.
  2. 스트림은 원본 데이터에 영향을 주지 않는다. 단순히 읽기만 한다.
  3. 멀티쓰레드를 이용하여 작업을 병렬로 처리할 수 있다.("parallel 호출", 속도가 빨라진다.)

🤔 스트림 생성

먼저 어떠한 타입을 읽고 스트림으로 생성해야한다. 코드로 바로 살펴보자.

🔎객체로부터 스트림 생성


// ----------- 객체로부터 스트림 생성----------
Stream<String> strStream = Stream.of("a", "b", "c"); //생성

int[] intArr = {1, 2, 3, 4, 5};
IntStream intStream = Arrays.steam(intArr); //생성

Stream vs IntStream

굳이 2개로 나눈 이유가 무엇일까?

거기에 대한 답은 다음과 같다.

IntStream은 int 타입이라는 것을 알고 있다. 그래서 average, sum과 같은 숫자를 다루는 함수가 추가적으로 제공된다.

Stream -> IntStream으로 변경하는 함수는 찾아보니까 제공되지 않는 것 같다..

🔎랜덤 스트림 생성


//-------------랜덤 스트림 생성 --------------//
IntStream intStream = new Random().ints(int begin, int end); //난수 무한스트림 생성

IntStream intStream = new Random().ints(int streamSize, int begin, int end); // 난수 유한스트림 생성
//LongStream, DoubleStream도 있다. - longs(), doubles()

자주 쓰이는 일을 없을 듯 하지만, 알아두도록 하자!

🔎범위 스트림 생성


// -------------범위로 생성 -----------------
IntStream intStream = IntStream.range(1, 5); // 1, 2, 3, 4
IntStream intStream = IntStream.ranged(1, 5); //1, 2, 3, 4, 5

🔎람다식을 이용한 스트림 생성

// ----------람다식으로 스트림 생성-----------

Stream<Integer> evenStream = Stream.iterate(0, n->n+2) // 0, 2, 4, 6 ~

Stream<Double> randomStream = Stream.generate(Math::random);//랜덤

Stream<Integer> oneStream = Stream.generate(() -> 1);
// 1, 1, 1, 1, ~

가장 많이 쓰이는 내용이 될 듯하다.

스트림은 위의 코드와 같이 생성할 수 있다.

더 많은 기능이 있는데, 필요하다면 찾아보도록 하자!

🤔 스트림의 연산

스트림의 흐름은 다음과 같다.

생성 -> 중간 연산(n번 반복) -> 최종 연산 -> 스트림 소멸

중간 연산은 주로 Stream으로 리턴이 된다.
최종 연산은 주로 void, Optional, 기본 타입으로 리턴이 된다.

🔎중간 연산

중간 연산에 대해서 알아보도록 하자.

중간 연산은 생성된 스트림에 임의의 조작을 하는 것이다.
위에서 보았던 "distinct", "sorted"와 같다.

중간 연산이 어느 것이 있는지 살펴보자.

리턴함수 명파라미터설명
Stream <T>distinct-중복 제거
Stream <T>filterPredicate<T> predicate조건에 맞지 않는 요소 제거
Stream <T>limitlong maxSizemaxSize 이후의 요소 삭제
Stream <T>skiplong nn만큼 뛰어넘음
Stream <T>sorted- & Comparator<T> comparator스트림의 요소를 정렬(없으면 오름차순)
Stream <T>mapFunction<T,R> mapper스트림의 요소를 변환한다.

중간 연산 예시

헷갈릴만한 것만 골라서 보자!

//-----------filter-----------
intStream.filter(i->i%2==0).forEach(System.out::print); // 246810

IntStream intStream = IntStream.rangeClosed(1, 10);
intStream.filter(i->i%2==0 && i%3!=0) // 논리 연산자도 가능
// = intStream.filter(i->i%2==0).filter(i->i%3==0);

//-----------sorted-----------
studentStream.sorted(Comparator.comparint(Student::getBan));/// 반별로 정렬

studentStream.sorted(Comparator.comparint(Student::getBan))//반별로 정렬
    .thenComparing(Student::getTotalScore)// 총점으로 정렬
    .thenComparing(Student::getName)) //이름으로 정렬
    .forEach(System.out::println);
      
//------------map-------------
Stream<File> fileStream = Stream.of(new File("Ex1.java"), 
  				    new File("Ex1"), 
   				    new File("Ex1.bak"), 
   				    new File("Ex2.java"), 
   				    new File("Ex1.txt"));

fileStream.map(File::getName) //Stream<File> -> Stream<String>
.filter(s->s.indexOf('.') != -1) //확장자 없으면 제거
.map(s->s.substring(s.intexOf('.')+1)) //Stream<String>(이름 전체) -> Stream<String>(확장자만)
.map(String::toUpperCase) // Stream<String> -> Stream<String> 대문자로
.distinct() //중복 제거
.forEach(System.out::println); // JAVABAKTXT

// File Stream을 name만 뽑아서 String Stream으로 변환해주었다.

다음은 최종 연산을 보자.

🔎최종 연산

리턴함수 명파라미터설명
voidforEachConsumer<? super T> action)각 요소에 지정된 작업 수행
voidforEachOrderedConsumer<? super T> action병렬용
longcount-스트림 요소의 개수 반환
Optional<T>max/minComparator&#? super T> comparator스트림의 최대값/최소값을 반환
Optional<T>findAny/findFirst-스트림의 요소를 랜덤/하나를 반환
booleanallMatchPredicate<T> p주어진 조건을 모두 만족하는지 확인
Object[]toArray-스트림의 모든 요소를 배열로 반환

위의 최종 연산이 수행되면 해당 스트림은 소멸한다.

최종적으로 코드를 보자. 위에서 보았던 것이랑 같다.

List<String> arr = new List<String>();
arr.add("o");
arr.add("c");
arr.add("a");
arr.add("o");

Stream<String> listStream = arr.stream();
listStream.skip(1).distinct().sorted().forEach(System.Out::println);

// o,c 스킵 -> o, o 중복 제거 -> 오름차 순 정리 -> 반복 출력


🧷Reference


마치며

스트림을 자주 사용하여 코드를 아주 짧게 쓰고, 보기 편하게 만드는 습관을 들이도록 하자!!

오늘은 여기까지 알아보도록 하자!

profile
관심많은 영호입니다. 궁금한 거 있으시면 다음 익명 카톡으로 말씀해주시면 가능한 도와드리겠습니다! https://open.kakao.com/o/sE6T84kf

0개의 댓글