Jin's Dev Story

[JAVA] Stream(스트림) 본문

Programming Language/JAVA

[JAVA] Stream(스트림)

woojin._. 2023. 7. 19. 11:28

Stream(스트림)

다양한 데이터 소스(컬렉션, 배열 등)를 표준화된 방법으로 다루기 위한 것

  • 데이터 소스를 스트림으로 변환 후 여러 번의 중간 연산과 마지막의 최종 연산을 통해 다를 수 있음
  • 배열, 컬렉션을 대상으로 연산 수행
  • 한 번 생성하고 사용한 스트림 재사용 불가
  • 중간 연산은 여러 개의 연산 적용 가능, 최종 연산은 마지막에 한 번 적용
    • 최종 연산이 호출되어야 중간 연산에 대한 수행이 이루어지고 그 결과가 만들어짐
    • 따라서 중간 연산에 대한 결과를 연산 중에 알 수 없음 → 이를 ‘지연 연산’이라 함
  1. 스트림 만들기
  2. 중간연산(반복 적용 가능, 연산 결과가 스트림)
  3. 최종연산(스트림의 요소를 소모) → 결과 리턴
list.stream() // 스트림 만들기
		.distinct() // 중간연산
		.limit(5)   // 중간연산
		.sorted()   // 중간연산
		.forEach(System.out::println)  // 최종연산

 

Stream의 특징

  1. 데이터를 담고 있는 저장소(컬렉션)이 아님
  2. 원본 데이터 소스를 변경하지 않음
  3. 일회용(필요하면 다시 스트림 생성)
  4. 병렬 처리 가능(멀티 쓰레드 사용 → .parallel)

1. Stream 생성

Stream<Integer> stream = Arrays.asList(1, 2, 3, 4, 5).stream();

 

2. Stream의 중간 연산

  • 중간 연산의 예 - filter(), map(), sorted() 등
    • 조건에 맞는 요소를 추출(filter)하거나 요소를 변환함(map)
  .distinct()  // 중복 제거
  .filter(Predicate<T> predicate) // 조건에 안맞는 요소는 제외
  .limit(long maxSize) // maxSize 이후의 요소는 잘라냄
  .skip(long n) // 앞에서부터 n개 건너뛰기
  .sorted()  // 정렬

  // 스트림의 요소를 변환 
  // ex) map(s->s.subString(3))
  .map(Function<T> mapper) 

  // 요소에 작업수행. 보통 중간 작업결과 확인으로 사용
  // peek(s->System.out.println(s))
  .peek(Consumer<T> action)

Stream.filter()

어떤 조건으로 Stream의 요소들을 필터링 함

List<String> list =
        Arrays.asList("a1", "a2", "b1", "b2", "c2", "c1", "c3");
Stream<String> stream = list.stream();
Stream<String> filtered = stream.filter(s -> s.startsWith("c"));
filtered.forEach(System.out::println);

// 출력 결과
// c2
// c1
// c3

Stream.map()

Stream의 요소를 다른 형태로 변경

List<String> list =
        Arrays.asList("a1", "a2", "b1", "b2", "c2", "c1", "c3");
Stream<String> stream = list.stream();
stream.map(s -> s.toUpperCase()).forEach(System.out::println);

// 출력 결과 : 
// A1
// A2
// B1
// B2
// C2
// C1
// C3

Stream.sort()

Stream의 요소를 정렬

List<Integer> notSortedList = Arrays.asList(3, 5, 2, 4, 1, 7);

// 오름차순
Stream<Integer> streamAsc = notSortedList.stream().sorted();

// 내림차순
Stream<Integer> streamDesc = notSortedList.stream().sorted(Comparator.reverseOrder());

예제 1) 

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

public class Stream_pr1 {

