자바로 배열 또는 컬렉션 객체를 다룰 때 IDE의 추천 메소드에는 stream()이 항상 있었다. 하지만 for문이나 향상된 for문으로도 충분히 원하는 결과를 이끌어낼 수 있어서 매번 지나쳤던 기억이 있다.
추후 로직이 복잡한 코드를 작성할 때 코드의 양이 많아지고 가독성이 떨어지는 상황을 대비해 스트림에 대해 제대로 알아보고 적절한 상황에 잘 활용할 수 있으면 좋겠다.
Java 8부터 추가된 기술로 람다를 활용해 배열과 컬렉션을 함수형으로 간단하게 처리할 수 있는 기술이다.
기존의 for문과 Iterator를 사용하면 코드가 길어져서 가독성과 재사용성이 떨어지며 데이터 타입마다 다른 방식으로 다뤄야 하는 불편함이 있다.
스트림은 데이터 소스를 추상화하고, 데이터를 다루는데 자주 사용되는 메소드를 정의해 놓아서 데이터 소스에 상관없이 모두 같은 방식으로 다룰 수 있으므로 코드의 재사용성이 높아진다.
Stream<Integer>
대신 IntStream
이 제공되어서 오토박싱과 언박싱 등의 불필요한 과정이 생략되고 숫자의 경우 유용한 메소드를 추가로 제공한다. (.sum()
, .average()
등)String[] arr = new String[]{"a", "b", "c"};
Stream<String> stream = Arrays.stream(arr);
List<String> list = Arrays.asList("a","b","c");
Stream<String> stream = list.stream();
Stream<String> builderStream = Stream.<String>builder()
.add("a").add("b").add("c")
.build();
Stream<String> generatedStream = Stream.generate(()->"a").limit(3);
// 생성할 때 스트림의 크기가 정해져있지 않기(무한하기)때문에 최대 크기를 제한해줘야 한다.
Stream<Integer> iteratedStream = Stream.iterate(0, n->n+2).limit(5); //0,2,4,6,8
IntStream intStream = IntStream.range(1, 5); // [1, 2, 3, 4]
Stream<String> parallelStream = list.parallelStream();
스트림 내 요소들을 하나씩 평가해서 걸러내는 작업, if문 역할
List<String> list = Arrays.asList("a","b","c");
Stream<String> stream = list.stream()
.filter(list -> list.contains("a"));
// 'a'가 들어간 요소만 선택 [a]
람다식의 리턴값은 boolean이고 true인 경우만 다음 단계 진행
스트림 내 요소들을 하나씩 특정 값으로 변환하는 작업, 값을 변환하기 위한 람다를 인자로 받는다.
스트림을 원하는 모양의 새로운 스트림으로 변환하고싶을 때 사용
Stream<String> stream = list.stream()
.map(String::toUpperCase);
//[A,B,C]
.map(Integers::parseInt);
// 문자열 -> 정수로 변환
스트림에 있는 값을 원하는 메소드에 입력값으로 넣으면 메소드 실행 결과(반환 값)가 담긴다.
스트림 내 요소들을 정렬하는 작업, Comparator 사용
Stream<String> stream = list.stream()
.sorted() // [a,b,c] 오름차순 정렬
.sorted(Comparator.reverseOrder()) // [c,b,a] (내림차순)
List<String> list = Arrays.asList("a","bb","ccc");
Stream<String> stream = list.stream()
.sorted(Comparator.comparingInt(String::length)) // [ccc,bb,a] //문자열 길이 기준 정렬
Stream<String> stream = list.stream()
.distinct() // 중복 제거
.limit(max) // 최대 크기 제한
.skip(n) // 앞에서부터 n개 skip하기
.peek(System.out::println) // 중간 작업결과 확인
기본형 타입을 사용하는 경우 스트림 내 요소들로 최소, 최대, 합, 평균 등을 구하는 연산을 수행할 수 있다.
IntStream stream = list.stream()
.count() //스트림 요소 개수 반환
.sum() //스트림 요소의 합 반환
.min() //스트림의 최소값 반환
.max() //스트림의 최대값 반환
.average() //스트림의 평균값 반환
스트림의 요소를 하나씩 줄여가며 누적연산을 수행
IntStream stream = IntStream.range(1,5);
.reduce(10, (total,num)->total+num);
//reduce(초기값, (누적 변수,요소)->수행문)
// 10 + 1+2+3+4+5 = 25
스트림의 요소를 원하는 자료형으로 변환
//예시 리스트
List<Person> members = Arrays.asList(new Person("lee",26),
new Person("kim", 23),
new Person("park", 23));
// toList() - 리스트로 반환
members.stream()
.map(Person::getLastName)
.collect(Collectors.toList());
// [lee, kim, park]
// joining() - 작업 결과를 하나의 스트링으로 이어 붙이기
members.stream()
.map(Person::getLastName)
.collect(Collectors.joining(delimiter = "+" , prefix = "<", suffix = ">");
// <lee+kim+park>
//groupingBy() - 그룹지어서 Map으로 반환
members.stream()
.collect(Collectors.groupingBy(Person::getAge));
// {26 = [Person{lastName="lee",age=26}],
// 23 = [Person{lastName="kim",age=23},Person{lastName="park",age=23}]}
//collectingAndThen() - collecting 이후 추가 작업 수행
members.stream()
.collect(Collectors.collectingAndThen (Collectors.toSet(),
Collections::unmodifiableSet));
//Set으로 collect한 후 수정불가한 set으로 변환하는 작업 실행
특정 조건을 만족하는 요소가 있는지 체크한 결과를 반환: anyMatch(하나라도 만족하는 요소가 있는지), allMatch(모두 만족하는지), noneMatch(모두 만족하지 않는지)
List<String> members = Arrays.asList("Lee", "Park", "Hwang");
boolean matchResult = members.stream()
.anyMatch(members->members.contains("w")); //w를 포함하는 요소가 있는지, True
boolean matchResult = members.stream()
.allMatch(members->members.length() >= 4); //모든 요소의 길이가 4 이상인지, False
boolean matchResult = members.stream()
.noneMatch(members->members.endsWith("t")); //t로 끝나는 요소가 하나도 없는지, True
forEach로 스트림을 돌면서 실행되는 작업
members.stream()
.map(Person::getName)
.forEach(System.out::println);
//결과를 출력 (peek는 중간, forEach는 최종)
스트림에서 하나의 요소를 반환
Person person = members.stream()
.findAny() //먼저 찾은 요소 하나 반환, 병렬 스트림의 경우 첫번째 요소가 보장되지 않음
.findFirst() //첫번째 요소 반환
Java Stream API는 왜 for-loop보다 느릴까?