반응형
반응형
해당 글의 목적은 Stream API를 이해하고 예제를 통한 이해를 돕기 위해 작성한 글입니다. 주된 내용은 이전에 작성한 Stream 생성을 기반으로 Stream의 중간연산인 조작과 관련된 메서드에 대해서 이해합니다. 해당 글에서는 모든 함수에 대해서는 포함하고 있지 않으며 자주 사용되는 메서드 위주로 작성하였습니다.
[참고] Stream API에 대한 이해와 Stream 생성 방법에 대해서 궁금하시다면 이전에 글을 참고하시면 좋을 것 같습니다.
1) Stream의 구성 과정
💡 Stream의 객체를 구성하고자 할 때 "Stream 생성 → 중간 연산→ 최종 연산" 의 세 단계의 과정을 통하여서 Stream의 구성이 이루어집니다. 해당 글에서 과정은 “중간 연산” 부분에 해당됩니다.
// 객체의 Stream을 생성하고 중간 연산을 수행하고 최종 연산을 하여 결과값을 얻습니다.
객체.Stream생성().중간연산.최종연산()
2) Stream 중간연산
1. 요약
분류 | 상세 분류 | 설명 |
Stream 필터 | filter(), distinct() | - filter()는 구성한 스트림 내에서 특정 조건에 맞는 결과값을 필터링 하기 위해 사용됩니다. - distinct()는 구성한 스트림 내에서 중복을 제거한 결과값을 반환하기 위해 사용됩니다. |
Stream 변환 | map(), flatMap() | - map()은 구성한 스트림 내에서 요소들을 원하는 값으로 변환하여서 반환하기 위해 사용됩니다. - flatMap()는 구성한 스트림 내에서 중복된 스트림을 평면화(flattern)하여 요소를 구성하여 반환하기 위해 사용됩니다. |
Stream 제한 | limit(), skip() | - limit()는 구성한 스트림 내에서 요소의 개수를 제한하여 반환해주기 위한 목적으로 사용됩니다. - skip()는 구성한 스트림 내에서 시작부터 특정 n개의 요소를 제외하여 반환해주는 목적으로 사용합니다. |
Stream 정렬 | sorted() | - sorted()는 구성한 스트림 내에서 배열 혹은 리스트 그리고 Object의 요소에 대해서 오름/내림 차순을 수행하여 반환해주는 함수입니다. |
Stream 연산 결과 확인 | peek() | - peek()는 구성한 스트림 내에서 각각의 요소를 조회하는 연산자료 요소 자체를 추출하는것이 아닌 스트림의 요소를 조회하는 함수입니다. |
3) Stream 중간연산 상세
1. Stream 필터 : filter()
💡 해당 함수는 구성한 스트림 내에서 특정 조건에 맞는 결과값을 필터링하기 위해 사용됩니다.
(값을 조작을 하기 위해서는 사용하지 않고 요소 내에서 조건부 검색을 위한 목적을 사용이 됩니다.)
/*
* [CASE1] Array 이용한 방법
*/
// 1. Array Initialize
int[] filterIntArr = {1000, 2000, 3000, 5000};
// 2. Array to IntStream : 3000 이상의 값 filter
IntStream filterIntStream = Arrays.stream(filterIntArr).filter(item -> item >= 3000);
// 3. IntStream to Array
filterIntArr = filterIntStream.toArray(); // 결과값 반환 : [3000, 5000]
/*
* [CASE2] ArrayList 이용한 방법
*/
// 1. ArrayList Initialize
List<String> filterStrList = new ArrayList<>(Arrays.asList("kim", "lee", "park", "lee", "jung"));
// 2. ArrayList to Stream<String> : 리스트 내에 "lee"가 존재하는 배열을 찾습니다.
Stream<String> filterStrStream = filterStrList.stream().filter(item -> item.equals("lee"));
// 3. Stream<String> to ArrayList
filterStrList = filterStrStream.collect(Collectors.toList()); // 결과값 반환 : ["lee", "lee"]
/*
* [CASE3] Object 이용한 방법
*/
// 1. Object ArrayList Initialize
List<UserDto> filterUserDtoList = Arrays.asList(
UserDto.userBuilder().userId("adjh54").userNm("lee").userPw("1234").userSt("S").build(),
UserDto.userBuilder().userId("ckask123").userNm("kim").userPw("4321").userSt("A").build()
);
// 2. Object to Stream<Object> : 사용자 상태가 "S"인 Object 를 찾습니다.
Stream<UserDto> filterUserDtoStream = filterUserDtoList.stream().filter(item -> item.getUserSt().equals("S"));
// 3. Stream<Object> to ArrayList
filterUserDtoList = filterUserDtoStream.collect(Collectors.toList()); // 결과값 반환: List<UserDto> 2
[참고] Object 이용한 방법의 결과값 - filterUserDtoList
2. Stream 필터 : distinct()
💡 해당 함수는 구성한 스트림 내에서 중복을 제거한 결과값을 반환하기 위해 사용됩니다.
/*
* [CASE1] Array 이용한 방법
*/
// 1. Array Initialize
int[] distinctIntArr = {1000, 5000, 5000, 7000, 12000, 12000};
// 2. Array to IntStream : Array 내에 중복되는 요소 제거
IntStream distinctIntStream = Arrays.stream(distinctIntArr).distinct();
// 3. InputStream to Array
distinctIntArr = distinctIntStream.toArray(); // 결과값 반환 : [1000, 5000, 7000, 12000]
/*
* [CASE2] ArrayList 이용한 방법
*/
// 1. ArrayList Initialize
List<String> distinctStrList = new ArrayList<>(Arrays.asList("kim", "lee", "park", "lee", "jung"));
// 2. Array to IntStream : ArrayList 내에 중복되는 요소 제거
Stream<String> distinctStrStream = distinctStrList.stream().distinct();
// 3. InputStream to Array
distinctStrList = distinctStrStream.collect(Collectors.toList()); // 결과값 반환 : ["kim", "lee", "park", "jung"]
/*
* [CASE3] Object 이용한 방법
*/
// 1. Object ArrayList Initialize
List<UserDto> distinctUserDtoList = Arrays.asList(
UserDto.userBuilder().userId("adjh54").userNm("lee").userPw("1234").userSt("S").build(),
UserDto.userBuilder().userId("ckask123").userNm("kim").userPw("4321").userSt("S").build()
);
// 2. Object to Stream<Object> : 객체간의 중복되는 요소를 확인.
Stream<UserDto> distinctUserDtoStream = distinctUserDtoList.stream().distinct();
// 3. Stream<Object> to ArrayList
distinctUserDtoList = distinctUserDtoStream.collect(Collectors.toList()); // 결과값 반환: 동일한 객체가 아니므로 구성한 모든 객체가 리스트로 반환이 됩니다.
[참고] Object 이용한 방법의 결과값 - distinctUserDtoList
3. Stream 변환 : map()
💡 해당 함수는 구성한 스트림 내에서 요소들을 원하는 값으로 변환하여서 반환하기 위해 사용됩니다.
💡 요소 내에서 조건부 검색을 위한 목적으로 사용하는 filter와 다르게 요소를 조작하여서 반환을 해줍니다.
[참고] map() 메서드 외에 즉시 캐스팅 메서드
메서드 | 타입 |
map() | Any |
mapToObj() | Object |
mapToLong() | Long |
mapToDouble() | Double |
1. 활용방안 1 - 일반적인 사용 방안
/*
* [CASE1] Array 이용한 방법
*/
// 1. Array Initialize
int[] mapIntArr = {1000, 5000, 7000, 12000};
// 2. Array to IntStream : 배열 요소 값이 7000 이상일 경우에만 3000을 더해서 반환합니다.
IntStream mapIntStream = Arrays.stream(mapIntArr).map(item -> item >= 7000 ? item + 3000 : item);
// 3. InputStream to Array
mapIntArr = mapIntStream.toArray(); // 결과값 반환 : [1000, 5000, 10000, 15000]
/*
* [CASE2] ArrayList 이용한 방법
*/
// 1. ArrayList Initialize
List<String> mapStrList = new ArrayList<>(Arrays.asList("kim", "lee", "park", "lee", "jung"));
// 2. ArrayList to Stream<String>
Stream<String> strMapStream = mapStrList.stream().map(item -> "name ::" + item);
// 3. Stream<String> to ArrayList
mapStrList = strMapStream.collect(Collectors.toList()); // 결과값 반환 : ["name ::kim", "name ::lee", "name ::park", "name ::lee", "name ::jung"]
/*
* [CASE3] Object 이용한 방법
*/
// 1. Object ArrayList Initialize
List<UserDto> mapUserDtoList = Arrays.asList(
UserDto.userBuilder().userId("adjh54").userNm("lee").userPw("1234").userSt("S").build(),
UserDto.userBuilder().userId("ckask123").userNm("kim").userPw("4321").userSt("S").build()
);
// 2. Object to Stream<Object>
Stream<UserDto> userDtoMapStream = mapUserDtoList.stream().map(item -> {
return item.toBuilder().userNm("MyName is " + item.getUserNm()).build();
});
// 3. Stream<Object> to ArrayList
mapUserDtoList = userDtoMapStream.collect(Collectors.toList()); // 결과값 반환: List<UserDto> 2
[참고] Object 이용한 방법의 결과값 - mapUserDtoList
2. 활용방안2 - toUpperCase / toLowerCase를 활용한 방안
// map을 이용한 소문자를 대문자로 전환 작업
String[] toLowerCaseArr = {"one", "two", "three"};
Stream<String> upperCaseStream = Arrays.stream(toLowerCaseArr).map(String::toUpperCase);
4. Stream 변환: flatMap()
💡 해당 함수는 구성한 스트림 내에서 중복된 스트림을 평면화(flattern)하여 요소를 구성하여 반환하기 위해 사용됩니다. 중복된 구조의 리스트를 하나의 평면화된 리스트로 반환을 받습니다.
[참고] flatMap() 메서드 외에 즉시 캐스팅 메서드
Mehtod | type |
flatMap() | String |
flatMapToInt() | int |
flatMapToDouble() | double |
flatMapToLong() | long |
/*
* [CASE1] 2차원 int Array 이용한 방법
*/
// 1. 2차원 intArray Initialize
int[][] int2Dimension = {{1, 2}, {3, 4}, {5, 6}};
// 2. 2차원 intArray to 1차원 intArray
int[] flatMapIntArr = Arrays.stream(int2Dimension).flatMapToInt(Arrays::stream).toArray(); // 결과값 반환: [1, 2, 3, 4, 5, 6]
/*
* [CASE2] 2차원 string Array 이용한 방법
*/
// 1. 2차원 stringArray Initialize
String[][] str2Dimension = {{"one", "two"}, {"three", "four"}, {"five", "six"}};
// 2. 2차원 stringArray Initialize to 1차원 object Array
Object[] flatMapObjectArr = Arrays.stream(str2Dimension).flatMap(Arrays::stream).toArray(); // 결과값 반환: ["one, "two", "three", "four", "five", "six")
/*
* [CASE3] Object 이용한 방법
*/
// 1. Object ArrayList Initialize
List<UserDto> limitUserDtoList = Arrays.asList(
UserDto.userBuilder().userId("adjh54").userNm("lee").userPw("1234").userSt("S").build(),
UserDto.userBuilder().userId("ckask123").userNm("kim").userPw("4321").userSt("S").build(),
UserDto.userBuilder().userId("fjdsl3").userNm("park").userPw("5678").userSt("S").build(),
UserDto.userBuilder().userId("jklasd").userNm("jung").userPw("8765").userSt("S").build()
);
// 2. Object to Stream<Object>
Stream<UserDto> limitUserDtoStream = limitUserDtoList.stream().limit(2);
// 3. Stream<Object> to ArrayList
limitUserDtoList = limitUserDtoStream.collect(Collectors.toList()); // 결과값 반환: List<UserDto> 3
5. Stream 제한 : limit()
💡 해당 함수는 구성한 스트림 내에서 요소의 개수를 제한하여 반환해 주기 위한 목적으로 사용됩니다.
/*
* [CASE1] Array 이용한 방법
*/
// 1. Array Initialize
int[] limitIntArr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// 2. Array to IntStream : 4개의 요소만 출력되도록 한다.
IntStream limitIntStream = Arrays.stream(limitIntArr).limit(4);
// 3. InputStream to Array
limitIntArr = limitIntStream.toArray(); // [1, 2, 3, 4]
/*
* [CASE2] ArrayList 이용한 방법
*/
// 1. ArrayList Initialize
List<String> limitStrList = new ArrayList<>(Arrays.asList("one", "two", "three", "four", "five"));
// 2. ArrayList to Stream<String>
Stream<String> limitStrStream = limitStrList.stream().limit(4);
// 2. InputStream to Array
limitStrList = limitStrStream.collect(Collectors.toList()); // ["one", "two", "three", "four"]
/*
* [CASE3] Object 이용한 방법
*/
// 1. Object ArrayList Initialize
List<UserDto> limitUserDtoList = Arrays.asList(
UserDto.userBuilder().userId("adjh54").userNm("lee").userPw("1234").userSt("S").build(),
UserDto.userBuilder().userId("ckask123").userNm("kim").userPw("4321").userSt("S").build(),
UserDto.userBuilder().userId("fjdsl3").userNm("park").userPw("5678").userSt("S").build(),
UserDto.userBuilder().userId("jklasd").userNm("jung").userPw("8765").userSt("S").build()
);
// 2. Object to Stream<Object>
Stream<UserDto> limitUserDtoStream = limitUserDtoList.stream().limit(2);
// 3. Stream<Object> to ArrayList
limitUserDtoList = limitUserDtoStream.collect(Collectors.toList()); // 결과값 반환: List<UserDto> 2
[참고] Object 이용한 방법의 결과값 - limitUserDtoList
6. Stream 제한: skip()
💡 해당 함수는 구성한 스트림 내에서 시작부터 특정 n개의 요소를 제외하여 반환해 주는 목적으로 사용합니다.
/*
* [CASE1] Array 이용한 방법
*/
// 1. Array Initialize
int[] skipIntArr = {1, 2, 3, 4, 5, 6, 7, 8};
// 2. Array to IntStream : 배열 내에서 인덱스 순서대로 2개의 값을 제외한 결과값을 반환합니다.
IntStream skipIntStream = Arrays.stream(skipIntArr).skip(2);
// 3. InputStream to Array
skipIntArr = skipIntStream.toArray(); // [3, 4, 5, 6, 7, 8]
/*
* [CASE2] ArrayList 이용한 방법
*/
// 1. ArrayList Initialize
List<String> skipStrList = new ArrayList<>(Arrays.asList("one", "two", "three", "four", "five"));
// 2. InputStream to Array : 리스트 내에서 인덱스 순서대로 4개의 값을 제외한 결과값을 반환합니다.
Stream<String> skipStrStream = skipStrList.stream().skip(4);
// 3. InputStream to Array
skipStrList = skipStrStream.collect(Collectors.toList()); // ["five"]
/*
* [CASE3] Object 이용한 방법
*/
// 1. Object ArrayList Initialize
List<UserDto> skipUserDtoList = Arrays.asList(
UserDto.userBuilder().userId("adjh54").userNm("lee").userPw("1234").userSt("S").build(),
UserDto.userBuilder().userId("ckask123").userNm("kim").userPw("4321").userSt("S").build(),
UserDto.userBuilder().userId("fjdsl3").userNm("park").userPw("5678").userSt("S").build(),
UserDto.userBuilder().userId("jklasd").userNm("jung").userPw("8765").userSt("S").build()
);
// 2. Object to Stream<Object> : 리스트 내에서 인덱스 순서대로 2개의 값을 제외한 결과값을 반환합니다.
Stream<UserDto> skipUserDtoStream = skipUserDtoList.stream().skip(2);
// 3. Stream<Object> to ArrayList
skipUserDtoList = skipUserDtoStream.collect(Collectors.toList()); // 결과값 반환: List<UserDto> 2
[참고] Object 이용한 방법의 결과값 - skipUserDtoList
7. Stream 정렬: sorted()
💡 해당 함수는 구성한 스트림 내에서 배열 혹은 리스트 그리고 Object의 요소에 대해서 오름/내림 차순을 수행하여 반환해 주는 함수입니다.
/*
* [CASE1] Array 이용한 방법
*/
// 1. Array Initialize
int[] sortNumArr1 = {10, 11, 1, 2, 4};
int[] sortNumArr2 = {0, 1, 2, 3, 4};
// 2.1. Array to IntStream : 배열을 오름차순으로 정렬합니다.
IntStream sortAscIntStreamType1 = Arrays.stream(sortNumArr1).sorted();
// 2.2. Array to Stream<Integer> : 배열을 내림차순으로 정렬합니다.
Stream<Integer> sortDescIntStreamType1 = Arrays.stream(sortNumArr1).boxed().sorted(Comparator.reverseOrder());
Stream<Integer> sortDescIntStreamType2 = Arrays.stream(sortNumArr2).boxed().sorted((a, b) -> b - a);
// 3.1. IntStream to int[]
int[] resultSortedNumArr1 = sortAscIntStreamType1.toArray(); // 결과값 반환(오름차순) : [1, 2, 4, 10, 11]
// 3.2. Stream<Integer> to int[]
int[] resultSortedNumArr2 = sortDescIntStreamType1.mapToInt(i -> i).toArray(); // 결과값 반환(내림차순) : [11, 10, 4, 2, 1]
int[] resultSortedNumArr3 = sortDescIntStreamType2.mapToInt(i -> i).toArray(); // 결과값 반환(내림차순) : [4, 3, 2, 1, 0]
/*
* [CASE2] ArrayList 이용한 방법
*/
// 1. ArrayList Initialize
List<String> sortedStrList1 = new ArrayList<>(Arrays.asList("aaa", "bbb", "ccc", "ddd", "AAA"));
List<String> sortedStrList2 = new ArrayList<>(Arrays.asList("apple", "banana", "cherry"));
List<String> sortedStrList3 = new ArrayList<>(Arrays.asList("f", "b", "z"));
// 2.1. ArrayList to Stream<String> : 리스트를 오름 차순으로 정렬합니다.
Stream<String> sortedStrStream1 = sortedStrList1.stream().sorted(Comparator.naturalOrder());
// 2.2. ArrayList to Stream<String> : 리스트를 오름 차순으로 정렬합니다.
Stream<String> sortedStrStream2 = sortedStrList2.stream().sorted(Comparator.reverseOrder());
Stream<String> sortedStrStream3 = sortedStrList3.stream().sorted((a, b) -> b.compareTo(a));
// 3.1. Stream<String> to List<String>
sortedStrList1 = sortedStrStream1.collect(Collectors.toList()); // 결과값 반환(오름차순) : ["AAA", "aaa", "bbb", "ccc", "ddd"]
sortedStrList2 = sortedStrStream2.collect(Collectors.toList()); // 결과값 반환(오름차순) : ["cherry", "banana", "apple"]
sortedStrList3 = sortedStrStream3.collect(Collectors.toList()); // 결과값 반환(오름차순) : ["z", "f", "d"]
/*
* [CASE3] Object 이용한 방법
*/
// 1. Object ArrayList Initialize
List<UserDto> sortedUserDtoList = Arrays.asList(
UserDto.userBuilder().userId("adjh54").userNm("lee").userPw("1234").userSt("S").build(),
UserDto.userBuilder().userId("ckask123").userNm("kim").userPw("4321").userSt("S").build(),
UserDto.userBuilder().userId("fjdsl3").userNm("park").userPw("5678").userSt("S").build()
);
// 2.1. Object to Stream<Object> : 리스트 내에서 userNm을 기준으로 오름차순으로 정렬합니다.
Stream<UserDto> sortedAscUserDtoStream = sortedUserDtoList.stream().sorted(Comparator.comparing(UserDto::getUserNm));
// 2.2. Object to Stream<Object> : 리스트 내에서 userNm을 기준으로 내림차순으로 정렬합니다.
Stream<UserDto> sortedDescUserDtoStream = sortedUserDtoList.stream().sorted(Comparator.comparing(UserDto::getUserNm).reversed());
// 3. Stream<Object> to ArrayList
List<UserDto> sortedAscUserDtoList = sortedAscUserDtoStream.collect(Collectors.toList()); // 결과값 반환: List<UserDto>
List<UserDto> sortedDescUserDtoList = sortedDescUserDtoStream.collect(Collectors.toList()); // 결과값 반환: List<UserDto>
[참고] Object 이용한 방법의 결과값 - sortedDescUserDtoList
[참고] Object 이용한 방법의 결과값 - sortedAscUserDtoList
8. Stream 연산 결과 확인: peek()
💡 해당 함수는 구성한 스트림 내에서 각각의 요소를 조회하는 연산자료 요소 자체를 추출하는 것이 아닌 스트림의 요소를 조회하는 함수입니다. 또한 해당 값은 스트림 그대로 반환하기에 다시 배열/리스트/객체 형태로 변환이 불가능합니다. peek() 함수를 사용하여 디버깅과 디버깅을 위한 중간 연산 결과값을 확인이 가능합니다.
/*
* [CASE1] Array 이용한 방법
*/
// 1. Array Initialize
int[] peekIntArr = {10, 11, 1, 2, 4};
// 2. Array to IntStream
IntStream peekIntStream = Arrays.stream(peekIntArr)
.peek(System.out::println)
.map(i -> i + 10)
.peek(i -> System.out.println("결과값 : " + i))
.map(i -> i + 10);
/*
* [CASE2] ArrayList 이용한 방법
*/
// 1. ArrayList Initialize
List<String> peekStrList = new ArrayList<>(Arrays.asList("apple", "banana", "cherry"));
// 2. Array to Stream<String>
Stream<String> peekStrStream = peekStrList.stream()
.peek(System.out::println)
.map(i -> "My " + i)
.peek(i -> System.out.println("결과값 : " + i))
.map(i -> i + " 입니다");
[참고] peekIntStream 결과값
[참고] peekStrList 결과값
오늘도 감사합니다. 😀
반응형
'Java > 공통 모듈' 카테고리의 다른 글
[Java] String, StringBuffer, StringBuilder 이해하기 (2) | 2023.02.26 |
---|---|
[Java] Stream API -3 이해하기: Stream 최종연산 (0) | 2023.02.14 |
[Java] Stream API -1 이해하기: 용어 및 Stream 생성 (4) | 2023.02.05 |
[Java] 배열(Array) 조작 함수 이해하기-1: 기본 구성, Arrays 함수 (0) | 2023.01.30 |
[Java] 문자열(String) 조작 함수 이해하기 : 조작 및 비교 함수 (2) | 2023.01.21 |