스트림
스트림이란?
- 배열 요소를 특정 기준에 따라 정렬 하거나 (sort), 요소 중 특정 값은 제외하고 출력하는 기능 (filter).
- 이런 자료처리에 대한 기능을 구현해놓은 클래스가 stream이다.
- 스트림을 활용하면 자료를 일관성 있게 처리할 수 있다.
- 자료에 따라 기능을 새로 구현하는 것이 아니라 자료형에 상관없이 같은 방식으로 메소드를 호출한다.
- 간단한 스트림 예제
int[] arr = {1,2,3,4,5};
Arrays.stream(arr).forEach(n -> System.out.println(n));
Arrays.stream()
: 스트림의 생성 부분이다forEach()
: 요소를 하나씩 꺼내는 기능이다.
스트림 연산
- 스트림의 연산 종류에는 크게 중간 연산과 최종 연산 두 가지가 있다.
- 중간 연산 : 자료를 거르거나 변경하여 또 다른 자료를 내부적으로 생성한다.
- 최종 연산 : 생성된 내부 자료를 소모하며 연산을 수행한다.
중간 연산
filter()
- 조건을 넣고 그 조건에 맞는 참인 경우만 추출하는 경우에 사용한다.
sList.stream().filter(s -> s.length() >= 5).forEach(s -> sout(s));
- 문자열의 길이가 5 이상인 경우만 출력하는 코드.
map()
- 특정 요소만 가지고 와서 출력하는 경우에 사용한다.
- map()은 요소를 순회해 다른 형식으로 변환하기도 한다.
customerList.stream().map(c -> c.getName()).forEach(s -> sout(s));
- 클래스에서
getName()
으로 클래스의 특정 요소만 가지고오는 코드.
최종 연산
- forEach() : 요소 순회
- count() : 배열 요소의 개수
- sum() : 배열 요소의 합계
- reduce() : (아래에서 다시 설명)
스트림 생성하고 사용하기
정수 배열에 스트림 생성하고 사용하기
Collection에서 스트림 생성하고 사용하기
- ArrayList에 스트림을 생성하고 활용해보자.
Stream<E> stream()
: 스트림 클래스를 반환한다.- Collection에서 stream()를 이용하면 클래스는 제네릭형을 사용해 아래와 같이 자료형 명시가 가능하다
Stream<Stream> strm = sList.stream();
- 이렇게 생성된 스트림은 내부적으로 ArrayList의 모든 요소를 가지고 있다.
forEach()
- forEach()를 활용해 모든 요소를 가지고 와본다
strm.forEach(s -> sout(s));
- forEach()내의 람다식의 s에 하나씩 변수가 들어가고 출력문이 실행된다.
sorted()
- sorted()를 활용해 모든 요소를 정렬해본다.
strm.sorted().forEach(s -> sout(s));
- 중간 연산으로 sorted()를 활용하면 요소를 정렬할 수 있다.
- 기본 정렬 이외에 지정된 정렬방식이 있다면, Comparable를 구현하거나 Comparator 클래스를 sorted()의 매게변수로 지정해줘야 한다.
- 코드보기
스트림의 특징
자료의 대상과 관계 없이 동일한 연산을 수행한다
- 배열이나 컬렉션에 저장된 자료를 가지고 수행할 수 있는 연산은 여러가지가 있다.
- 단순 출력, 조건에 따른 필터링, 합계 또는 평균.
- 스트림은 컬렉션의 여러 자료구조에 대해 이러한 작업을 일관성 있게 처리할 수 있다.
한 번 생성하고 사용한 스트림은 재사용할 수 없다
- 스트림을 생성하고 메소드를 호출해 연산을 수행했다면 다시 사용할 수 없다.
- 만약 다른 기능을 호출 하려면 스트림을 새로 생성해야한다.
스트림의 연산은 기존 자료를 변경하지 않는다.
- 스트림을 생성하면서 중간연산으로 정렬이나 합을 구한다고 하더라도 원본 자료는 변하지 않는다.
- 스트림 연산을 위한 메모리 공간이 별도로 존재한다.
스트림의 연산은 중간 연산과 최종 연산이 있다.
- 중간연산은 여러개가 적용 될 수 있다.
- 최종연산은 마지막 하나만 적용된다.
- 중간연산이 여러개 호출되더라도 최종연산이 있어야 중간 연산들이 모두 적용된다. – 이것을 지연 연산(lazy evaluation)이라고 한다.
기능을 지정하는 reduce() 연산
- reduce()는 내부적으로 스트림의 요소를 하나씩 소모하면서 프로그래머가 직접 지정한 기능을 수행한다.
- reduce()원형
T reduce(T idnetify, BinaryOperator<T> accumulator)
T idnetify
: 초기값BinaryOperator<T> accumulator
: 수행해야 할 기능BinaryOperator
인터페이스는 두 매개변수로 람다식을 구현한다. 람다식이 각 요소가 수행해야할 기능이 된다.- 람다식을 직접 넣어도 되고 인터페이스를 구현한 클래스를 생성하여 대입해도 된다.
BinaryOperator
는 Functional Interface로 apply()
를 반드시 구현해야한다.apply()
는 두 개의 매개변수와 한개의 반환값을 가진다. 세 개 모두 같은 자료형이다.reduce()
가 호출될 때 BinaryOperator
의 apply()
가 호출된다.- 요소의 합에 대해
reduce()
를 사용한 예
Arrays.stream(arr).reduce(0, (a , b) -> a + b));
0
: 초기값(a, b)
: 전달되는 요소-> a + b
: 각 요소가 수행해야 하는 기능- 가장 긴 문자열을 찾아내는 reduce()예제
class CompareString implements BinaryOperator<String> {
@Override
public String apply(String s, String s2) {
if (s.getBytes().length >= s2.getBytes().length) {
return s;
} else {
return s2;
}
}
}
public class ReduceTest {
public static void main(String[] args) {
String[] greetings = {"안녕하세요", "헬로", "곤방와", "봉쥬르"};
System.out.println(
Arrays.stream(greetings)
.reduce("", (s1, s2) -> {
if (s1.getBytes().length >= s2.getBytes().length) {
return s1;
} else {
return s2;
}
})
);
String str = Arrays.stream(greetings).reduce(new CompareString()).get();
System.out.println(str);
}
}
- 첫번째 스트림에서는 람다식 내 직접 구현하고 있고
- 두번째 스트림은 구현한 인터페이스를 생성하여 사용하고 있다. apply()가 자동으로 호출된다.
스트림을 활용하여 여행객의 여행 비용 계산하기
public class TravelTest {
public static void main(String[] args) {
List<TravelCustomer> customerList = new ArrayList<>();
customerList.add(new TravelCustomer("MINKANG", 30, 100));
customerList.add(new TravelCustomer("JIN-LEE", 31, 200));
customerList.add(new TravelCustomer("JONGPAK", 16, 300));
System.out.println("== in-order customer list ==");
customerList.stream()
.map(c -> c.getName())
.forEach(s -> System.out.println(s));
int total =
customerList.stream()
.mapToInt(c -> c.getPrice())
.sum();
System.out.println("Total travel cost: " + total);
System.out.println("== Customer list that age over 20");
customerList.stream()
.filter(c -> c.getAge() >= 20)
.map(c -> c.getName())
.sorted()
.forEach(s -> System.out.println(s));
}
}
== in-order customer list ==
MINKANG
JIN-LEE
JONGPAK
Total travel cost:600
== Customer list that age over 20
JIN-LEE
MINKANG