-
Java 8 - 3. Stream공부일기/Java 8 2020. 12. 16. 16:35
1. Stream
연속된 데이터를 처리하는 Operation들의 모음.
스트림은 데이터를 담고 있는 저장소가 아니며, 스트림으로 처리되는 데이터 소스는 변경되지 않는다.
오직 한 번만 처리하며 무제한일 수 있다.
중개 오퍼레이터와 종료 오퍼레이터로 나눌 수 있다.
중개 오퍼레이션
-
Stream을 리턴한다.
-
Stateless / Stateful 오퍼레이션으로 더 상세하게 구분할 수도 있다. (대부분은 Stateless지만 distinct나 sorted 처럼 이전 이전 소스 데이터를 참조해야 하는 오퍼레이션은 Stateful 오퍼레이션이다.)
-
filter, map, limit, skip, sorted, ...
종료 오퍼레이션
-
Stream을 리턴하지 않는다.
-
collect, allMatch, count, forEach, min, max, ...
2. Stream API
걸러내기
-
Filter(Predicate.not())
! 사용이 불가능 하기 때문에 Predicate.not()을 사용할 수 있다. -
예) 이름이 3글자 이상인 데이터만 새로운 스트림으로
package stream; import java.util.Arrays; import java.util.List; public class practice { public static void main(String[] args) { List<String> names = Arrays.asList("유비", "관우", "제갈공명", "사마천", "사마의"); names.stream().filter(practice::nameLengthisThree) .forEach(System.out::println); } private static boolean nameLengthisThree(String name) { return name.length() == 3; } }
사마천 사마의
아래는 메서드 레퍼런스로 변경한 코드 결과는 동일하다.
package stream; import java.util.Arrays; import java.util.List; import java.util.function.Predicate; public class practice { public static void main(String[] args) { List<String> names = Arrays.asList("유비", "관우", "제갈공명", "사마천", "사마의"); names.stream().filter(Predicate.not(practice::name)) .forEach(System.out::println); } private static boolean name(String name) { return name.length() == 4; } }
- 예) 이름이 4글자가 아닌 데이터만 새로운 스트림으로
package stream; import java.util.Arrays; import java.util.List; import java.util.function.Predicate; public class practice { public static void main(String[] args) { List<String> names = Arrays.asList("유비", "관우", "제갈공명", "사마천", "사마의"); names.stream().filter(Predicate.not(name->name.length()==4)) .forEach(System.out::println); } }
유비 관우 사마천 사마의
마찬가지로 아래는 위의 코드를 메서드 레퍼런스를 사용해 변경한 코드.
package stream; import java.util.Arrays; import java.util.List; import java.util.function.Predicate; public class practice { public static void main(String[] args) { List<String> names = Arrays.asList("유비", "관우", "제갈공명", "사마천", "사마의"); names.stream().filter(Predicate.not(practice::nameLengthisNotFour)) .forEach(System.out::println); } private static boolean nameLengthisNotFour(String name) { return name.length() == 4; } }
변경하기
-
Map(Function) 또는 FlatMap(Function)
package stream; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.stream.Collectors; public class practice { public static void main(String[] args) { List<Integer> scores = Arrays.asList(10,20,30,40,50,60,70,80,90,100); Collection<String> stringScore = scores.stream() .map(score -> score + "") .collect(Collectors.toList()); System.out.println(stringScore); } }
map()을 이용해 String 타입으로 변환시켜 새로운 리스트에 저장한 예제이다.
[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
flatmap()은 이중리스트를 스트림으로 보낼 때 각 리스트안의 요소들을 펼쳐 요소 하나하나가 스트림을 거쳐 지나갈 수 있게 만들어 주는 기능이다.
package stream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.stream.Collectors; public class practice { public static void main(String[] args) { List<Integer> mathScore = Arrays.asList(10,20,30); List<Integer> koreanScore = Arrays.asList(40,50,60); List<Integer> engScore = Arrays.asList(70,80,90); List<List<Integer>> subject = new ArrayList<>(); subject.add(mathScore); subject.add(koreanScore); subject.add(engScore); subject.stream().flatMap(Collection::stream) .forEach(System.out::println); } }
10 20 30 40 50 60 70 80 90
10 - 90까지 각 과목의 점수를 출력해주는 것을 확인할 수 있다. 이 메소드를 진작 알았더라면 우테코 3주차 미션에서 지하철 노선도 출력할 때 활용할 수 있었을텐데...
생성하기
-
generate(Supplier) 또는 Iterate(T seed, UnaryOperator)
-
예) 10부터 1씩 증가하는 무제한 숫자 스트림
package stream; import java.util.stream.Stream; public class practice { public static void main(String[] args) { Stream.iterate(10, i -> i+1) .forEach(System.out::println); } }
10 11 12 ...
-
예) 랜덤 int 무제한 스트림
package stream; import java.util.Random; import java.util.stream.Stream; public class practice { public static void main(String[] args) { Random random = new Random(); Stream.iterate(10, i -> random.nextInt() ) .forEach(System.out::println); } }
10 -860808916 297488868 1860616718 ...
제한하기
-
limit(long) 또는 skip(long)
그렇다면 생성 하는데 제한을 두려면 어떻게 해야 할까? -
예) 최대 5개의 요소가 담긴 스트림을 리턴한다.
package stream; import java.util.stream.Stream; public class practice { public static void main(String[] args) { Stream.iterate(10, i -> i+1) .limit(5) .forEach(System.out::println); } }
10 11 12 13 14
-
예) 앞에서 3개를 뺀 나머지 스트림을 리턴한다.
package stream; import java.util.stream.Stream; public class practice { public static void main(String[] args) { Stream.iterate(10, i -> i+1) .limit(5) .skip(3) .forEach(System.out::println); } }
13 14
- 예) 10부터 1씩 증가하는 무제한 스트림 중 최대 10개까지만 증가하는 스트림
package stream; import java.util.Random; import java.util.stream.Stream; public class practice { public static void main(String[] args) { Random random = new Random(); Stream.iterate(10, i -> i+1) .limit(10) .forEach(System.out::println); } }
10 11 12 ... 19
- 예) 10부터 1씩 증가하는 무제한 스트림 중 앞의 5개는 제외후 10개까지 증가하는 스트림
package stream; import java.util.Random; import java.util.stream.Stream; public class practice { public static void main(String[] args) { Random random = new Random(); Stream.iterate(10, i -> i+1) .skip(5) .limit(10) .forEach(System.out::println); } }
15 16 17 ... 24 // 10, 11, 12, 13, 14 // 5개는 skip하고 나머지의 것들을 10개 보여준다.
스트림에 있는 데이터가 특정 조건을 만족하는지 확인
-
anyMatch(), allMatch(), nonMatch()
이 스트림 메소드들은 우테코 과제를 진행하며 자연스럽게 자주 익히게 되었다. 하나라도 일치하는 경우, 전부 일치해야하는 경우, 하나도 일치하지 않는 경우를 의미힌다.
-
예) k로 시작하는 문자열이 있는지 확인한다. (true 또는 false를 리턴한다.)
package stream; import java.util.Arrays; import java.util.List; public class practice { public static void main(String[] args) { List<String> names = Arrays.asList("kim", "lee", "park", "kang"); boolean result = names.stream().anyMatch(name -> name.startsWith("k")); System.out.println(result); } }
true
-
예) 스트림에 있는 모든 값이 10보다 작은지 확인한다.
package stream; import java.util.Arrays; import java.util.List; public class practice { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1,3,5,10,15,20); boolean result = numbers.stream().allMatch(n -> n<10); System.out.println(result); } }
false
- 예) 스트림의 값 중 100이 있는지 확인한다.
package stream; import java.util.Arrays; import java.util.List; public class practice { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1,3,5,10,15,20); boolean result = numbers.stream().noneMatch(n -> n==100); System.out.println(result); } }
true
개수 세기
-
count()
-
예) 10보다 큰 수의 개수를 센다.
package stream; import java.util.Arrays; import java.util.List; public class practice { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1,3,5,10,15,20); long count = numbers.stream() .filter(number -> number>10) .count(); System.out.println(count); } }
2
반환 타입이 long인 것을 주의하자!!
스트림을 데이터 하나로 뭉치기
-
reduce(identity, BiFunction), collect(), sum(), max()
-
예) 모든 숫자 합 구하기
package stream; import java.util.Arrays; import java.util.List; public class practice { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1,3,5,10,15,20); System.out.println(numbers.stream().mapToInt(i->i).sum()); } }
54
-
예) 모든 데이터를 하나의 List 또는 Set에 옮겨 담기
package stream; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class practice { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1,3,5,10,15,20); List<Integer> numList = numbers.stream().collect(Collectors.toList()); System.out.println(numList); } }
[1, 3, 5, 10, 15, 20]
package stream; import java.util.Arrays; import java.util.List; import java.util.Set; import java.util.stream.Collectors; public class practice { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1,3,5,10,15,20); Set numList = numbers.stream().collect(Collectors.toSet()); System.out.println(numList); } }
[1, 3, 20, 5, 10, 15]
'공부일기 > Java 8' 카테고리의 다른 글
Java 8 - 6. Concurrent 프로그래밍과 Executors (0) 2020.12.24 Java 8 - 5. Date & Time (0) 2020.12.23 Java 8 - 4. Optional (0) 2020.12.22 Java 8 - 2. 인터페이스의 변화 (0) 2020.12.07 Java 8 - 1. 함수형 인터페이스와 람다 표현식 (0) 2020.12.06 -