Java Stream?
자바의 Stream은 Java 8에서 도입된 기능으로, 데이터의 컬렉션을 처리하고 조작하는 데 유용하다.
Stream을 사용하면 데이터 처리 파이프라인을 구축할 수 있으며, 이는 코드의 가독성을 높이고 유지 보수를 하는데 도움을 준다.
Stream의 특징을 알아보자
1. 선언형 프로그래밍이 가능하다
- filter(), map(), collect()와 같은 메서드를 체이닝하여 사용할 수 있다.
- 명령형 프로그래밍 방식인 '어떻게'가 아닌 '무엇을' 할지를 표현한다.
ex) 상사가 부하직원에게 회원조회 API를 개발하라는 업무를 지시하는 상황
명령형 : OO님, 회원의 아이디 값을 요청받아서 DB Select SQL을 날려서 회원 정보를 추출한 다음 User라는 객체에 정보를 담아서 return 해주는 방법으로 API를 만들어주세요.
선언형 : OO님, 회원 정보를 return 해주는 API를 만들어주세요.
명령형은 '어떻게'라는 방식이 고정되어 있기 때문에 자율성이 떨어진다.
그러나 선언형의 경우 return 해주는 정보는 같지만 그 정보를 만드는 과정에 자율성이 있다는 점에서 재사용성이 좋다 고 볼 수 있다.
2. Stream은 저장소가 아니다.
- 스트림 자체는 데이터 저장소가 아니고 데이터 소스로부터 데이터를 읽고 처리하는 역할만 한다.
3. Stream은 데이터 소스에서 추출된 요소에서 시퀀스를 만들고 처리한다.
- 순차적으로 처리한다. Like for문(?)
4. Stream은 일회성이다.
- 최종 연산을 처리하면 Stream은 소멸된다.
- 다시 사용하려면 새로운 Stream을 생성해야 한다.
5. Stream은 병렬처리를 지원한다.
6. Stream은 중간연산과 최종연산이 있다.
- 중간 연산 (Intermediate Operations): 스트림을 변환하지만 새로운 스트림을 반환한다. 무한히 체이닝이 가능하다.
- 예: filter, map, flatMap, sorted, distinct, limit, skip
- 최종 연산 (Terminal Operations): 스트림을 닫고 결과를 반환하거나 부수 효과를 일으킵니다.
- 예: forEach, collect, reduce, count, findFirst, findAny, anyMatch, allMatch, noneMatch
중간연산
1. filter
- 설명: 스트림의 각 요소에 대해 주어진 조건(predicate)을 검사하고, 조건을 만족하는 요소만을 포함하는 새로운 스트림을 반환한다.
- 용도: 특정 조건에 맞는 요소들을 필터링할 때 사용한다.
- 예제:
List<String> list = Arrays.asList("apple", "banana", "cherry");
List<String> result = list.stream()
.filter(s -> s.startsWith("a"))
.collect(Collectors.toList());
// result: ["apple"]
2. map
- 설명: 스트림의 각 요소에 주어진 함수(function)를 적용하여 새로운 요소로 변환하고, 변환된 요소들로 구성된 새로운 스트림을 반환한다.
- 용도: 요소들을 변환할 때 사용한다.
- 예제:
List<String> list = Arrays.asList("apple", "banana", "cherry");
List<Integer> result = list.stream()
.map(String::length)
.collect(Collectors.toList());
// result: [5, 6, 6]
3. flatMap
- 설명: 스트림의 각 요소에 주어진 함수(function)를 적용하여 스트림을 생성하고, 생성된 여러 스트림을 하나의 스트림으로 평면화한다.
- 용도: 중첩된 구조를 평면화할 때 사용한다.
- 예제:
List<List<String>> list = Arrays.asList(
Arrays.asList("apple", "banana"),
Arrays.asList("cherry", "date")
);
List<String> result = list.stream()
.flatMap(Collection::stream)
.collect(Collectors.toList());
// result: ["apple", "banana", "cherry", "date"]
4. sorted
- 설명: 스트림의 요소들을 자연 순서(오름차순)나 제공된 비교자(comparator)에 따라 정렬하여 새로운 스트림을 반환한다.
- 용도: 요소들을 정렬할 때 사용한다.
- 예제:
List<String> list = Arrays.asList("cherry", "banana", "apple");
List<String> result = list.stream()
.sorted()
.collect(Collectors.toList());
// result: ["apple", "banana", "cherry"]
5. distinct
- 설명: 스트림의 요소들 중 중복된 요소를 제거하여 고유한 요소들로 구성된 새로운 스트림을 반환한다.
- 용도: 중복을 제거할 때 사용한다.
- 예제:
List<String> list = Arrays.asList("apple", "banana", "apple", "cherry");
List<String> result = list.stream()
.distinct()
.collect(Collectors.toList());
// result: ["apple", "banana", "cherry"]
6. limit
- 설명: 스트림의 처음 n개의 요소들만 포함하는 새로운 스트림을 반환한다.
- 용도: 요소의 개수를 제한할 때 사용한다.
- 예제:
List<String> list = Arrays.asList("apple", "banana", "cherry", "date");
List<String> result = list.stream()
.limit(2)
.collect(Collectors.toList());
// result: ["apple", "banana"]
7. skip
- 설명: 스트림의 처음 n개의 요소들을 건너뛰고 나머지 요소들로 구성된 새로운 스트림을 반환한다.
- 용도: 특정 개수의 요소를 건너뛸 때 사용한다.
- 예제:
List<String> list = Arrays.asList("apple", "banana", "cherry", "date");
List<String> result = list.stream()
.skip(2)
.collect(Collectors.toList());
// result: ["cherry", "date"]
최종연산
1. forEach
- 설명: 스트림의 각 요소에 대해 주어진 동작을 수행합니다. 이 메서드는 스트림의 요소를 반복(iterate)하는 데 사용된다.
- 용도: 요소들에 대해 부수 효과(side-effect)를 일으키는 작업을 수행할 때 사용한다.
- 예제:
List<String> list = Arrays.asList("apple", "banana", "cherry");
list.stream().forEach(System.out::println);
// 출력: apple, banana, cherry (각 요소가 개별적으로 출력됨)
2. collect
- 설명: 스트림의 요소들을 수집하여 리스트, 세트, 맵 등의 다른 형태로 변환합니다. 주로 Collectors 유틸리티 클래스를 사용한다.
- 용도: 스트림의 결과를 특정 컬렉션으로 변환할 때 사용한다.
- 예제:
List<String> list = Arrays.asList("apple", "banana", "cherry");
List<String> result = list.stream().collect(Collectors.toList());
// result: ["apple", "banana", "cherry"]
3. reduce
- 설명: 스트림의 요소들을 결합하여 하나의 결과를 생성한다. 초기값과 결합 함수를 인수로 받는다.
- 용도: 스트림의 모든 요소를 결합하여 단일 결과를 도출할 때 사용한다.
- 예제:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
int sum = list.stream().reduce(0, Integer::sum);
// sum: 15
4. count
- 설명: 스트림의 요소 개수를 반환한다.
- 용도: 스트림에 포함된 요소의 개수를 셀 때 사용한다.
- 예제:
List<String> list = Arrays.asList("apple", "banana", "cherry");
long count = list.stream().count();
// count: 3
5. findFirst
- 설명: 스트림에서 첫 번째 요소를 반환한다. 요소가 없으면 빈 Optional을 반환한다.
- 용도: 스트림의 첫 번째 요소를 찾을 때 사용한다.
- 예제:
List<String> list = Arrays.asList("apple", "banana", "cherry");
Optional<String> firstElement = list.stream().findFirst();
// firstElement: Optional[apple]
6. findAny
- 설명: 스트림에서 임의의 요소를 반환한다. 요소가 없으면 빈 Optional을 반환한다.
- 용도: 병렬 스트림에서 성능 최적화를 위해 임의의 요소를 찾을 때 사용한다.
- 예제:
List<String> list = Arrays.asList("apple", "banana", "cherry");
Optional<String> anyElement = list.stream().findAny();
// anyElement: Optional[apple] (또는 다른 임의의 요소)
7. anyMatch
- 설명: 스트림의 어떤 요소라도 주어진 조건(predicate)을 만족하면 true를 반환한다.
- 용도: 스트림에 조건을 만족하는 요소가 하나라도 있는지 확인할 때 사용한니다.
- 예제:
List<String> list = Arrays.asList("apple", "banana", "cherry");
boolean hasApple = list.stream().anyMatch(s -> s.equals("apple"));
// hasApple: true
8. allMatch
- 설명: 스트림의 모든 요소가 주어진 조건(predicate)을 만족하면 true를 반환한다.
- 용도: 스트림의 모든 요소가 조건을 만족하는지 확인할 때 사용한다.
- 예제:
List<String> list = Arrays.asList("apple", "banana", "cherry");
boolean allHaveA = list.stream().allMatch(s -> s.contains("a"));
// allHaveA: true
9. noneMatch
- 설명: 스트림의 모든 요소가 주어진 조건(predicate)을 만족하지 않으면 true를 반환한다.
- 용도: 스트림의 모든 요소가 조건을 만족하지 않는지 확인할 때 사용한다.
- 예제:
List<String> list = Arrays.asList("apple", "banana", "cherry");
boolean noneStartWithZ = list.stream().noneMatch(s -> s.startsWith("z"));
// noneStartWithZ: true
Stream 사용 예제
컬렉션에서 스트림 생성
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Edward");
List<String> filteredNames = names.stream()
.filter(name -> name.startsWith("A")) // 이름이 "A"로 시작하는 항목 필터링
.map(String::toUpperCase) // 이름을 대문자로 변환
.sorted() // 이름을 정렬
.collect(Collectors.toList()); // 결과를 리스트로 수집
filteredNames.forEach(System.out::println); // 결과 출력: ALICE
배열에서 스트림 생성
int[] numbers = {1, 2, 3, 4, 5};
int sum = Arrays.stream(numbers)
.filter(n -> n % 2 == 0) // 짝수 필터링
.sum(); // 합계 계산
System.out.println(sum); // 결과 출력: 6
파일에서 스트림 생성
try (Stream<String> lines = Files.lines(Paths.get("example.txt"))) {
long lineCount = lines.count(); // 파일의 줄 수 계산
System.out.println(lineCount);
} catch (IOException e) {
e.printStackTrace();
}
'Java' 카테고리의 다른 글
[Java] Restful API 구현하기 (0) | 2024.08.13 |
---|---|
[Java] 추상화란? (0) | 2024.08.11 |
[Java] Math 클래스란? (0) | 2024.08.07 |
[Java] HttpServletRequest를 통하여 Client IP 주소 가져오기 (0) | 2024.08.05 |
[Java] HttpServletRequest를 통하여 Client IP 주소 가져오기 (0) | 2024.08.01 |