스트림은 자바 8 API에 새로 추가된 기능으로 스트림은 컬렉션의 저장요소를 하나씩 참조해 람다식으로 처리할 수 있도록 해주는 반복자이다.
자바 7 이전까지는 List<String>
컬렉션에서 요소를 순차적으로 처리하기 위해 다음과 같이 사용했다.
List<String> LIST = Arrays.asList("홍길동", "신용권");
Iterator<String> iter = list.iterator();
while(iter.hasNext()){
String name = iter.next();
System.out.println(name);
}
이 코드를 Stream
을 사용해 변경하면 다음과 같다.
List<String> list = Arrays.asList("홍길동", "신용권");
Stream<String> stream = list.stream();
stream.forEach(name -> ystem.out.println(name));
컬렉션의 stream()
메서드로 스트림 객체를 얻고 나서 stream.ForEach()
를 사용해 컬렉션의 요소를 하나씩 출력한다.
대량의 데이터를 가공해 축소하는 것을 일반적으로 리덕션이라고 하느데 데이터의 합계, 평균값, 최대값 등이 대표적인 리덕션의 결과문이라고 볼 수 있다. 그러나 컬렉션의 요소를 리덕션의 결과물로 바로 집계할 수 없는 경우에는 집계하기 좋도록 필터링, 매핑, 정렬 등의 중간 처리가 필요하다.
double ageAvg = list.stream() //오리지널 스트림
.filter(m->m.getSex() == Member.MALE) //중간 처리 스트림
.mapToInt(Member::getAge)
.average() // 최종 처리
.getAsDouble();
필터링은 중간 처리 기능을 요소를 걸러내는 역할을 한다.
distinct()
: 중복 제거. Stream
의 경우 Object.equals(Object)
가 true이면 동일한 객체로 판단하고 중복을 제거한다.filter()
: 매개값으로 주어진 Predicate
가 true를 리턴하는 요소만 필터링한다.List<String> names = Arrays.asList("홍길동", "신용권", "신용권", "신민철");
names.stream().distinct().forEach(n->System.out.println(n));
//홍길동 신용권 신민철 출력
//중복값인 신용권 제거
names.stream().filter(n -> n.startsWith("신")).forEach(n -> System.out.println(n));
//신용권 신용권 신민철 출력
//첫 시작이 신인 이름만 출력됨
names.strea().filter(n -> n.startsWith("신")).forEach(n -> System.out.println(n));
//신용권 신민철
//신으로 시작되는 사람들 출력되지만 중복 값 제거
매핑은 중간 처리 기능으로 스트림의 요소를 다른 요소로 대체하는 작업을 말한다.
flatMapXXX()
: 요소를 대체하는 복수 개의 요소들로 구성된 새로운 스트림 리턴List<String> inputList = Arrays.asList("10, 20, 30", "40, 50, 60");
inputList.flatMapToInt(data -> {
String[] str = data.split(",");
int[] intArr = new int[str.length];
for(int i=0; i<str.length; i++){
intArr[i] = Integer.parseInt(str[i].trim());
}
return Arrays.stream(intArr);
})
.forEach(number -> System.out.println(number));
/* 출력
10
20
30
40
50
60
*/
mapXXX()
: 요소를 대체하는 요소로 구성된 새로운 스트림 리턴List<Student> student = Arrays.asList(
new Student("홍길동", 10),
new Student("신용권", 20)
);
student.stream().mapToInt(Student :: getScore)
.forEach(score -> System.out.println(score));
/* 출력
10
20
*/
asXXXStream()
: XXX 요소로 타입을 변환한다.boxed()
: int, long, double 요소를 Integer, Double, Long 요소로 박싱해서 Stream을 생성한다.int[] arr = {1, 2, 3, 4, 5};
IntStream intStream = Arrays.stream(intArray);
intStream.asDoubleStream().forEach(d -> System.out.println(d));
// DoubleStream 생성
intStream = Arrays.stream(arr);
intStream.boxed().forEach(obj -> System.out.println(obj.intValue()));
//Stream<Integer> 생성
/** 출력
1.0
2.0
3.0
4.0
5.0
1
2
3
4
5
*/
스트림은 요소가 최종 처리되기 전에 중간 단계에서 요소를 정렬해 최종 처리 순서를 변경할 수 있다.
루핑은 요소 전체를 반복하는 것을 말한다. 루핑하는 메소드에는 peek()
, forEach()
가 있다.
peek()
: 중간 처리 단계에서 전체 요소를 루핑하면서 추가적인 작업을 하기 위해 사용한다. 최정처리 메소드가 실행되지 않으면 지연되기 때문에 반드시 최종 처리 메소드가 호출되어야 한다.intStream.filter(a -> a%2 == 0).peek(a -> System.out.println(a));
// 이렇게 적으면 스트림 동작하지 않음
intStream.filter(a -> a%2 == 0).peek(a -> System.out.println(a)).sum();
//요소 처리의 최종 단계가 합을 구하는 것이라면 peek 이후 sum 메서드 호출 필요
forEach()
: 최종 처리 메소드이기 때문에 파이프라인 마지막에 루핑하면서 요소를 하나씩 처리한다.int[] arr = {1, 2, 3, 4, 5};
Arrays.stream(arr).filter(a -> a%2==0).forEach(n -> System.out.println(n));
/** 출력
2
4
*/
스트림 클래스는 최종 처리 단계에서 요소들이 특정 조건에만족하는지 조사할 수 있는 메서드를 제공한다.
allMatch()
: 모든 요소들이 매개값으로 주어진 Predicate
의 조건을 만족하는지 검사한다.anyMatch()
: 최소한 한개의 요소가 매개값으로 주어진 Predicate
의 조건을 만족하는지 검사한다.noneMatch()
: 모든 요소들이 매개값으로 주어진 Predicate
의 조건을 만족하지 않는지 검사한다.참고 : 이것이 자바다