스트림 API는 특정 속성이 데이터 집합에 존재 여부를 검색하는데 유용한

allMatch, anyMatch, noneMatch, findFirst, findAny 등의 메서드를 제공.

 

예제를 작성하기에 앞서 공통으로 사용할 games 리스트를 생성.

// 게임 데이터를 담는 리스트 생성.
List<Game> games = Arrays.asList(
	 new Game("CALL 1", 20000)
	,new Game("DIA 3", 30000)
	, new Game("DIA 2", 40000)
	, new Game("DIA 1", 50000)
);

 

anyMatch 

적어도 한 요소와 프레디케이트와 일치하는지 확인하는 메서드.

// 적어도 하나라도 일치하는지 불리언 반환하므로 최종연산
if(games.stream().anyMatch(game -> game.getName().startsWith("CALL"))) {
	System.out.println("The game is CALL series");
}

 

결과값

CALL 1이 일치하는 요소 이므로 아래의 결과값 출력.

The game is CALL series

 

allMatch

모든 요소가 주어진 프레디케이트와 일치하는지 검사.

// 모든 요소와 일치하는지 검사
if(games.stream().allMatch(game -> game.getName().startsWith("CALL"))) {
	System.out.println("The game is CALL series");
}

 

결과값

CALL 1 외에는 전부 DIA 시리즈이므로 일치하는 것이 없어 출력되는 것이 없음.

 

noneMatch

모든 요소가 주어진 프레디케이트와 일치하는지 않는지 검사.

if(games.stream().noneMatch(game -> game.getName().startsWith("STAR"))) {
	System.out.println("There is no Star series on this list of games");
}

 

결과값

요소 중에 STAR 시리즈는 없으므로 아래와 같은 결과가 출력.

There is no Star series on this list of games

 

 

findAny

현재 스트림의 임의의 요소를  Optional 객체로 반환.

Optional은 자바 8 에서 추가 된 기능으로 간단하게 활용도를 설명하면 null 확인 관련 버그를 피하는데 유용하다.

Optional에 대해서는 추후에 따로 글을 작성해보겠습니다.

Optional<Game> result = games.stream()
			.filter(game -> game.getName().startsWith("DIA"))
			.findAny();
System.out.println(result.get().getName());

 

결과값

요소 중에 랜덤으로 출력.

 

findFirst

첫번째 요소를 찾아서 Optional 객체로 반환.

Optional<Game> result = games.stream()
			.filter(game -> game.getName()
			.startsWith("DIA")).findFirst();
System.out.println(result.get().getName());

 

결과값

첫번째 요소는 DIA 3 이므로 아래와 같은 결과 출력.

DIA 3

 

 

'Java > Stream' 카테고리의 다른 글

기본형 특화 스트림  (0) 2022.10.27
리듀싱  (0) 2022.10.26
map과 flatMap  (0) 2022.10.17
필터링 및 슬라이싱  (0) 2022.10.10
정의 및 특징  (0) 2022.10.03

스트림 API의 map과 flatMap 메서드는 특정 데이터를 선택 가능하게 기능을 제공.

 

스트림 map

List<Game> games = Arrays.asList(
	new Game("CALL 1", 20000)
	, new Game("DIA 1", 30000)
	, new Game("DIA 2", 40000)
	, new Game("DIA 3", 50000)
);

객체 데이터를 생성 후에 간단하게 리스트 요소들의 게임명을 가져오는 map에 예제.

List<String> gameNameList = games.stream()
				.map(Game::getName)
				.collect(toList());
		
gameNameList.stream().forEach(name -> System.out.println(name));

만약에 각 요소들의 게임명의 길이가 필요하다면 아래와 같이 체이닝 처리할 수 있다.

List<Integer> gameNameLengthList = games.stream()
				.map(Game::getName)
				.map(String::length)
				.collect(toList());
		
gameNameLengthList.stream().forEach(itemLength -> System.out.println(itemLength));

 

결과값

6
5
5
5

 

스트림 flatMap

메서드 map을 이용해 리스트의 중복을 제거한 각 단어의 길이를 반환한다고 하자.

아래와 같이 작성한다면 리턴 값은 Stream<String[]>이 된다.

각각의 스트림으로 반환이 되는 것이다.

List <String> words = Arrays.asList("Goodbye", "World");
		
List<String[]> uniqueCharList = words.stream()
.map(word -> word.split(""))
.distinct()
.collect(toList());

하나의 스트림으로 반환하고 싶다면 어떻게 해야 할까?

아래와 같이 작성해도 결국 Stream 리스트가 반환된다.

 

List<Stream<String>> uniqueCharList = words.stream()
		.map(word -> word.split(""))
		.map(Arrays::stream)
		.distinct()
		.collect(toList());​

