- 자바8부터 추가된 컬렉션의 저장 요소를 하나씩 참조해서 람다식으로 처리할 수 있도록 해주는 반복자
- 배열이나 컬렉션(List, Set, Map)으로 원하는 값을 얻을 때 for문 과도한 사용을 방지하기 위해 나온 개념
- 스트림은 선언, 가공, 반환 세 부분으로 구성
- 선언 : 스트림 인스턴스 생성, 배열, 컬렉션(list, set, map) 등을 스트림 형태로 만들기
- 가공 : 스트림을 필요한 형태로 가공, 필터링, 매핑등 중간 작업
- 반환 : 가공한 값을 원하는 형태로 가져오기
장점
- 사용하기 편함
- 코드가 간결해짐
- 가독성 높아짐 (for문으로 도배 된 코드를 보라~~)
단점
- 디버그 힘듬(한번에 수행되기 때문)
- 재활용 불가능(스트림은 사용후 close)
참고사이트 : https://wakestand.tistory.com/419
외부반복자와 내부반복자
- 일반적인 반복 : for, while
- 외부반복자 : iterator -> next()
- 내부반복자: forEach -> 람다식
package chapter16;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
public class IteratorEx {
public static void main(String[] args) {
List<String> list = Arrays.asList(new String[]{"홍길동", "김유신",
"이순신", "유관순"});
System.out.println("for문 이용");
for (int i=0; i<list.size(); i++) {
System.out.println(list.get(i));
}
System.out.println("외부 반복자 이용");
Iterator<String> it = list.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
System.out.println("내부 반복자 이용");
list.stream().forEach(s ->System.out.println(s));
}
}
스트림 선언(생성)
배열 -> 스트림
- Arrays.stream()
package chapter16;
import java.util.Arrays;
import java.util.stream.Stream;
public class ArrayToStream {
public static void main(String[] args) {
// 문자열 배열객체 생성
String[] arr = new String[]{"a", "b", "c", "d", "e", "f"};
// 배열전체 Stream 객체로 변환
Stream<String> stream1 = Arrays.stream(arr);
stream1.forEach(s -> System.out.print(s+" "));
System.out.println();
// 인덱스 지정해서 변환 (2부터 5전까지)
// 두번째 인덱스는 포함되지 않음
Stream<String> stream2 = Arrays.stream(arr, 2, 5);
stream2.forEach(s -> System.out.print(s+" "));
}
}
컬렉션 -> 스트림
- 컬렉션.stream()
package chapter16;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class CollectionToStream {
public static void main(String[] args) {
// 문자열 배열을 컬렉션프레임워크 List로 변환
List<String> list = Arrays.asList("a", "b", "c", "d", "e");
// List 객체를 stream()메서드를 이용해 Stream 객체로 생성
Stream<String> stream = list.stream();
// 내부반복자를 이용해 출력
stream.forEach(s -> System.out.println(s));
}
}
메서드-> 스트림
build() 메서드 - > 스트림
- 메서드 체이닝으로 Builder 객체 생성, 값추가, 스트림 생성
- Stream.buulder().add(value).build()
package chapter16;
import java.util.stream.Stream;
public class StreamByBuilder{
public static void main(String[] args) {
// builder() 메서드로 Builder 객체 생성
// add() 메서드도 리턴타입이 Builder 객체 이므로 메서드 체이닝 가능
Stream stream = Stream.builder()
.add("무궁화")
.add("삼천리")
.add("화려강산")
.add("대한사람")
.build();
// build() 메서드로 Stream 객체 생성
// 내부 반복자로 출력
stream.forEach(s -> System.out.println(s + " "));
}
}
generate() 메서드 - > 스트림
- 매개변수 없이 리턴값만 있는 경우
- 문한 반복 출력이라 limit() 메서드로 횟수 제한
- Stream.generate(람다식).limit(n)
package chapter16;
import java.util.stream.Stream;
public class StreamByGenerator {
public static void main(String[] args) {
// generate() 메서드로 Stream 객체 생성
// 리미트 10개 생성
Stream<String> stream = Stream.generate(() -> "애국가").limit(10);
// 내부 반복자로 출력
stream.forEach(s -> System.out.println(s));
}
}
iterate() 메서드 - > 스트림
- 매개변수로 초기값, 람다식 사용
- 문한 반복 출력이라 limit() 메서드로 횟수 제한
- Stream.iterate(초기값, 람다식).limit(n)
package chapter16;
import java.util.stream.Stream;
public class StreamByIterator {
public static void main(String[] args) {
// generate() 메서드로 Stream 객체 생성
// 리미트 10개 생성, 초기값 1 부터 생성
Stream<Integer> stream = Stream.iterate(1, n -> n + 1).limit(10);
// 내부 반복자로 출력
stream.forEach(s -> System.out.println(s));
}
}
스트림 종류
스트림 인터페이스
- 최상위 인터페이스 : BaseStream
- 하위 인터페이스
Stream<T>
: Collection, Array 형 처리 - 하위 인터페이스
IntStream<T>
: int 형 처리 - 하위 인터페이스
LongStream<T>
: long 형 처리 - 하위 인터페이스
DoubleStream<T>
: double 형 처리 - Random, File, 디렉토리등에서도 생성 가능
Random 클래스로 스트림 사용
- ints(), longs(), doubles() 메서드 사용
package chapter16;
import java.util.Random;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
public class RandomToStream {
public static void main(String[] args) {
System.out.println("int 형 난수 스트림 : ");
// ints(3) 3개
IntStream isr = new Random().ints(3);
isr.forEach(s -> System.out.println(s));
// ints(갯수, 시작값, 끝값전까지)
isr = new Random().ints(10,0,3);
isr.forEach(s -> System.out.println(s));
System.out.println();
System.out.println("long 형 난수 스트림 : ");
// longs(갯수, 시작값, 끝값전까지)
LongStream lsr = new Random().longs(3,0,10);
lsr.forEach(s -> System.out.println(s));
System.out.println();
System.out.println("double 형 난수 스트림 : ");
// doubles(3) 3개
DoubleStream dsr = new Random().doubles(3);
dsr.forEach(s ->System.out.println(s));
}
}
스트림 가공
- 중간 처리 작업
- 필터링(Filtering), 매핑(Mapping), 정렬(Sorting), 그룹핑(Groupping)
필터링 Filtering
- 조건 처리
- distinct() : 중복 제거 된 스트림 생성
- filter() : true 리턴 데이터만 스트림 생성
package chapter16;
import java.util.Arrays;
import java.util.List;
public class FilterStream {
public static void main(String[] args) {
// List 객체 생성
List<String> list = Arrays.asList("홍길동", "김유신", "홍길동",
"이순신", "홍길동", "유관순");
// distinct() 메서드로 중복 제거 후 내부 반복자로 출력
System.out.println("distinct()");
list.stream().distinct().forEach(n -> System.out.println(n));
System.out.println();
// "홍"으로 시작하는 문자열로 필터링 후 내부 반복자로 출력
System.out.println("filter()");
list.stream().filter(n -> n.startsWith("홍"))
.forEach(n -> System.out.println(n));
System.out.println();
// 중복제거 후 "홍"으로 시작하는 문자열 내부 반복자로 출력
System.out.println("distinct() + filter()");
list.stream().distinct().filter(n -> n.startsWith("홍")).forEach(n -> System.out.println(n));
}
}
매핑 Mapping
- 데이터 변환 처리
flatMapXXX() 메서드
package chapter16;
import java.util.Arrays;
import java.util.List;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
public class StreamFlatMap {
public static void main(String[] args) {
// 문자열을 공백으로 분리해서 매핑
List<String> list1 = Arrays.asList("동해물과", "백두산이",
"마르고 닳도록");
list1.stream().flatMap(data -> Arrays.stream(data.split(" ")))
.forEach(word -> System.out.println(word));
System.out.println();
// 문자열을 ,로 분리해서 double 자료형으로 변환해서 매핑
List<String> list2 = Arrays.asList("1.1, 2.2, 3.3", "4.4, 5.5, 6.6");
DoubleStream dsr = list2.stream().flatMapToDouble(data -> {
String[] strArr = data.split(",");
double[] dArr = new double[strArr.length];
for(int i=0; i<dArr.length; i++) {
dArr[i] = Double.parseDouble(strArr[i].trim());
}
return Arrays.stream(dArr);
});
dsr.forEach(n -> System.out.println(n));
System.out.println();
// 문자열을 ,로 분리해서 int 자료형으로 변환해서 매핑
List<String> list3 = Arrays.asList("1, 2, 3", "4, 5, 6");
IntStream isr = list3.stream().flatMapToInt(data -> {
String[] strArr = data.split(",");
int[] intArr = new int[strArr.length];
for(int i=0; i<strArr.length; i++) {
intArr[i] = Integer.parseInt(strArr[i].trim());
}
return Arrays.stream(intArr);
});
isr.forEach(n -> System.out.println(n));
}
}
mapXXX()
- 요소를 새로 구성하여 새로운 스트림 리턴
package chapter16;
import java.util.Arrays;
import java.util.List;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
public class StreamMap {
public static void main(String[] args) {
List<String> list = Arrays.asList("동해물과", "백두산이",
"마르고 닳도록");
System.out.println("함수적 인터페이스 방식");
list.stream().mapToInt(s -> s.length())
.forEach(len -> System.out.println(len));
System.out.println();
System.out.println("메서드 참조 방식");
list.stream().mapToInt(String::length)
.forEach(len -> System.out.println(len));
}
}
정렬 sorting
- 객체정렬은 Comparable 인터페이스를 구현한 클래스 인스턴스만 정렬이 가능
- 스트림 중간단계에서 sorted 메서드를 이용하여 순서 변경 가능
package chapter16;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public class StreamOrder {
public static void main(String[] args) {
List<String> list = Arrays.asList("홍길동", "김유신", "이순신", "유관순");
System.out.println("기본 정렬");
list.stream().sorted().forEach(System.out::println);
System.out.println();
System.out.println("역순 정렬");
list.stream().sorted(Comparator.reverseOrder()).forEach(System.out::println);
}
}
집계 메서드
- 스트림 API는 요소들의 최소값, 최대값, 합계, 평균값, 갯수 등을 구할 수 있는 메서드 제공
package chapter16;
import java.util.Arrays;
import java.util.OptionalDouble;
import java.util.OptionalInt;
public class StreamOptional {
public static void main(String[] args) {
int[] arr = new int[100];
for(int i=0;i<100;i++) {
arr[i] = i+1;
}
// 리턴값 long
long count = Arrays.stream(arr).count();
System.out.println("요소들의 갯수 : " + count);
// 리턴값 int
int sum = Arrays.stream(arr).sum();
System.out.println("요소들의 합 : " + sum);
OptionalInt first = Arrays.stream(arr).findFirst();
System.out.println("요소들 중 첫번째 값 : " + first.getAsInt());
OptionalInt max = Arrays.stream(arr).max();
System.out.println("요소들 중 최대 값 : " + max.getAsInt());
OptionalInt min = Arrays.stream(arr).min();
System.out.println("요소들 중 최소 값 : " + min.getAsInt());
OptionalDouble avg = Arrays.stream(arr).average();
System.out.println("요소들의 평균 : " + avg.getAsDouble());
}
}
'Java' 카테고리의 다른 글
입출력 Input / Output (0) | 2022.03.07 |
---|---|
스레드 thread (0) | 2022.03.07 |
람다 lambda (0) | 2022.03.07 |
제네릭 generic (0) | 2022.03.07 |
컬렉션 F/W collection (0) | 2022.03.07 |