Java8부터는 Stream API와 람다식, 함수형 인터페이스 등을 지원하면서 Java를 이용해 함수형으로 프로그래밍할 수 있는 API 들을 제공해 주고 있다
스트림이란
컬렉션 배열의 요소를 하나씩 참조하여 람다 표현식으로 처리할 수 있는 반복자(내부 반복자)
(이전에는 for 문이 나 Interator를 사용했다고 한다 - 외부 반복자)
외부 반복 자일 경우 컬렉션의 요소를 외부로 가져오는 코드와 처리하는 코드를 모두 개발자 코드가 가지고 있어야 한다
반면 내부 반복 자일 경우 개발자가 코드에서 제공한 데이터 처리 코드(람다식)를 가지고 컬렉션 내부에서 요소를 반복 처리한다)
Stream 특징
람다 표현식
스트림은 람다식으로 요소 처리 코드를 제공
스트림이 제공하는 대부분의 요소 처리 메서드는 함수형 인터페이스를 사용하므로, 람다식으로 요소 처리 코드를 제공할 수 있다
생성, 중간처리, 최종 처리
스트림의 처리는 생성, 중간처리, 최종 처리 3단계로 구분된다
재사용 불가능
스트림은 생성되고, 중간처리를 거쳐 최종 처리까지 완료되면 닫히게 된다
이미 닫힌 스트림은 재사용 할 수 없으며, 재사용을 시도할 경우 예외 처리가 발생한다
스트림은 일회용이다
List<Integer> numbers = List.of(10, 20, 25, 15, 30, 35);
Stream<Integer> integerStream = numbers.stream()
.filter(number -> number > 20);
integerStream.count();
integerStream.count();
// java.lang.IllegalStateException: stream has already been operated upon or closed
원본 데이터를 변경하기 않는다
원본 데이터를 조회하여 원본이 데이터가 아닌 별도의 요소들로 Stream을 생성
정렬이나 필터링 등의 작업은 별도의 Stream 요소들에서 처리가 된다
List<String> sortedList = nameStream.sorted()
.collect(Collections.toList());
Stream의 단계
1. 생성하기
- Stream 객체를 생성하는 단계
- 재사용이 불가능함으로 닫히면 다시 생성해 주어야 한다
- 배열, 컬렉션, 임의의 수, 파일 등 거의 모든 것을 가지고 스트림을 생성할 수 있다.
2. 가공하기(중산 연산)
- 원본 데이터를 별도의 데이터로 가공하기 위한 중간 연산
- 연산 결과가 Stream으로 다시 반환하기 때문에 연속해서 중간 연산을 이어갈 수 있다
[필터링 - Filter]
filter는 Stream에서 조건에 맞는 데이터만 정제하여 더 작은 컬렉션을 만들어내는 연산
Stream<String> stream =
list.stream()
.filter(name -> name.contains("a"));
// 어떤 String에서a 가 들어간 문자열만 포함하도록 필터링
[데이터 변환 - Map]
Map은 기존의 Stream 요소들을 변환하여 새로운 Stream을 형성하는 연산
저장된 값을 특정 형태로 변환하는데 주소 사용되며, Java에서는 map 함수의 인자로 함수형 인터페이스 function을 받고 있다
Stream<String> stream =
names.stream()
.map(s -> s.toUpperCase());
// String요소들을 갖는 Stream을 모두 대문자 String요소로 변환
//메소드 참조를 이용 파일의 Stream을 파일 이름의 Stream으로 변경 가능
Stream<File> fileStream = Stream.of(new File("Test1.java"), new File("Test2.java"), new File("Test3.java"));
//Stream<File> --> Stream<String> 변환
Stream<String> fileNameStream = fileStream.map(File::getName);
[정렬 - Sorted]
Stream에서 요소들을 정렬하기 위해서는 sorted를 사용해야 하며, 파라미터로 Comparator를 넘길 수도 있다
Comparator인 자 없이 호출할 경우, 오름 차순으로 정렬이 되며, 내림차순으로 정렬을 원하면 Comparator의 reverseOrder를 이용하면 된다
List<String> list = Arrays.asList("Java", "Scala", "Groovy", "Python", "Go", "Swift");
Stream<String> stream = list.stream()
.sorted()
// [Go, Groovy, Java, Python, Scala, Swift]
Stream<String> stream = list.stream()
.sorted(Comparator.reverseOrder())
// [Swift, Scala, Python, Java, Groovy, Go]
[중복제거 - Distinct ]
Stream의 요소들에 중복된 데이터가 존재하는 경우, 중복을 제거하기 위해 distinct를 사용
List<String> list = Arrays.asList("Java", "Scala", "Groovy", "Python", "Go", "Swift", "Java");
Stream<String> stream = list.stream()
.distinct()
3. 결과 만들기
- 가공된 데이터로부터 원하는 결과를 만들기 위한 최종 연산
- Stream의 요소들을 소모하면서 연산이 수행되기 때문에 1번만 처리가 가능하다
List<String> myList = Array.asList("a1","a2","b1","b2","c1","c2")
myList.stream() //생성하기
.filter(s -> s.startsWith("c")) // 가공하기
.map(String::toUpperCase) // 가공하기
.sorted() // 가공하기
.count(); // 결과만들기
[ 최댓값/최솟값/총합/평균/갯수 - Max/Min/Sum/Average/Count ]
[ 데이터 수집 - collect ]
Stream의 요소들을 List, set, map 등 다른 종류의 결과로 수집하고 싶은 경우 collect 함수를 이용
collect 함수는 어떻게 stream의 요소들을 수집할 것인가를 정의한 Collector 타입을 인자로 받아서 처리함
collect() : 스트림의 최종연산, 매개변수로 Collector를 필요로 한다.
Collector : 인터페이스, collect의 파라미터는 이 인터페이스를 구현해야한다.
Collectors : 클래스, static메소드로 미리 작성된 컬렉터를 제공한다.
// collect의 파라미터로 Collector의 구현체가 와야 한다.
Object collect(Collector collector)
- Collectors.toList() : Stream에서 작업한 결과를 List로 반환받을 수 있음
// Stream의 요소들을 Product의 이름으로 변환하여, 그 결과를 List로 반환받음
List<String> nameList = productList.stream()
.map(Product::getName)
.collect(Collectors.toList());
- Collectors.joining()
- Stream에서 작업한 결과를 1개의 String으로 이어붙이기를 원하는 경우에 Collectors.joining()을 이용
- delimiter : 각 요소 중간에 들어가 요소를 구분시켜주는 구분자
- prefix : 결과 맨 앞에 붙는 문자
- suffix : 결과 맨 뒤에 붙는 문자
- Collectors.joining()은 총 3개의 인자를 받을 수 있는데, 이를 이용하면 간단하게 String을 조합할 수 있다.
- Stream에서 작업한 결과를 1개의 String으로 이어붙이기를 원하는 경우에 Collectors.joining()을 이용
'JAVA' 카테고리의 다른 글
[Java] 입/출력 (0) | 2024.07.18 |
---|---|
[Java] 스레드 Thread (0) | 2024.05.04 |
[Java] 람다식 Lambda Expression (0) | 2024.05.04 |
[Java] Collections framework (0) | 2024.05.04 |
[Java] 인터페이스 interface (0) | 2024.05.04 |