본문 바로가기

언어공부/Java

자바 - 스트림(stream), 스트림의 특징

자바 - 스트림(stream), 스트림의 연산, forEach()에 대해서 알아보자.

스트림(stream)

컬렉션이나 배열에 데이터를 담고 원하는 결과를 얻기위해 for문과 Iterator를 이용해서 코드를 작성하는데 이러한 코드는 길고 알아보기 어려워 재사용성이 떨어진다. 또 다른 문제는 데이터 소스마다 다른 방식으로 다뤄야 한다.

 Collection이나 Iterator와 같은 인터페이스를 이용해서 컬렉션을 다루는 방식을 표준화하긴 했지만, 각 컬렉션 클래스에는 같은 기능의 메소드들이 중복해서 정의되어 있다. 예를 들어 List를 정렬할 때는 Collections.sort()를 사용해야 하고, 배열을 정렬할 때는 Arrays.sort()를 사용해야한다.

 

이러한 문제점들을 해결하기 위해서 만든 것이 '스트림(Stream)'이다. 스트림은 데이터 소스를 추상화하고, 데이터를 다루는데 자주 사용되는 메소드들을 정의해 놓았다. 데이터 소스를 추상화하였다는 것은 데이터 소스가 무엇이던 간에 같은방식으로 다룰 수 있게 되었다는 것과 코드의 재사용성이 높아진다는 것을 의미한다.

 스트림을 이용하면, 배열이나 컬레견뿐만 아니라 파일에 저장된 데이터도 모두 같은 방식으로 다룰 수 있다.

 

String[] stArr = {"aa","bb","cc"}; //배열
List<String> stList = Arrays.asList(stArr); //컬렉션

 

문자열 배열과 같은 내용의 문자열을 저장하는 List가 있을 때, 이 두 데이터 소스를 기반으로 하는 스트림은 아래와 같이 생성한다.

 

Stream<String> Stream1 = Arrays.stream(stArr); //스트림 생성
Stream<String> Stream2 = stList.stream(); //스트림 생성

 

이 두 스트림으로 데이터 소스의 데이터를 읽어서 정렬하고 화면에 출력하는 방법은 아래와 같다.

 

Stream1.sorted().forEach(System.out:println);
Stream2.sorted().forEach(System.out:println);

 

두 스트림의 데이터 소스는 서로 다르지만, 정렬하고 출력하는 방법은 완전히 동일하다.

 


스트림(stream)의 특징

스트림의 특징은 아래와 같다.

 

  1. 스트림은 데이터 소스를 변경하지 않는다. 데이터 소스로 부터 데이터를 읽기만 할 뿐, 데이터 소스를 변경하지 않는다.
  2. 스트림은 일회용이다. Iterator처럼 일회용이며, 스트림도 한번 사용하면 닫혀서 다시 사용할 수 없다.
  3. 스트림은 작업을 내부 반복으로 처리한다. 내부 반복이라는 것은 반복문을 메소드의 내부에 숨겼다는 것을 의미한다. forEach()는 스트림에 정의된 메소드 중의 하나로 매개변수에 대입된 람다식을 데이터 소스의 모든 요소에 적용한다. 즉, forEach()s는 메소드 안으로 for문을 넣은 것이며 수행할 작업은 매개변수로 받는다.
  4. 지연된 연산. 스트림 연산에서 한 가지 중요한 점은 최종 연산이 수행되기 전까지는 중간 연산이 수행되지 않는다는 것이다. 최종연산이 수행되어야 비로소 스트림의 요소들이 중간 연산을 거쳐 최종 연산에서 소모된다.
  5. Stream<Integer>와 IntStream. 요소의 타입이 T인 스트림은 기본적으로 Stream<T>이지만, 오토박싱&언박싱으로 인한 비효율을 줄이기 위해 데이터 소스의 요소를 기본형으로 다루는 스트림, IntStream, LongStream, DoubleStream이 제공된다.
  6. 병렬 스트림. 스트림으로 데이터를 다룰 때의 장점 중 하나가 바로 병렬 처리가 쉽다는 것이다. 

 

 

실행화면