flatMap을 사용하면 각 배열을 스트림이 아니라 스트림의 콘텐츠로 맵핑한다.

앞의 예제와는 다르게 하나의 스트림을 반환한다.

List<String> uniqueCharList = words.stream()
		.map(word -> word.split(""))
		.flatMap(stream -> Arrays.stream(stream))
		.distinct()
		.collect(toList());
		
uniqueCharList.stream().forEach(System.out::println);

 

결과값

GodbyeWrl

 

'Java > Stream' 카테고리의 다른 글

기본형 특화 스트림  (0) 2022.10.27
리듀싱  (0) 2022.10.26
검색과 매칭  (0) 2022.10.26
필터링 및 슬라이싱  (0) 2022.10.10
정의 및 특징  (0) 2022.10.03

스트림 필터링

스트림에서 지원하는 filter 메서드 사용.

프리디케이트를 인수로 받아서 프레디케이트와 일치하는 모든 요소를 포함하는 스트림을 반환.

List<Integer> numArr = Arrays.asList(1,2,1,3,3,3,2,4,5);
numArr.stream()
	.filter(i -> i == 3)
	.forEach(System.out::println);

 

요소 중에 3인 요소들이 있으면 출력.

여기서 중복을 제거하는 고유 요소 필터링을 하고 싶다면 스트림에서 지원하는 distinct 메서드를 사용한다.

고유 여부는 스트림에서 만든 객체의 hashcode, equals로 결정.

List<Integer> numArr = Arrays.asList(1,2,1,3,3,3,2,4,5);
numArr.stream()
	.filter(i -> i == 3)
	.distinct()
	.forEach(System.out::println);

 

스트림 슬라이싱

프리디케이트를 이용한 슬라이싱, 스트림 요소 무시, 축소 등 다양한 방법으로 요소를 선택하거나 스킵할 수 있다.

아래 예제는 단순히 게임 목록에 대한 가격 필터링을 한 예제이다.

List<Game> games = Arrays.asList(
	new Game("CALL 1", 20000)
	, new Game("DIA 1", 30000)
	, new Game("DIA 2", 40000)
	, new Game("DIA 3", 50000)
);
List<Game> filteredGame = games.stream()
			.filter(game -> game.getPrice() < 40000)
			.collect(toList());

만약 filter 메서드의 요소를 만족했을 때 작업을 중단하고 싶다면 takeWhile, dropWhile을 사용하면 된다.

사용하지 않는 경우 모든 요소만큼 작업을 수행하므로 요소 목록 크기가 크다면 그만큼 낭비가 된다.

 

takewhile 메서드

프레디케이트가 처음으로 참이 되는 지점까지 발견된 요소를 반환.

List<Game> takeWhileGame = games.stream()
		.takeWhile(game -> game.getPrice() < 40000)
		.collect(toList());

 

dropwhile 메서드

프레디케이트가 처음으로 거짓이 되는 지점까지 발견된 요소를 버림.

List<Game> dropWhileGame = games.stream()
		.dropWhile(game -> game.getPrice() < 40000)
		.collect(toList());

 

limit 메서드

주어진 값 이하의 크기를 갖는 새로운 스트림을 반환.

List<Game> dropWhileGame = games.stream()
		.dropWhile(game -> game.getPrice() < 40000)
       		.limit(1)
		.collect(toList());

 

skip 메서드

처음 N개 요소를 제외한 스트림을 반환.

List<Game> dropWhileGame = games.stream()
		.dropWhile(game -> game.getPrice() < 40000)
       		.skip(2)
		.collect(toList());


위에서 작성한 예제들의 요소 값들을 출력해보면 어떻게 동작하는지 짐작할 수 있습니다.

filteredGame.stream().forEach(game -> System.out.println(game.getName()));
Sytem.out.println();
takeWhileGame.stream().forEach(game -> System.out.println(game.getName()));
Sytem.out.println();
dropWhileGame.stream().forEach(game -> System.out.println(game.getName()));

 

결과 값

CALL 1
DIA 1

CALL 1

DIA 1

 

'Java > Stream' 카테고리의 다른 글

기본형 특화 스트림  (0) 2022.10.27
리듀싱  (0) 2022.10.26
검색과 매칭  (0) 2022.10.26
map과 flatMap  (0) 2022.10.17
정의 및 특징  (0) 2022.10.03

정의

스트림이란?

데이터 처리 연산을 지원하는 추출된 연속된 요소.

자바 8 컬렉션에 stream 메서드 및 java.util.steam.Stream 에 인터페이스 정의가 추가되었다.

 

특징

1. 주제

