728x90
스트림(Stream)
- 다양한 데이터소스(컬렉션, 배열)를 표준화된 방법으로 다루기 위한 것
List,Set,Map 사용방법이 같지 않았지만 스트림을 통해 사용방법을 통일시킴
Stream → 중간 연산(n번) → 최종연산(1번, 결과)
스트림 작업 : 스트림 만들기 → 중간연산 → 최종연산
Stream<T> Collection stream()
List<Integer> list = Arrays.asList{1,2,3,4,5};
Stream<Integer> intStream = list.stream(); //컬렉션
Stream<String> strStream = Stream.of(new String[]{"a","b","c"}); //배열
Stream<Integer> evenStream = Stream.iterate(0, n -> n+2); //0,2,4,6,8,...
Steram<Double> randomStream = Stream.generate(Math::random);
IntStream intStream = new Random().ints(5); //크기가 5인 난수 스트림
- 스트림이 제공하는 기능
중간 연산 : 연산결과가 스트림인 연산. 반복적으로 적용가능
최종 연산 : 연산결과가 스트림이 아닌 연산. 단 한 번만 적용가능(스트림의 요소를 소모)
stream.distinct().limit(5).sorted().forEach(System.out::println)
// 중간연산 최종연산
//distinct() 중복제거, limit() 자르기, sorted() 정렬
//forEach() 출력
String[] strArr={"dd","aaa","cc","CC","b"};
Stream<String> stream = Stream.of(strArr); //문자열 배열이 소스인 스트림
Stream<String> filteredStream = stream.filter(); //걸러내기(중간연산)
Stream<String> distinctedStream = stream.distinct(); //중복제거(중간연산)
Stream<String> sortedStream = stream.sort(); //정렬(중간연산)
Stream<String> limitedStream = stream.limit(5); //스트림자르기(중간연산)
int total = stream.count(); //요소 개수 세기(최종 연산)
스트림의 특징
- 데이터 소스로부터 데이터를 읽기만할 뿐 변경하지 않음
원본 변경 X, Read Only
List<Integer> list = Arrays.asList(3,1,5,2,4);
List<Integer> sortedList = list.stream().sorted() //list를 정렬
.collect(Collectors.toList()); //새로운 List에 저장
System.out.println(list); // [3,1,5,2,4]
System.out.println(sortedList); //[1,2,3,4,5]
- Iterator처럼 일회용(필요하면 다시 스트림을 생성해야함)
strStream.forEach(System.out::println); //모든 요소를 화면에 출력(최종연산)
int numOfStr = strStream.count(); //에러 스트림이 닫혀있음
- 최종 연산 전까지 중간연산이 수행되지 않음. 지연된 연산
IntStream intStream = new Random().ints(1,46); //1~45범위의 무한 스트림
IntStream.distinct().limit(6).sorted() //중간연산
.forEach(i->System.out.println(i+", ")); //최종연산
- 작업을 내부 반복으로 처리
for(String str : strLis)
System.out.println(str);
==>
stream.forEach(System.out::println);
void forEach(Consumer<? super T> action){
Objects.requireNonNull(action); //매개변수의 널 체크
for(T t : src) //내부 반복(for문을 메소드 안으로 넣음)
action.accept(T);
}
- 작업을 병렬로 처리 - 병렬 스트림(멀티쓰레드)
Stream<String> strStream = Stream.of("dd","aaa","CC","cc","b");
int sum = strStream.parallel() //병렬 스트림으로 전환(속성만 변경)
.mapToInt(s->s.length()).sum(); //모든 문자열의 길이의 합
- 기본형 스트림 - IntStream, LongStream, DoubleStream
오토박싱 & 언박싱의 비효율이 제거됨(Stream<Integer> 대신 IntStream 사용)
숫자와 관련된 유용한 메소드를 Stream<T>보다 더 많이 제공
스트림 만들기 - 컬렉션
- Collection인터페이스의 stream()으로 컬렉션을 스트림으로 변환
Stream<E> stream() //Collection 인터페이스의 메소드
List<Integer> list = Arrays.asList(1,2,3,4,5);
Stream<Integer> intStream = list.stream(); //list를 스트림을 변환
//스트림의 모든 요소를 출력
intStream.forEach(System.out::print); //12345
intStream.forEach(System.out::print); //에러. 스트림이 닫힘
package chapter14;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class Study7_1 {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1,2,3,4,5);
Stream<Integer> intStream = list.stream();
intStream.forEach(System.out::print);
// intStream.forEach(System.out::println); //에러발생
//stream은 1회용이므로 최종연산을 수행하면 stream이 닫혀 다시 생성해줘야함
intStream = list.stream();
intStream.forEach(System.out::print);
}
}
스트림 만들기 - 배열
- 객체 배열로부터 스트림 생성하기
Stream<T> Stream.of(T... values) //가변인자
Stream<T> Stream.of(T[])
Stream<T> Stream.stream(T[])
Stream<T> Arrays.stream(T[] array, int startInclusive, int endExclusive) //from to
Stream<String> strStrem = Stream.of("a","b","c"); //가변인자
Stream<String> strStrem = Stream.of(new String[]{"a","b","c"});
Stream<String> strStrem = Arrays.stream(new String[]{"a","b","c"});
Stream<String> strStrem = Arrays.stream(new String[]{"a","b","c"},0,3);
- 기본형 배열로부터 스트림 생성하기
IntStream IntStream.of(int... value) //Stream이 아닌 IntStream
IntStream IntStream.of(int[])
IntStream Arrays.stream(int[])
IntStream Arrays.stream(int[] array, int startInclusive, int endExclusive)
package chapter14;
import java.util.Arrays;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class Study7_2 {
public static void main(String[] args) {
Stream<String> strStream = Stream.of("a","b","c");
strStream.forEach(System.out::print);
String[] strArr = new String[] {"a","b","c","d"};
// Stream<String> strStream2 = Stream.of(strArr);
Stream<String> strStream2 = Stream.of(new String[]{"a","b","c","d"});
strStream2.forEach(System.out::print);
Stream<String> strStream3 = Arrays.stream(strArr);
strStream3.forEach(System.out::print);
int[] intArr = {1,2,3,4,5};
IntStream intStream = Arrays.stream(intArr);
// System.out.println("count = " + intStream.count()); //IntStream은 숫자가 요소임을 알 수 있어 더 많은 메소드를 포함
System.out.println("average = " + intStream.average());
// intStream.forEach(System.out::print);
Integer[] intArr2 = {1,2,3,4,5};
// Integer[] intArr2 = {new Integer(1),new Integer(2),new Integer(3),new Integer(4),new Integer(5)};
Stream<Integer> intStream2 = Arrays.stream(intArr2);
intStream2.forEach(System.out::print);
}
}
스트림 만들기 - 임의의 수
- 난수를 요소로 갖는 스트림 생성하기
IntStream intStream = new Random().ints(); //무한 스트림
intStream.limit(5).forEach(System.out::println); //5개의 요소만 출력
==>
IntStream intStream = new Random().ints(5); //크기가 5인 난수 스트림을 반환
Integer.MIN_VALUE <= ints() <= Integer.MAX_VALUE
Long.MIN_VALUE <= longs() <= Long.MAX_VALUE
0.0<= doubles() < 1.0
- 지정된 범위의 난수를 요소로 갖는 스트림을 생성하는 메소드(Random 클래스)
//무한 스트림
IntStream ints(int begin, int end);
LongStream longs(int begin, int end);
DoublesStream doubles(int begin, int end);
//유한 스트림
IntStream ints(long streamSize, int begin, int end);
LongStream longs(long streamSize, long begin, long end);
DoubleStream doubles(long streamSize, double begin, double end);
package chapter14;
import java.util.Random;
import java.util.stream.IntStream;
public class Study7_3 {
public static void main(String[] args) {
IntStream intStream = new Random().ints();
intStream
.limit(5) //5개만 자르기
.forEach(System.out::println);
System.out.println();
IntStream intStream2 = new Random().ints(10,5,10);
intStream2
.forEach(System.out::println);
}
}
스트림 만들기 - 특정 범위의 정수
- 특정 범위의 정수를 요소로 갖는 스트림 생성하기(IntStream, LongStream)
IntStream IntStream.range(int begin,int end); //begin <= x < end. end가 포함되지 않음
IntStream IntStream.rangeClosed(int begin,int end); // begin<= x <= end. end가 포함
IntStream intStream = IntStream.range(1,5); //1234
IntStream intStream = IntStream.rangeClosed(1,5); //12345
스트림 만들기 - 람다식 iterate(), generate()
- 람다식을 소스로 하는 스트림 생성하기
static <T> Stream<T> iterate(T seed, UnaryOperator<T> f) //이전 요소에 종속적
static <T> Stream<T> genrate(Supplier<T> s) //이전 요소에 독립적
- iterate()는 이전 요소를 seed로 해서 다음 요소를 계산
Stream<Integer> evenStream = Stream.iterate(0, n->n+2); //0,2,4,6,...
- generate()는 seed를 사용하지 않음
Stream<Double> randomStream = Stream.generate(Math::random);
Stream<Integer> oneStrem = Stream.generate(()->1);
package chapter14;
import java.util.stream.Stream;
public class Study7_5 {
public static void main(String[] args) {
//iterate(T seed, UnaryOperator f)
Stream<Integer> intStream = Stream.iterate(1, n->n+2);
intStream.limit(10).forEach(System.out::print);
//generate(Supplier s) : 주기만 하는 것. 입력 X 출력 O
Stream<Integer> oneStream = Stream.generate(()->1);
oneStream.limit(10).forEach(System.out::print);
}
}
스트림 만들기 - 파일과 빈 스트림
- 파일을 소스로 하는 스트림 생성
Stream<Path> Files.list(Path dir) //Path는 파일 또는 디렉토리
Stream<String> Files.lines(Path path)
Stream<String> Files.lines(Path path, Charset cs)
Stream<String> lines() //BufferedReader 클래스의 메소드
- 비어있는 스트림 생성하기
Stream emptyStream = Stream.empty(); //empty()는 빈 스트림을 생성해서 반환
long count = emptyStream.count(); //0
스트림의 연산
- 중간연산
Stream<T> distinct() : 중복 제거
Stream<T> filter(Predicate<T> predicate) : 조건에 안 맞는 요소 제외
Stream<T> limit(long maxSize) : 스트림의 일부를 잘라냄
Stream<T> skip(long n) : 스트림의 일부를 건너뜀
Stream<T> peek(Consumer<T> action) : 스트림 요소에 작업 수행
Stream<T> sorted(), Stream<T> sorted(Comparator<T> comparator) : 스트림의 요소를 정렬
스트림의 요소를 변환
Stream<R> map(Function<T,R> mapper)
DoubleStream mapToDouble(ToDoubleFunction<T> mapper)
IntStream mapToInt(ToIntFunction<T> mapper)
LongStream mapToLong(ToLongFunction<T> mapper)
Stream<R> flatMat(Function<T, Stream<R>> mapper)
DoubleStream flatMapToDouble(Function<T,DoubleStream> m)
IntStream flatMapToInt(Function<T, IntStream> m)
LongStream flatMapToLong(Function<T, LongStream> m) - 최종연산
void forEach(Consumer<? super T> action), void forEachOrdered(Consumer<? super ?) action) : 각 요소에 지정된 작업 수행(병렬일 때 forEachOrdered)
long count() : 스트림의 요소의 개수 반환
Optional <T> max/min(Conparator<? super T> comparator) : 스트림의 최대값/최소값을 반환
Optional <T> findAny() : 스트림의 요소 아무거나 하나를 반환
Optional <T> findFirst() : 스트림의 첫 번째 요소 하나를 반환
boolean allMatch(Predicate <T> p) : 주어진 조건을 모두 만족하는지 확인
boolean anyMatch(Predicate<T> p) : 주어진 조건 중 하나라도 만족하는지 확인
boolean noneMatch(Predicate<T> p) : 주어진 조건을 모두 만족하지 않는지 확인
Object[] toArray(), A[] toArray(IntFunction<A[]> generator) : 스트림의 모든 요소를 배열로 반환
Optional<T> reduce(BinaryOperator<T> accumulator), T reduce(T identity, BinaryOperator<T> accumulator),
U reduce(U identity, BiFunction<U,T,U> accumulator, BinaryOperator<U> combiner : 스트림의 요소를 하나씩 줄여가면서 리듀싱 계산
R collect(Collector<T,A,R> collector), R collect(Supplier<R> supplier, BiConsumer<R,T> accumulator, BiConsumer<R,R> combiner) : 스트림의 요소를 수집. 주로 요소를 그룹화하거나 분할한 결과를 컬렉션에 담아 반환하는데 사용
스트림의 중간연산
- 스트림 자르기 - skip(), limit()
Stream<T> skip(long n) //앞에서부터 n개 건너뛰기
Stream<T> limit(long maxSize) //maxSize 이후의 요소는 잘라냄
IntStream intStream = IntStream.rangeClosed(1,10); //12345678910
intStream.skip(3).limit(5).forEach(System.out::print); //45678
- 스트림의 요소 걸러내기 - filter(), distinct()
Stream<T> filter(Predicate <? super T> predicate) //조건에 맞지 않는 요소 제거
Stream<T> distinct() //중복제거
IntStream intStream = IntStream.of(1,2,3,4,4,5,5,5,6,6,1);
intStream.distinct().forEach(System.out::print); //123456
IntStream intStream = IntStream.rangeClosed(1,10); //12345678910
intStream.filter(i->i%2==0).forEach(System.out::print); //246810
intStream.filter(i->i%2!=0 &&i%3!=0).forEach(System.out::print);
intStream.filter(i->i%2!=0).filter(i->i%3!=0).forEach(System.out::print);
- 스트림 정렬하기 - sorted()
Stream<T> sorted() //스트림 요소의 기본 정렬(Comparable)로 정렬
Stream<T> sorted(Comparator<? super T> comparator) //지정된 Comparator로 정렬
strStream.sorted() //기본정렬
strStream.sorted(Comparator, naturalOrder()) //기본정렬
strStream.sorted((s1,s2)->s1.compareTo(s2)) //람다식 가능
strStream.sorted(String::comparaTo) //메소드 참조
//출력결과 예 : CCaaabccdd
strStream.sorted(Comparator.reverseOrder()) //기본 정렬의 역순
strStream.sorted(Comparator.(String)naturalOrder().reversed())
//출력결과 예 : ddccbaaaCC
strStream.sorted(String.CASE_INSENSITIVE_ORDER) //대소문자 구분안함
//출력결과 예 : aaabCCccdd
strStream.sorted(String.CASE_INSENSITIVE_ORDER.reversed())
//출력결과 예 : ddCCccbaaa
strStream.sorted(Comparator.comparing(String::length)) //길이 순 정렬
strStream.sorted(Comparator.comparingInt(String::length)) //no 오토박싱
//출력결과 예 : bddCCccaaa
strStream.sorted(Comparator.comparing(String::length).reversed())
//출력결과 예 : aaaddCCccb
- Comparator의 comparing()으로 정렬 기준을 제공
comparing(Function<T,U> keyExtractor)
comparing(Function<T,U> keyExtractor, Comparator<U> keyComparator)
studentStream.sorted(Comparator.comparing(Student::getBan)) //반별로 정렬
.forEach(System.out::println);
- 추가 정렬 기준을 제공할 때는 thenComparing()을 사용
thenComparing(Comparator<T> other)
thenComparing(Function<T,U> keyExtractor)
thenComparing(Function<T,U> keyExtractor, Comparator<U> keyComp)
studentStream.sorted(Comparator.comparing(Student::getBan) //반별로 정렬
.thenComparing(Student::getTotalScore) //총점별로 정렬
.thenComparing(Student::getName)) //이름별로 정려
.forEach(System.out::print);
package chapter14;
import java.util.Comparator;
import java.util.stream.Stream;
class Student9_1 implements Comparable<Student9_1>{
String name;
int ban;
int totalScore;
public Student9_1(String name, int ban, int totalScore) {
this.name = name;
this.ban = ban;
this.totalScore = totalScore;
}
public String toString() {
return String.format("[%s, %d, %d]",name,ban,totalScore);
}
String getName() {return name;}
int getBan() {return ban;}
int getTotalScore() {return totalScore;}
@Override
public int compareTo(Student9_1 s) {
return s.totalScore-this.totalScore;
}
}
public class Study9_1 {
public static void main(String[] args) {
Stream<Student9_1> studentStream = Stream.of(
new Student9_1("aaa", 3, 300),
new Student9_1("bbb", 2, 200),
new Student9_1("ccc", 2, 150),
new Student9_1("ddd", 1, 300),
new Student9_1("eee", 3, 200),
new Student9_1("fff", 1, 200),
new Student9_1("ggg", 3, 200)
);
studentStream.sorted(Comparator.comparing(Student9_1::getBan) //반별로 정렬
.thenComparing(Comparator.naturalOrder())) //기본정렬
.forEach(System.out::println);
}
}
- 스트림의 요소 변환하기 - map()
Stream<R> map(Function<?super T, ? extends R> mapper) //Stream<T>에서 Stream<R>
package chapter14;
import java.io.File;
import java.util.stream.Stream;
public class Study10_1 {
public static void main(String[] args) {
File[] fileArr = { new File("Ex1.java"), new File("Ex1.bak"), new File("Ex2.java"), new File("Ex1"), new File("Ex1.txt")};
Stream<File> fileStream = Stream.of(fileArr);
Stream<String> filenameStream = fileStream.map(File::getName); //map()으로 Stream<File>을 Stream<String>으로 변환
filenameStream.forEach(System.out::println); //모든 파일이름을 출력
fileStream = Stream.of(fileArr); //스트림을 다시 생성
fileStream.map(File::getName) //Stream<File> → Stream<String>
.filter(s->s.indexOf('.')!=-1) //확장자가 없는 것은 제외
.map(String::toUpperCase)
.distinct()
.forEach(System.out::print);;
System.out.println();
}
}
- 스트림의 요소를 소비하지 않고 보기 - peek()
Stream<T> peek(Consumer<? super T> action) //중간연산(스트림 소비 X)
void forEach(Consumer<? super T> action) //최종연산(스트림 소비 O)
package chapter14;
import java.io.File;
import java.util.stream.Stream;
public class Study10_2 {
public static void main(String[] args) {
File[] fileArr = { new File("Ex1.java"), new File("Ex1.bak"), new File("Ex2.java"), new File("Ex1"), new File("Ex1.txt")};
Stream<File> fileStream = Stream.of(fileArr);
Stream<String> filenameStream = fileStream.map(File::getName); //map()으로 Stream<File>을 Stream<String>으로 변환
filenameStream.forEach(System.out::println); //모든 파일이름을 출력
fileStream = Stream.of(fileArr); //스트림을 다시 생성
fileStream.map(File::getName) //Stream<File> → Stream<String>
.filter(s->s.indexOf('.')!=-1) //확장자가 없는 것은 제외
.map(String::toUpperCase)
.peek(s->System.out.printf("extension=%s%n", s))
.distinct()
.forEach(System.out::print);;
System.out.println();
}
}
- 스트림의 스트림을 스트림으로 변환 - flatMap()
Stream<String[]> strArrStrm = Stream.of(new String[]{"abc","def","ghi"}, new String[] {"ABC","GHI","JKLMN"});
Stream<Stream<String>> strStrStrm = strArrStrm.map(Arrays::stream);//스트림의 스트림
Stream<Stream<String>> strStrStrm = strArrStrm.flatMap(Arrays::stream); //Arrays.stream(T[])
package chapter14;
import java.util.Arrays;
import java.util.stream.Stream;
public class Study10_3 {
public static void main(String[] args) {
Stream<String[]> strArrStrm = Stream.of(new String[]{"abc","def","ghi"}, new String[] {"ABC","GHI","JKLMN"});
Stream<String> strStrm = strArrStrm.flatMap(Arrays::stream);
strStrm.map(String::toLowerCase) //스트림의 요소를 모두 소문자로 변경
.distinct() //중복 제거
.sorted() //정렬
.forEach(System.out::println);
System.out.println();
String[] lineArr = {
"abc def ghi",
"stream is not easy"
};
Stream<String> lineStream = Arrays.stream(lineArr);
lineStream.flatMap(line->Stream.of(line.split(" +"))) //정규식기호 하나이상의 공백
.map(String::toLowerCase)
.distinct()
.sorted()
.forEach(System.out::println);
}
}
728x90