	public static void main(String[] args) {
		
		TravelCustomer customer1 = new TravelCustomer("이순신", 40, 100, "b");
		TravelCustomer customer2 = new TravelCustomer("김유신", 20, 100, "a");
		TravelCustomer customer3 = new TravelCustomer("홍길동", 13, 50, "c");
		
		List<TravelCustomer> customerList = new ArrayList<TravelCustomer>();
		customerList.add(customer1);
		customerList.add(customer2);
		customerList.add(customer3);
		
		System.out.println("== 고객 명단 추가된 순서대로 출력 ==");
		customerList.stream().map(c -> c.getName()).forEach(s -> System.out.println(s));
		
		int sum = customerList.stream().mapToInt(c -> c.getPrice()).sum();
		System.out.println("== 여행 총 비용 == " + sum);
		
		System.out.println("== 20세 이상 고객 명단 정렬 출력 ==");
		customerList.stream().filter(c -> c.getAge() >= 20).map(c -> c.getName()).sorted().forEach(s -> System.out.println(s));
	
		System.out.println("== 고객 등급 대문자로 변경 출력 (2개 요소를 출력하되 앞에서 1개 건너뛰기) ==");
		customerList.stream().map(c -> c.getTest().toUpperCase()).limit(2).skip(1).forEach(System.out::println);
	
	}
	
}

class TravelCustomer {

	private String name;
	private int age;
	private int price;
	private String test;
	
	public TravelCustomer(String name, int age, int price, String test) {
		this.name=name;
		this.age=age;
		this.price=price;
		this.test=test;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public int getPrice() {
		return price;
	}

	public void setPrice(int price) {
		this.price = price;
	}

	
	public String getTest() {
		return test;
	}

	public void setTest(String test) {
		this.test = test;
	}

	public String toString() {
		return "name=" + name + ", age=" + age + ", price=" + price + ", test=" + test;
	}
	
	
}

 

3. Stream의 최종 연산

  • 최종 연산의 예 - forEach(), count(), sum(), collect() 등
  • 최종 연산 후에 스트림은 더 이상 다른 연산을 적용할 수 없음

 

Stream.collect()

Stream의 데이터를 변형 등의 처리를 하고 원하는 자료형으로 변환해줌

  • List로 변환 → Collectors.toList()
  • Map으로 변환 → Collectors.toMap()
  • 그 외 Collections로 변환 → Collectors.toCollection(람다식)
  • 문자열 결합 → Collectors.joining(”결합할 문자”)
  //Collectors.toList()
  Stream<String> stream = Stream.of("1", "2", "3", "4", "5");
  List<String> streamToList = stream.collect(Collectors.toList());
  System.out.println("streamToList = " + streamToList);

  //Collectors.toMap()
  Stream<String> stream2 = Stream.of("1", "2", "3", "4", "5");
  Map<Integer, String> streamToMap = stream2.collect(Collectors.toMap((i) -> Integer.parseInt(i), (i) -> "\""+(i)+"\""));
  System.out.println("streamToMap = " + streamToMap);

  //List나 Map이 아닌 컬렉션으로의 변환
  Stream<String> stream3 = Stream.of("1", "2", "3", "4", "5");
  ArrayList<String> streamToArrayList = stream3.collect(Collectors.toCollection(() -> new ArrayList<>()));
  System.out.println("streamToArrayList = " + streamToArrayList);

  // 매개변수가 1개
  Stream<String> stream = Stream.of("1", "2", "3", "4", "5", "6");
  String joining = stream.collect(Collectors.joining(","));
  System.out.println("joining = " + joining);

  // 매개변수가 3개
  Stream<String> stream2 = Stream.of("1", "2", "3", "4", "5", "6");
  String joining2 = stream2.collect(Collectors.joining(",", "[", "]"));
  System.out.println("joining2 = " + joining2);

'Programming Language > JAVA' 카테고리의 다른 글

[JAVA] 지역 변수 & 전역 변수 & static(정적) 변수  (0) 2023.08.15
[JAVA] 인터페이스(interface)  (0) 2023.08.12
[JAVA] 가비지 컬렉션(Garbage Collection)  (0) 2023.08.01
[JAVA] JVM  (0) 2023.08.01
[JAVA] 람다식  (0) 2023.07.19