: 다양한 데이터 소스(컬렉션, 배열, 파일 등)를 표준화된 방법으로 다루기 위한 것
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"}); // 배열 -> 스트림
String[] strArr = new String[] {"a", "b", "c", "d"}; // 배열
Stream<String> strStream = Arrays.stream(strArr); // 배열 -> 스트림
Stream<Integer> evenStream = Stream.iterate(0, n->n+2); // 람다식 -> 스트림
Stream<Double> randomStream = Stream.generate(Math::random); // 메서드 참조 -> 스트림
// Int형 최적화 Stream : IntStream
IntStream intStream = new Random().ints(5); // 난수 스트림
데이터 소스를 스트림으로 만들기
중간 연산(0 ~ n번 가능) : 연산 결과가 스트림인 연산. 반복적으로 적용 가능
최종 연산(0 ~ 1번만 가능) : 연산 결과가 스트림이 아닌 연산. 스트림의 요소를 소모
List<Integer> list = Arrays.asList(3, 4, 1, 2, 1, 1, 2, 5, 2);
Stream<Integer> intStream = list.stream(); // 스트림 만들기
intStream.distinct() // 중간 연산 - 중복 제거
.sorted() // 중간 연산 - 정렬
.forEach(s-> System.out.print(s+" ")); // 최종 연산 - 출력
intStream.forEach(System.out::println); // 에러
스트림은 데이터 소스로부터 데이터를 읽기만할 뿐 변경하지 않는다.(Read only)
List<Integer> list = Arrays.asList(3,1,5,4,2);
List<Integer> sortedList = list.stream()
.sorted()
.collect(Collections.toList()); // 정렬해서 sortedList에 저장
System.out.println(list); // [3,1,5,4,2]
System.out.println(sortedList) ; // [1,2,3,4,5]
스트림은 Iterator
처럼 일회용이다. 최종 연산 후 필요하면 다시 스트림을 생성해야한다.
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> intStream = list.stream(); // 스트림 만들기
intStream.forEach(System.out::println); // 최종 연산 - 출력
intStream.forEach(System.out::println); // 에러
스트림은 최종 연산 전까지 중간 연산이 수행되지 않는다. -> 지연된 연산
IntStream intStream = new Random().ints(1, 46); // 1~46 범위의 난수를 생성하는 무한 스트림
intStream.distinct().limit(6).sorted()
.forEach(i -> System.out.println(i + " ")); // 로또 번호 6개 출력하는 연산
스트림은 작업을 내부 반복으로 처리한다.
스트림의 작업을 병렬로 처리할 수 있다. - 병렬 스트림
Stream<String> strStream = Stream.of("dd", "aaa", "c", "bb");
int sum = strStream.parallel()
.mapToInt(String::length)
.sum(); // 병렬 스트림
멀티쓰레드로 데이터를 동시에 처리하고 싶을 때 사용한다. 빅데이터를 병렬로 처리해서 작업속도를 높일 수 있다.
기본이 직렬 스트림이다.
병렬로 스트림을 수행하고 싶을 때 parallel()
추가
다시 직렬로 바꾸고 싶을때 sequential()
추가
기본형 스트림 - IntStream, LongStream, DoubleStream
오토 박싱&언박싱의 비효율 제거된다.
: Stream<T>
은 참조형 타입만 올 수 있다. 만약 int[] 배열을 스트림으로 만든다면 int 기본형 타입이 Integer 참조형 타입으로 오토 박싱된다.
따라서 빅데이터를 다룰 때 효율과 성능을 높이기 위해서 기본형 스트림을 사용한다.
숫자와 관련된 유용한 메서드를 Stream<T>
보다 많이 제공한다
: 기본형 스트림의 요소들은 기본형 타입을 보장하기 때문에 max()
, min()
, average()
, sum()
과 같은 숫자와 관련된 유용한 메서드들을 더 제공한다.
Collection 인터페이스의 stream()
으로 컬렉션을 스트림으로 변환
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> intStream = list.stream(); // 스트림 만들기
객체 배열로부터 스트림 생성
Stream<T> Stream.of(T...values) // 가변 인자
Stream<T> Stream.of(T[])
Stream<T> Arrays.stream(T[])
// 배열의 인덱스 from ~ to(to는 포함x)까지 스트림 생성
Stream<T> Arrays.stream(T[] array, int from, int to)
Integer[] intArr = {1,2,3,4,5}; //int[] 는 불가능
Stream<Integer> intStream = Arrays.stream(intArr) ; // intArr가 참조형(Integer)이여야 가능
Stream<String> strStream = Stream.of("a", "b", "c")
Stream<String> strStream = Stream.of(new String[]{"a", "b", "c"});
Stream<String> strStream = Arrays.stream(new String[]{"a", "b", "c"});
Stream<String> strStream = Arrays.stream(new String[]{"a", "b", "c"}, 0, 3);
기본형 배열로부터 스트림 생성
IntStream IntStream.of(int...values) // 가변 인자
IntStream IntStream.of(int[])
IntStream Arrays.stream(int[])
// 배열의 인덱스 from ~ to(to는 포함x)까지 스트림 생성
IntStream Arrays.stream(int[] array, int from, int to)
IntStream intStream2 = IntStream.of(1, 2, 3);
IntStream intStream3 = IntStream.of(new int[]{1, 2, 3});
IntStream intStream4 = Arrays.stream(new int[]{1, 2, 3});
IntStream intStream5 = Arrays.stream(new int[]{1, 2, 3, 4, 5}, 1, 4);
intStream5.forEach(s -> System.out.print(s + " "));
intStream5 : 2 3 4
임의의 수를 요소로 갖는 스트림 생성
IntStream intStream = new Random().ints(); // 무한 스트림
intStream.limit(5).forEach(System.out::println); // 무한 스트림에서 5개의 요소만 출력
IntStream intStream = new Random().ints(5); // 유한 스트림
ints()
, longs()
, doubles()
메서드로 난수 스트림을 만들 수 있다.limit()
를 통해 무한 스트림에서 n개의 요소만 출력 할 수 있다.new Random().ints(5);
: 난수 스트림을 만들 때 크기를 지정해줄 수도 있다.ints(), longs(), doubles()의 기본 범위
Integer.MIN_VALUE <= ints() <= Integer.MAX_VALUE
Long.MIN_VALUE <= longs() <= Long.MAX_VALUE
0.0 <= doubles < 1.0
지정된 범위의 난수를 요소로 갖는 스트림 생성
// 무한 스트림
IntStream ints(int begin, int end)
LongStream longs(long begin, long end)
DoubleStream doubles(double begin, double 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)
ints(int begin, int end)
: begin ~ end 범위(end 포함x)의 난수를 생성하는 스트림ints(long streamSize, int begin, int end)
: begin ~ end 범위(end 포함x)의 난수를 streamSize만큼 생성하는 스트림특정 범위의 정수를 요소로 갖는 스트림 생성
IntStream IntStream.range(int begin, int end)
IntStream IntStream.rangeClosed(int begin, int end)
IntStream intS = IntStream.range(1, 5) ; // 1,2,3,4
IntStream intS = IntStream.rangeClosed(1, 5) ; // 1,2,3,4,5
람다식을 소스로 하는 스트림 생성
static <T> Stream<T> iterate(T seed, UnaryOperator<T> f) // 이전 요소에 종속적
static <T> Stream<T> generate(Supplier<T> s) // 이전 요소에 독립적
이 두 메서드는 매개변수로 받은 람다식에 의해 계산되는 값들을 요소로 하는 무한 스트림을 생성
T seed
는 초기값
: 이전 요소를 seed로 해서 다음 요소를 계산한다.
Stream<Integer> evenStream = Stream.iterate(0, n -> n +2);
evenStream.limit(10).forEach(s -> System.out.print(s + " "));
0 2 4 6 8 10 12 14 16 18
초기값이 없으며 이전 요소에 독립적이다.
Stream<Integer> oneStream = Stream.generate(() -> 1);
oneStream.limit(10).forEach(s -> System.out.print(s + " "));
1 1 1 1 1 1 1 1 1 1
파일을 소스로 하는 스트림 생성
Stream<Path> Files.list(Path dir)
Stream<String> Files.lines(Path path)
Stream<String> Files.lines(Path path, Charset cs)
Stream<String> lines() // BufferedReader 클래스의 메서드
요소가 하나도 없는 비어있는 스트림
Stream emptyStream = Stream.empty(); // 비어있는 스트림 생성 및 반환
long cnt = emptyStream.count(); // 비어있기 때문에 당연히 0
: 연산 결과가 스트림인 연산. 0 ~ n번 사용 가능
중간 연산 | 설명 |
---|---|
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) | 스트림의 요소를 정렬 |
map(), flatMap()
반환타입 | 중간 연산 | 설명 |
---|---|---|
Stream<R> | map(Function<T, R> mapper) | |
IntStream | mapToInt(ToIntFunction<T> mapper) | |
LongStream | mapToLong(ToLongFunction<T> mapper) | |
DoubleStream | mapToDouble(ToDoubleFunction<T> mapper) | |
Stream<R> | flatMap(Function<T, Stream<R>> mapper) | 스트림의 요소를 변환한다. |
IntStream | flatMapToInt(Function<T, IntStream> mapper) | |
LongStream | flatMapToLong(Function<T, LongStream> mapper) | |
DoubleStream | flatMapToDouble(Function<T, DoubleStream> mapper) |
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
skip(3)
: 123 건너뛴다.limit(5)
: 4부터 5개 요소만 잘라낸다.Stream<T> filter(Predicate<T> predicate)
: 조건에 맞지 않는 요소를 제거한다.
IntStream intStream = IntStream.rangeClosed(1, 10); // 12345678910
intStream.filter(i -> i % 2 == 0).forEach(System.out::print);
246810
IntStream intStream = IntStream.rangeClosed(1, 10); // 12345678910
intStream.filter(i -> i % 2 == 0 && i % 3 == 0).forEach(System.out::print);
6
intStream.filter(i -> i % 2 == 0).filter(i -> i % 3 == 0).forEach(System.out::print); );
: filter를 2번 써서 &&
와 같은 동작을 수행할 수 있다.Stream<T> distinct()
: 중복을 제거한다.
IntStream intStream = IntStream.of(1,1,2,2,3,4,4,5);
intStream.distinct().forEach(System.out::print);
12345
Stream<T> sorted()
: 스트림 요소의 기본 정렬 기준(Comparable)으로 정렬
Stream<T> sorted(Comparator<T> comparator)
: 지정된 Comparator으로 정렬
Stream<String> strStream = Stream.of("dd", "aaa", "CC", "cc", "b");
// 기본 정렬 -> 출력 결과 : CCaaabccdd
strStream.sorted(); // String 클래스의 Comparable
strStream.sorted(Comparator.naturalOrder()); // Comparator 클래스에 구현된 기본 정렬 기준
strStream.sorted((s1, s2) -> s1.compareTo(s2)); // 람다식
strStream.sorted(String::compareTo); // 메서드 참조
// 역순 정렬 -> 출력 결과 : ddccbaaaCC
strStream.sorted(Comparator.reverseOrder()) // 기본 정렬의 역순
strStream.sorted(Comparator.<String>naturalOrder().reversed()) // 잘안씀
// 기본 정렬(대소문자 구분 X) -> 출력 결과 : aaabCCccdd
strStream.sorted(String.CASE_INSENSITIVE_ORDER)
// 역순 정렬(대소문자 구분 X) -> 출력 결과 : ddCCccbaa 오타 아님(대문자가 앞에 온다.)
strStream.sorted(String.CASE_INSENSITIVE_ORDER.reversed())
// 별도 기준 정렬 -> 출력 결과 : bddCCccaaa
strStream.sorted(Comparator.comparing(String::length)) // 문자열 길이 순 정렬
strStream.sorted(Comparator.comparingInt(String::length))
// 별도 기준 역순 정렬 -> 출력 결과 : aaaddCCccb
strStream.sorted(Comparator.comparing(String::length).reversed())
Comparator의 comparing()으로 정렬 기준을 제공
Comparator<T> comparing(Function<T, U> keyExtractor)
Comparator<T> comparing(Function<T, U> keyExtractor, Comparator<U> keyComparator)
thenComparing() : 추가 정렬 기준을 제공할 때 사용
Comparator<T> thenComparing(Comparator<T> other)
Comparator<T> thenComparing(Function<T, U> keyExtractor)
Comparator<T> thenComparing(Function<T, U> keyExtractor, Comparator<U> keyComparator)
import java.util.*;
import java.util.stream.*;
class Student implements Comparable<Student> {
private String name;
private int ban;
private int totalScore;
Student(String name, int ban, int totalScore) {
this.name = name;
this.ban = ban;
this.totalScore = totalScore;
}
// toString() 오버라이딩
public String toString() {
return String.format("[%s, %d, %d]", name, ban, totalScore);
}
public String getName() { return name; }
public int getBan() { return ban; }
public int getTotalScore() { return totalScore; }
// 총점 내림차순으로 기본 정렬
public int compareTo(Student s) {
return s.totalScore - this.totalScore;
}
}
class Ex14_5 {
public static void main(String[] args) {
Stream<Student> studentStream = Stream.of(
new Student("이빛나", 3, 300),
new Student("김자바", 1, 200),
new Student("안정호", 2, 100),
new Student("박코딩", 2, 150),
new Student("최자연", 1, 200),
new Student("연보라", 3, 290),
new Student("정빛나", 3, 180)
);
studentStream.sorted(Comparator.comparing(Student::getBan)
.thenComparing(Comparator.naturalOrder()))
.forEach(System.out::println);
}
}ㅤ
[김자바, 1, 200]ㅤ
[최자연, 1, 200] ㅤ
[박코딩, 2, 150]ㅤ
[안정호, 2, 100]ㅤ
[이빛나, 3, 300]ㅤ
[연보라, 3, 290]ㅤ
[정빛나, 3, 180]
studentStream.sorted(Comparator.comparing(Student::getBan).reversed()
.thenComparing(Student::getName))
.forEach(System.out::println);
[연보라, 3, 290]ㅤ
[이빛나, 3, 300]ㅤ
[정빛나, 3, 180]ㅤ
[박코딩, 2, 150]ㅤ
[안정호, 2, 100]ㅤ
[김자바, 1, 200]ㅤ
[최자연, 1, 200]ㅤ
스트림의 요소 변환
import java.io.*;
import java.util.stream.*;
class Ex14_6 {
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);
fileStream.map(File::getName) // Stream<File> -> Stream<String>
.filter(s -> s.indexOf('.') != -1) // 확장자 없는 파일 삭제
.map(s -> s.substring(s.indexOf('.') + 1)) // 확장자명만 추출
.map(String::toUpperCase) // 대문자로 변경
.distinct() // 중복 제거
.forEach(System.out::print); // JAVABAKTXT
}
}
JAVABAKTXT
스트림의 요소를 소비하지 않고 엿보기
Stream<T> peek(Consumer<T> action)
void forEach(Consumer<T> action)
peek()
은 중간 연산. 스트림의 요소를 소비 XforEach()
는 최종 연산. 스트림의 요소를 소비 OfileStream.map(File::getName) // Stream<File> -> Stream<String>
.filter(s -> s.indexOf('.') != -1) // 확장자 없는 파일 삭제
.peek(s -> System.out.printf("파일명 : %s%n", s))
.map(s -> s.substring(s.indexOf('.') + 1)) // 확장자명만 추출
.peek(s -> System.out.printf("확장자 : %s%n", s))
.map(String::toUpperCase) // 대문자로 변경
.distinct() // 중복 제거
.forEach(System.out::print); // JAVABAKTXT
System.out.println();
파일명 : Ex1.java
확장자 : JAVA
JAVA파일명 : Ex1.bak
확장자 : BAK
BAK파일명 : Ex2.java
확장자 : JAVA
파일명 : Ex1.txt
확장자 : TXT
TXT
스트림의 스트림을 스트림으로 변환
Stream<String[]> strArrStrm = Stream.of(
new String[]{"abc", "def", "jkl"},
new String[]{"ABC", "GHI", "JKL"}
Stream<String> strStrm = strArrStrm.flatMap(Arrays::stream);
String[] strings = strStrm.map(String::toLowerCase)
.distinct()
.sorted()
.toArray(String[]::new);
System.out.println(Arrays.toString(strings));
[abc, def, ghi, jkl]
String[] lineArr = {
"Believe or not It is true",
"Do or do not There is no try",
};
Stream<String> lineStream = Arrays.stream(lineArr);
List<String> list = lineStream.flatMap(line -> Stream.of(line.split(" +")))
.map(String::toLowerCase)
.distinct()
.sorted()
.collect(Collectors.toList());
System.out.println(list);
[believe, do, is, it, no, not, or, there, true, try]