컬렉션과 마찬가지로 스트림은 특정 요소 형식의 연속된 값 집합 인터페이스 제공.

컬렉션은 주제가 데이터이면 스트림은 데이터의 계산입니다.

 

2. 소스

스트림은 컬렉션, 배열, I/O 자원 등 데이터 제공 소스로부터 데이터를 소비.

정렬된 컬렉션으로 스트림을 생성하면 정렬이 그대로 유지.

 

3. 연산

일반적인 함수형 프로그래밍 언어 및 DB 비슷한 연산 기능 지원.

filter, map, reduce, find, match, sort 등 데이터를 조작. 

연산을 순차적, 병렬적으로 실행 가능.

 

4. 파이프라이닝

스트림 연산은 연산 끼리 연결하여 파이프 라이닝 구성 가능.

 

5. 내부 반복

외부에서 명시적으로 반복하는 컬렉션과 달리 스트림은 내부 반복 지원.

 

스트림과 컬렉션

1. 데이터 계산

컬렉션은 현재 자료구조가 포함하는 모든 값을 메모리에 저장하는 구조.

반면 스트림은 이론적으로는 요청할 때만 요소를 계산하는 구조.

 

2. 탐색

반복자와 마찬가지로 스트림도 소비되고 나면 반복 사용할 수가 없습니다.

 

3. 데이터 반복 처리

컬렉션은 요소를 사용자가 for 문 등을 사용하여 직접 요소를 꺼내어 연산하고 다시 요소를 넣는 외부 반복을 이 필요.

반면 스트림은 반복은 내부에서 알아서 처리하고 어떤 연산을 할지만 지정하면 처리가 가능.

 

스트림 연산

1. 중간 연산

filter나 sorted 같은 중간 연산은 다른 스트림을 반환.

중간 연산을 연결하여 파이프 라이닝 가능.

 

2. 최종 연산

스트림 파이프라인에서 List, Integer 등 스트림 이외의 결과를 반환.

 

비교 예제

기존 외부 반복을 통한 연산과 스트림을 통한 연산을 비교해보기 위한 간략한 예제.

1. Game 이라는 게임명, 가격을 가진 객체를 생성.

2. 30,000원 초과하는 가격의 게임의 게임명 리스트를 반환.

public class Game {
	private String name;
	private int price;
	
	public Game(String name, int price) {
		this.name = name;
		this.price = price;
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getPrice() {
		return price;
	}
	public void setPrice(int price) {
		this.price = price;
	}
}

 

 

package demo;

import java.util.ArrayList;
import java.util.List;
import static java.util.stream.Collectors.toList;

public class Main {
	public static void main(String[] args) {
		
        // 1. 데이터 초기화
		List<Game> gameList = new ArrayList<>();
		gameList.add(new Game("Hell Gate", 39900));
		gameList.add(new Game("Heaven Gate", 49900));
		gameList.add(new Game("DIA 1", 10000));
		gameList.add(new Game("DIA 2", 20000));
		gameList.add(new Game("DIA 3", 30000));
		
        // 2. 외부반복을 통한 처리
		List<String> highPriceGameList = new ArrayList<>(gameList.size()); 
		
		for(Game game : gameList) {
			if (game.getPrice() > 30000) {
				highPriceGameList.add(game.getName());
			}
		}
		System.out.println(highPriceGameList);
	}
}

 

package demo;

import java.util.ArrayList;
import java.util.List;
import static java.util.stream.Collectors.toList;

public class Main {
	public static void main(String[] args) {
		
        // 1. 데이터 초기화
		List<Game> gameList = new ArrayList<>();
		gameList.add(new Game("Hell Gate", 39900));
		gameList.add(new Game("Heaven Gate", 49900));
		gameList.add(new Game("DIA 1", 10000));
		gameList.add(new Game("DIA 2", 20000));
		gameList.add(new Game("DIA 3", 30000));
		
        // 스트림 연산을 통한 처리
		List<String> highPriceGameList = gameList.stream()
							.filter(game -> game.getPrice() > 30000)
							.map(Game::getName)
							.limit(gameList.size())
							.collect(toList());
		System.out.println(highPriceGameList);
	}
}

 

마치며

비교적 간단한 예제라서 코드 길이는 큰 차이가 없어 보이지만 파이프 라이닝과 외부 반복 연산 없이

내부 연산을 통해 가독성이 좋게 처리가 가능하다.

 

'Java > Stream' 카테고리의 다른 글

기본형 특화 스트림  (0) 2022.10.27
리듀싱  (0) 2022.10.26
검색과 매칭  (0) 2022.10.26
map과 flatMap  (0) 2022.10.17
필터링 및 슬라이싱  (0) 2022.10.10

+ Recent posts