Stream API
- 데이터의 흐름. 배열 또는 컬렉션에 함수 여러개를 조합해서 원하는 결과를 얻게해줌
- 저장된 데이터를 다양한 방식으로 처리하기 위한 기능 제공
- 자바 8부터 추가된 기능 이전에는 for, forEach문만 사용
- 가독성이 떨어지는 for, forEach문의 단점 보완
특징
- 일회용
- 요청시에만 요소를 계산
- 원본 데이터 변경 없이 결과를 새로운 스트림에 저장
- 하나의 작업을 두개 이상으로 나눠서 동시 진행하는 '병렬처리' 가능
Collection과의 차이
Stream: 내부반복
- 병렬처리 및 최적화된 순서로 처리 가능
- 필요 데이터만 메모리에 로드해서 사용
Collection: 외부반복
- 컬렉션의 항목을 한개씩 가져와서 처리하므로 최적화 안됨
- 모든 데이터를 메모리에서 로드해서 처리
Stream의 흐름
생성
배열스트림
Arrays.stream(배열);
String[] example = new String[]{1,2,3,4,5};
Stream<String> stream = Arrays.stream(example);
컬렉션스트림
List<String> 스트림명 = List.of("값","값","값"..);
List<String> names = List.of("김유신","강감찬","이순신","유관순","홍길동");
// 스트림 생성
Stream<String> stream = names.stream();
빈 스트림(empty stream)
Stream<Object> stream = Stream.empty();
중간연산(변환)
- 초기 스트림을 다른 스트림으로 변환
- 두번 이상 사용가능하며 생략 가능
- 필터링, 매핑으로 자료 분류
필터링
filter(Predicate)
IntStream example = IntStream.of(7, 5, 5, 2, 1, 2, 3, 5, 4, 6);
examle.filter(num->num <= 5) // 5,5,2,1,2,3,5,4
- 조건식에 true인 값만 반환한 새 스트림 반환
distinct()
String[] sample = {"서울","경기","인천","서울","부산","인천","울산"};
sample.distict(); // 서울, 경기, 인천, 부산, 울산
변환
map(Function)
IntStream numbers = IntStream.of(1,3,5,7,9);
numbers.map(num -> num*2); // 2,6,10,14,18
- 스트림의 요소를 주어진 함수에 전달하여, 그 반환값으로 이루어진 새로운 스트림 반환
flatMap(Function)
// 배열생성
String names = {"김좌진", "이순신", "안중근", "김유신", "유관순"};
// 스트림생성
Arrays.stream(names)
// 스트림 변환
.flatMap(text->Stream.of(text.split(" "))) // 김좌진, 이순신, 안중근, 김유신, 유관순
- 스트림 요소가 배열일 때, 각 배열의 각 요소의 반환값을 하나로 합친 새로운 스트림 반환
제한
limit()
IntStream num1 = IntStream.range(0, 10); // 0~9
num.limit(5); // 0,1,2,3,4
- 첫번째 요소부터 시작하여 지정된 갯수만큼으로 이루어진 새로운 스트림 반환
skip()
IntStream num2 = IntStream.range(0, 10); // 0~9
num.skip(4); // 4,5,6,7,8,9
- 첫번째 요소부터 시작하여 지정된 갯수만큼을 제외한 나머지 요소로 이루어진 스트림 반환
정렬
sorted()
Stream<String> hangeul = Stream.of("마","다","라","가","나");
// 오름차순
hangeul.sorted(); // 가,나,다,라,마
// 내림차순
hangeul.sorted(Comparator.reverseOrder()); // 마,라,다,나,가
최종연산(사용)
- 스트림의 각 요소를 소모하거나 결과 표시
- 최종연산 완료 시 사용 불가
출력
forEach()
Stream<String> textArray = Stream.of("Hello","Hi","java","stream");
textArray.forEach(System.out::prinln);
소모
reduce()
Stream<String> countNumber = Stream.of("하나,"둘","셋,"넷");
String countNumber = countNumber.reduce("숫자세보기! ",(s1,s2)->s1+" 다음 "+s2);
// 숫자세보기! 하나 다음 둘 다음 셋 다음 넷
- 첫번째와 두번째 요소로 연산 수행 후, 그 값과 세번째 요소로 연산 수행
- 모든 요소를 소모하여 연산 소모 후 결과 반환
검색
findFirst()
IntStream example = IntStream.of(4, 2, 7, 3, 5, 1, 6);
OptionalInt result1 = stream1.findFirst(); // 4
findAny()
IntStream example = IntStream.of(4, 2, 7, 3, 5, 1, 6);
OptionalInt result1 = stream1.findFirst(); // 4
- 스트림의 첫번째 값 반환
- 병렬일 경우 findAny()를 사용해야 정확한 연산결과 반환 가능
검사
anyMatch()
IntStream numbers = IntStream.of(30, 90, 70, 10);
numbers.anyMatch(n-> n >= 70); //true
- 스트림의 일부요소가 특정 조건 만족 시 true 반환
allMatch()
IntStream numbers = IntStream.of(30, 90, 70, 10);
numbers.allMatch(n-> n >= 10); // true
numbers.allMatch(n-> n >= 70); // false
- 스트림의 모든요소가 특정 조건 만족 시 true 반환
noneMatch()
IntStream numbers = IntStream.of(30, 90, 70, 10);
numbers.noneMatch(n-> n >= 70); // false
numbers.noneMatch(n-> n >= 95); // true
- 스트림의 모든 요소가 특정 조건을 만족하지 않을 시 true 반환
통계
count()
IntStream.of(4, 2, 7, 6, 8, 1, 5).count()); // 7
min()
IntStream.of(4, 2, 7, 6, 8, 1, 5).min().getAsInt()) // 1
- 요소 중 가장 작은 값 반환
- getAsInt()를 하지 않으면 OptionalInt[값] 형태로 반환됨
max()
IntStream.of(4, 2, 7, 6, 8, 1, 5).max().getAsInt()) // 8
- 요소 중 가장 큰 값 반환
- getAsInt()를 하지 않으면 OptionalInt[값] 형태로 반환됨
연산
sum()
IntStream.of(4, 2, 7, 6, 8, 1, 5).sum() // 33
average()
IntStream.of(2,4,6,8,10).average().getAsDouble() // 6.0
- 요소의 평균 반환
- getAsInt()를 하지 않으면 OptionalDouble[값] 형태로 반환됨
수집
collect()
List<Integer> numberList = Stream.of(4, 2, 7, 6, 8, 1, 5).collect(Collectors.toList());
// [4,2,7,6,8,1,5]
Set<Integer> numberSet = Stream.of(4, 2, 7, 6, 8, 1, 5).collect(Collectors.toSet());
// [1,2,4,5,6,7,8]
- 스트림의 각 요소를 List, Set등의 형태로 반환
Optional
- 객체를 포장해주는 래퍼클래스. 모든 타입의 참조변수 저장 가능
- 간단하게 NullPointerException 처리 가능
생성
empty()
- 아무값도 갖지 않는 Optional 객체 반환
of()
- null이 아닌 명시된 값을 갖는 Optional 객체 반환
- null 저장 시 NullPointerException 발생
Optional<String> opt1 = Optional.of("가나다");
// 가나다
ofNullable()
- 값을 갖는 Optional객체 혹은 Null일 경우 비어있는 Optional 객체 반환
Optional<String> opt = Optional.ofNullable("Hello,world");
// Hello,world
검사
isPresent()
Optional<String> opt = Optional.ofNullable("테스트");
opt.isPresent() // true
조회
get()
- Optional 객체에 저장된 값 반환
- 객체가 비어있을 경우 NoSuchElementException 발생
Optional<String> opt1 = Optional.of("가나다");
opt1.get() // 가나다
orElse()
- 객체에 저장된 값 반환. 값이 없으면 인수로 전달된 값 반환
Optional<String> opt = Optional.empty();
opt.orElse("비어있습니다");
// 비어있습니다
orElseThrow()
- 객체에 저장된 값 반환. 값이 없으면 인수로 전달된 예외 발생
- if-else로 error를 발생시키지 않아도 됨
String name = null;
Optional.ofNullable(name).orElseThrow(IllegalArgumentException::new);