[210118] java Stream (1) - stream 정의와 관련 메소드
Stream은 java8에서 추가된 API이다. 데이터를 선언적으로 처리하고 특정 코드를 작성할 필요 없이 멀티 코어 아키텍처를 활용할 수 있도록 하기 위해 추가되었다.
Stream의 특성은 아래와 같다.
- Sequence of elements : stream은 순차적인 방식으로 특정 유형의 집합을 제공한다. 요소를 주문형으로 가져오고 처리하며, 요소를 저장하지는 않는다. 원본 데이터 구조를 변경하지도 않는다.
- Source : Stream으로 Collection, Array, 혹은 I/O 리소스를 사용할 수 있다.
- Aggregate operations : filter, map, limit, reduce, find, match 등의 메소드를 제공한다.
- Pipelining : 대부분의 Stream 함수가 처리 후에 자기자신을 return하면서, 파이프라인 형태로 구현할 수 있다.
- Automatic iterations : Stream 함수는 공급받은 요소에 대해서 내부적으로 이터레이터를 사용한다.
관련 메소드
Empty Stream
stream을 사용하려면 stream 객체를 생성해야 한다. Stream.empty() 메소드를 사용해서 빈 stream 객체를 만들거나, Collection, Array의 경우는 내장 메소드를 사용해서 stream을 생성할 수 있다.
// 1. 빈 Stream 객체 생성
Stream<Integer> stream1 = Stream.empty();
// 2. Collection 객체에서 객체 생성
List<Integer> list = new ArrayList<>(){};
Stream<Integer> stream2 = list.stream();
// 3. Array에서 stream 생성
int[] array = new int[10];
Stream<Integer> stream3 = Arrays.stream(array).boxed();
IntStream, LongStream, DoubleStream과 같은 인터페이스를 사용하면 자동으로 범위 안의 스트림 객체를 생성할 수 있다. 또, Random 클래스에 있는 ints, longs, doubles 메소드를 사용하면 랜덤의 수를 매개변수 개만큼 뽑아서 stream을 생성할 수 있다.
// 1. Random 객체 생성
Random random = new Random();
// 2. int 형의 stream 생성
// 2.1. IntStream.range 활용
IntStream intStream = IntStream.range(1, 5);
// 2.2. random.ints() 활용
intStream = random.ints(5);
// 3. double 형의 stream 생성
DoubleStream doubleStream = random.doubles(3);
doubleStream = random.doubles(5);
forEach
stream 내의 요소를 반복할 수 있다.
Random random = new Random();
random.ints().limit(5).forEach(System.out::println);
int[] arr = {1,2,3,4,5};
Arrays.stream(arr).forEach( i -> System.out.println("i = " + i));
map
stream 내의 요소 각각을 매핑하는 데 사용한다.
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
List<Integer> squaresList = numbers.stream().map(i -> i * i).distinct().collect(Collectors.toList());
squaresList.stream().forEach(i -> System.out.println("i = " + i));
distinct
stream 에 있는 요소 중 중복되는 요소를 제거한다.
List<Integer> list = Arrays.asList(1,4,2,3,3,5,1,4);
list.stream().distinct().forEach(System.out::println);
distinct 사용 결과 리스트에 있는 중복 요소가 모두 제거된 것을 확인할 수 있다.
filter
주어진 기준에 따라서 요소를 걸러낼 때 사용한다.
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
int count = (int) strings.stream().filter(string -> string.isEmpty()).count();
System.out.println("count = " + count);
list에서 string이 null인 요소의 숫자를 세는 코드이다.
limit
stream의 크기를 제한할 때 사용한다.
Random random = new Random();
random.ints().limit(5).forEach(System.out::println);
random.ints에서 5개만 추출해서 출력하였다.
sorted
stream을 정렬할 때 사용한다.
Random random = new Random();
random.ints().limit(10).sorted().forEach(System.out::println);
Parallel Processing
병렬 처리를 위해서 사용된다.
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
long count = strings.parallelStream().filter(string -> string.isEmpty()).count();
System.out.println("count = " + count);
Collectors
stream 처리 결과를 합치는 데 사용한다. 처리 결과로 list나 string을 반환할 수 있다.
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
System.out.println("Filtered List: " + filtered);
String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("Merged String: " + mergedString);
Collectors.toList()로 실행 결과를 list로 반환하고, Collecttors.joining()을 사용해서 결과를 ', '으로 연결한 후 string으로 반환하였다.
reduce
stream에서 연산을 수행해서 단일 결과를 생성할 수 있다.
: Parameters
- identity : 계산을 위한 초기값으로 stream이 비어있으면 디폴트 결과값이 된다.
- accumulator : 각 요소를 통합하기 위한 함수
- combiner : 2개 값을 합치기 위한 함수로 병렬 스트림에서 작동한다.
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
int result = numbers
.stream()
.reduce(0, (subtotal, element) -> subtotal + element);
System.out.println("result = " + result);
reduce의 초기값은 0이며, 요소를 각각 더한 합을 반환한다. 결과로 21이 출력됨을 확인할 수 있다.
-Reference
www.tutorialspoint.com/java8/java8_streams.htm
www.baeldung.com/java-8-streams
futurecreator.github.io/2018/08/26/java-8-streams/