List<String> list = ...;
for(int i=0; i<list.size(); i++) {
String item = list.get(i);
//item 처리
}
Set<String> set = ...;
Iterator<String> iterator = set.iterator();
while(iterator.hasNext()) {
String item = iterator.next();
//요소 처리
}
Stream<String> stream = list.stream();
stream.forEach( item -> //item 처리);
- 내부 반복자이므로 처리 속도가 빠르고 병렬 처리에 효율적이다.
- 람다식으로 다양한 요소 퍼리를 정의할 수 있다.
- 중간 처리와 최종 처리를 수행하도록 파이프 라인을 형성할 수 있다.
컬렉션의 요소를 컬렉션 바깥쪽으로 반복해서 가져와 처리하는데, 이것을 외부 반복자라고 한다.
요소 처리 방법을 컬렉션 내부로 주입시켜서 요소를 반복 처리하는데, 이것을 내부 반복자라고 한다.
아래 그림은 Student 객체를 요소로 가지는 컬렉션에서 Student 스트림을 얻고, 중간 처리를 통해 score 스트림으로 변환한 후 최종 집계 처리로 score 평균을 구하는 과정을 나타낸 것이다.
//Student 클래스 Stream<Student> studentStream = list.stream(); //Score 스트림 IntStream scoreStream = studentStream.mapToInt ( student -> student.getScore() ); //평균 계산 double avg = scroeStream.average().getAsDouble();
//메소드 체이닝 패턴 사용 double avg = list.stram() .mapToInt(student -> student.getScore()) .average() .getAsDouble();
이 스트림 인터페이스들의 구현 객체는 다양한 리소스로부터 얻을 수 있다.
import java.util.ArrayList;
import java.util.List;
public class FilteringExample {
public static void main(String[] args) {
//List 컬렉션 생성
List<String> list = new ArrayList<>();
list.add("홍길동"); list.add("신용권");
list.add("김자바"); list.add("신용권"); list.add("신민철");
//중복 요소 제거
list.stream()
.distinct()
.forEach(n -> System.out.println(n));
System.out.println();
//신으로 시작하는 요소만 필터링
list.stream()
.filter(n -> n.startsWith("신"))
.forEach(n -> System.out.println(n));
System.out.println();
//중복 요소를 먼저 제거하고, 신으로 시작하는 요소만 필터링
list.stream()
.distinct()
.filter(n -> n.startsWith("신"))
.forEach(n -> System.out.println(n));
}
}
홍길동
신용권
김자바
신민철
신용권
신용권
신민철
신용권
신민철
sorted((o1,o2) -> { ... })
매개타입인 Consumer는 함수형 인터페이스.
//Consumer<? super T>를 람다식으로 표현
T -> { ... }
or
T -> 실행문; //하나의 실행문만 있을 경우 중괄호 생략
import java.util.Arrays;
public class LoopingExample {
public static void main(String[] args) {
int[] intArr = { 1, 2, 3, 4, 5 };
//잘못 작성한 경우
Arrays.stream(intArr)
.filter(a -> (a%2) ==0)
.peek(n -> System.out.println(n)); //최종 처리가 없으므로 동작하지 않음
//중간 처리 메소드 peek()을 이용해서 반복 처리
int total = Arrays.stream(intArr)
.filter(a -> (a%2)==0)
.peek(n -> System.out.println(n))
.sum();//최종처리
System.out.println("총합 : " + total + "\n");
//최종 처리 메소드 forEach()를 이용해서 반복 처리
Arrays.stream(intArr)
.filter(a -> (a%2)==0)
.forEach(n -> System.out.println(n));
}
}
2
4
총합 : 6
2
4
모두 만족하는지 여부는 all 하나라도 만족하는지는 any, 모두 만족하지 않는 여부는 none을 접두사로 붙인다 ex) allMatch()
1) isPresent() 메소드가 true를 리턴할 때만 집계값만 얻는다.
OptionalDouble optional = stream
.average();
if(optional.isPresent()) {
System.out.println("평균: " + optional.getAsDouble());
} else {
System.out.println("평균 : 0.0");
}
2) orElse() 메소드로 집계값이 없을 경우를 대비해서 디폴트 값을 정해놓는다.
double avg = stream
.average();
.orElse();
System.out.println("평균 : " + avg);
3) ifPresent() 메소드로 집계값이 있을 경우에만 작동하는 Consumer 람다식을 제공한다.
stream
.average()
.ifPresent(a -> System.out.println("평균 : " + a));
(a, b) -> { ... return 값; }
or
(a, b) -> 값 //return 문만 있을 경우 중괄호와 return 키워드 생략 가능
int sum = stream
.reduce((a, b) -> a+b)
.getAsInt();
//요소가 없다면 NoSuchElementException 발생
int sum = stream
.reduce(0, (a, b) -> a+b);
//default 값으로 0을 리턴
.filter(a -> a.toLowerCase().contains("java"))
.forEach(a -> System.out.println(a));
.mapToInt(Member::getAge)
.average()
.getAsDouble();
.filter(m -> m.getJob().equals("개발자"))
.collect(Collectors.toList());
.collect(Collectors.groupingBy(m -> m.getJob()));
groupingMap.get("개발자").stream()
.forEach(m -> System.out.println(m));
groupingMap.get("디자이너").stream()
.forEach(m -> System.out.println(m));