728x90
Table of Contents
0. 이전 관련 포스팅
[java 기초] 람다와 스트림, 스트림의 이해와 생성(1 / 3)
Table of Contents 주의 :: 주인장 학습용 포스팅입니다. Stream API : 이론 학습에 어질어질한 파트일 수 밖에 없습니다.. Stream API : JDK 8때 도입되어 객체지향적 언어인 Java를 함수형으로 프로그래밍 할
doinitright.tistory.com
[java 기초] 람다와 스트림(2 / 3) - 람다식, java.util.function
Table of Contents 이전 포스팅에서 이어집니다. [java 기초] 람다와 스트림, 스트림의 이해와 생성(1 / 3) Table of Contents 주의 :: 주인장 학습용 포스팅입니다. Stream API : 이론 학습에 어질어질한 파트일
doinitright.tistory.com
오늘 포스팅 이후로, 스트림을 쓰고 말 것이다..
스트림의 생성
컬렉션 인터페이스 클래스
`stream` 메소드로 생성
* 주요 클래스 : `List, ArrayList, LinkedList, Vector, Stack, Queue, Set, HashSet, TreeSet`
ArrayList<String> list = new ArrayList<>(List.of("Hello", "World"));
Stream<String> listStream = list.stream();
Queue<String> queue = new LinkedList<>(List.of("Hello", "World"));
Stream<String> queueStream = queue.stream();
TreeSet<String> set = new TreeSet<>(List.of("Hello", "World"));
Stream<String> setStream = set.stream();
배열
`Arrays.stream` 메소드로 생성
String[] arr = new String[]{"Hello", "World"};
Stream<String> arrStream = Arrays.stream(arr);
기본 타입 특화 스트림 (int, long, double)
`IntStream, LongStream, DoubleStream` 클래스로 생성
IntStream intStream = IntStream.range(0, 4); // 0, 1, 2, 3
DoubleStream doubleStream = DoubleStream.of(1, 3, 5); // 1.0, 3.0, 5.0
LongStream longStream = LongStream.rangeClosed(0, 4); // 0, 1, 2, 3, 4
Pattern 생성
`Pattern.complie`
Stream<String> patternStream = Pattern.compile("챔피언")
.splitAsStream("챔피언 소리지르는 니가 챔피언 음악에 미치는 니가 챔피언 ");
patternStream.forEach(System.out::println); // out : 소리지르는 니가 \n 음악에 미치는 니가 \n
iterate : 초기값을 인수로 받아 규칙적인 값을 생성
`iterate` / `limit` 로 break를 걸어 크기 제한
IntStream iterateStream = IntStream.iterate(3, x -> x + 3).limit(3);
// out : 3, 6, 9
generate : 초기값, 인수 없이 일정한 값 생성
`generate` / `limit` 로 break를 걸어 크기 제한
IntStream generateStream = IntStream.generate(() -> 10).limit(2);
// out : 10, 10
concat : 두 스트림 연결
`concat` : 두 스트림을 연결합니다.
String[] arr = new String[]{"Hello", "World"};
Stream<String> arrStream = Arrays.stream(arr);
Queue<String> queue = new LinkedList<>(List.of("Hello", "World"));
Stream<String> queueStream = queue.stream();
Stream<String> concatStream = Stream.concat(arrStream, queueStream);
concatStream.forEach(System.out::println); // Hello \n World \n Hello \n World
스트림의 중간 연산
filter : 특정한 조건으로 필터링
Predicate<T> 함수형 인터페이스를 활용해 특정 조건에 맞는 스트림 내 요소들을 필터링합니다.
ArrayList<String> list = new ArrayList<>(List.of("Hello", "World"));
Stream<String> listStream = list.stream();
Queue<String> queue = new LinkedList<>(List.of("Hello", "World"));
Stream<String> queueStream = queue.stream();
listStream.filter(s -> s.contains("H")).forEach(System.out::println); // out : Hello
queueStream.filter(s -> s.length() == 5).forEach(System.out::println); // out : Hello, World
map : 특정한 형태로 변환
Function<T> 함수형 인터페이스를 활용해 스트림 내 요소들을 특정 형태로 변환시킵니다.
TreeSet<String> set = new TreeSet<>(List.of("Hello", "World"));
Stream<String> setStream = set.stream();
setStream.map(String::toLowerCase).forEach(System.out::println); // out : hello \n world
String[] arr = new String[]{"Hello", "World"};
Stream<String> arrStream = Arrays.stream(arr);
arrStream.map(s -> s + "!").forEach(System.out::println); // out : Hello! \n World!
maptoInt / Long / Double : 기본 타입 특화 스트림 변환
해당 스트림을 특정 기본 타입으로 매핑합니다.
기본 데이터 타입에 특화된 스트림 변환이 가능하며, 박싱 비용 절감 효과가 있습니다.
`intStream은 mapToInt` / `LongStream은 mapToLong` / `DoubleStream은 mapToDouble` 사용불가
int[] intArr = new int[]{1, 2, 3, 4, 5};
IntStream intStream1 = Arrays.stream(intArr);
intStream1.filter(i -> i < 4).max().stream().
mapToDouble(v -> v+1).forEach(System.out::println); // out : 4.0
String[] strArr = new String[]{"1", "3", "5", "7", "9"};
int max = Arrays.stream(strArr).mapToInt(Integer::parseInt).max().getAsInt();
System.out.println(max); // out : 9
max()의 경우 단일의 값을 리턴하므로 getAsInt()를 통해 int값을 리턴받습니다.
flatMap: N차원 배열, 리스트 등을 단일 차원 구조로 변환
n차원으로 선언된 배열, n차원 리스트 등 중첩되어 있는 구조를 없애고 단일 구조로 변환시킵니다.
List<String> list1 = List.of("Alpha", "Beta");
List<String> list2 = List.of("Charlie", "Delta");
List<List<String>> list3 = List.of(list1, list2);
System.out.println(list3); // out : [Alpha, Beta], [Charlie, Delta]
List<String> list4 = list3.stream().flatMap(Collection::stream).toList();
System.out.println(list4); // out : Alpha, Beta, Charlie, Delta
sorted : 정렬하기
stream 내부 요소를 정렬합니다.
`sorted` 내부에는 `comparator, comparable` 을 활용한 정렬 패턴 설정 및 역순 정렬 등이 가능합니다.
`IntStream, DoubleStream, LongStream` 기본형 스트림은 `.boxed()` 로 래퍼 클래스 스트림 변환 후 사용합니다.
List<String> sortedList =
List.of("Alpha", "Delta", "Charlie", "Beta").stream().sorted().toList();
System.out.println(sortedList); // out : Alpha, Beta, Charlie, Delta
List<Integer> sortedIntList =
IntStream.range(0, 10).boxed().sorted(Comparator.reverseOrder()).toList();
System.out.println(sortedIntList); // out : 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
peek : 중간 연산 결과를 중간 확인
스트림의 중간 요소에 대한 연산을 수행합니다.
연산 과정에서 요소를 소모하지 않으므로 통상 중간 연산 사이의 결과를 확인할 때 많이 사용됩니다.
최종 연산이 실행되지 않으면 `peek`를 사용할 수 없습니다.
double d = IntStream.range(0, 5)
.filter(i -> i < 4)
.mapToDouble(i -> i + 1)
.peek(i -> System.out.print("중간: " + i + " "))
.max().orElse(-1); // 최종 연산 없을 시 peek 에러
System.out.println("최종: "+ d); // out : 중간: 1.0 중간: 2.0 중간: 3.0 중간: 4.0 최종: 4.0
limit / skip : 특정 요소 생략 / 개수 제한 하기
`skip` : 스트림 내 특정 요소를 일정 개수만큼 건너뛰는 연산을 수행합니다.
List<String> skipList = List.of("Alpha", "Beta", "Charlie", "Delta")
.stream().skip(2).toList();
System.out.println(skipList); // out : Charlie, Delta
`limit` : 일정 수만큼 스트림 내 요소의 개수를 제한하는 연산을 수행합니다.
List<String> limitList = List.of("Alpha", "Beta", "Charlie", "Delta") .stream().limit(2).toList(); System.out.println(limitList); // out : Alpha, Beta
스트림의 최종 연산
forEach, forEachOrdered : 요소 순회
`forEach` : 요소를 순회합니다. (병렬 스트림에서 순서 보장 X)
`forEachOrdered` : 병렬 스트림에 사용합니다. (병렬 스트림에서 순서 보장 O)
List.of("눈","누","난","나").parallelStream().forEach(System.out::println);
// out : 난 \n 나 \n 눈 \n 누 (순서 보장 X)
List.of("눈","누","난","나").parallelStream().forEachOrdered(System.out::println);
// out : 눈 \n 누 \n 난 \n 나 (순서 보장 O)
reduce : 결과 합치기
연산 규칙을 정의해 스트림 요소를 정의하여 결과를 합칩니다.
reduce는 총 3가지 형태를 가지고 있으며 각 형태마다 다른 연산을 정의할 수 있습니다.
1개의 인자를 받는 형태 : 인자로 `BinaryOperator` 를 사용합니다.
`BinaryOperator` : 두 개의 동일 타입 요소 → 동일한 타입의 결과를 리턴합니다.
int reduce1 = IntStream.rangeClosed(1, 5).reduce((a, b) -> a + b).getAsInt()
System.out.println(reduce1); // out : 15 (1 + 2 + 3 + 4 + 5)
2개의 인자를 받는 형태 : 인자로 `BinaryOperator` 와 `항등값` 을 사용합니다.
`BinaryOperator` : 두 개의 동일 타입 요소 → 동일한 타입의 결과를 리턴합니다.
`항등값` : 항상 동일한 값입니다.
int reduce2 = IntStream.rangeClosed(1, 5).reduce(3, (a, b) -> a + b);
System.out.println(reduce2); // out : 18 (3 , 1 + 2 + 3 + 4 + 5)
3개의 인자를 받는 형태 : 인자로 `BinaryOperator` 와 `항등값`, 'BiFunction' 을 사용합니다.
`BinaryOperator` : 두 개의 동일 타입 요소 → 동일한 타입의 결과를 리턴합니다.
`항등값` : 항상 동일한 값입니다.
`BiFunction` : 값 누계 연산에 사용합니다.
int num1 = 5, num2 = 10, num3 = 15;
int result = Stream.of(num1, num2, num3)
.reduce(0, (acc, value) -> acc + value, Integer::sum);
// 초기값 : 0, 첫번째 인자 5
// acc, value : 현재까지 누산된 결과 acc와 스트림 각 요소 value를 더함
// Integer::sum : 누산된 결과를 더함
// 0 + 5 = 5
// 5 + 10 = 15
// 15 + 15 = 30
System.out.println(result); // out : 30
* 일반적으로 3개의 인자를 받는 형태의 연산은 병렬 스트림에서 사용됩니다.
* 일반 스트림과 병렬 스트림의 연산 값이 상이합니다.
min, max, average, count : 한 개의 결과 리턴(최소, 최대, 평균, 개수 등)
기본 산술 연산을 제공합니다.
IntStream, DoubleStream, LongStream 등에서 동작하거나,
다른 stream은 연산을 위해 해당 원시타입 (int, long, double) 으로 매핑이 필요합니다.
ArrayList<Integer> list = new ArrayList<>(List.of(1, 2, 3, 4, 5));
// count
System.out.println(list.stream().count()); // out : 5
// max
System.out.println(list.stream().mapToInt(i->i).max().getAsInt()); // out : 5
// min
System.out.println(list.stream().mapToInt(i->i).min().getAsInt()); // out : 1
// average
System.out.println(list.stream().mapToDouble(i->i).average().getAsDouble()); // out : 3.0
anyMatch, allMatch, noneMatch : 요소의 참, 거짓 조건 확인
`anyMatch` : 하나라도 조건을 만족하는 요소가 있으면 true / 아니면 false를 리턴합니다.
`allMatch` : 모든 요소가 조건을 만족하면 true / 아니면 false를 리턴합니다.
`noneMatch` : 모든 요소가 조건을 만족하지 않으면 true / 아니면 fasle를 리턴합니다.
ArrayList<Integer> list = new ArrayList<>(List.of(1, 2, 3, 4, 5));
// anyMatch
System.out.println(list.stream().anyMatch(i -> i < 1)); // out : false
// allMatch
System.out.println(list.stream().allMatch(i -> i > 0)); // out : true
// noneMatch
System.out.println(list.stream().noneMatch(i -> i > 5)); // out : true
Collectors : 분량 조절 실패로 다음 포스팅에서 이어집니다.
제길 졸업하지 못했어!
# 구현 코드
'DEV > Java' 카테고리의 다른 글
[Java][lombok] @ToString에 대한 이해와 적용 (0) | 2023.11.14 |
---|---|
[java] 가변 인자(variable args) 설명 및 예시 (1) | 2023.11.10 |
[java 기초] json.simple 활용 JSON 데이터 저장, 불러오기 (0) | 2023.10.25 |
[java 기초] NoSuchElementException 예외의 이해와 발생사례 (1) | 2023.10.25 |
[java 기초] JVM 메모리 구조와 변수별 메모리 할당 (0) | 2023.10.23 |