💡 스트림 생성
스트림의 소스가 될 수 있는 대상은 배열, 컬렉션, 임의의 수 등 다양하다.
컬렉션
컬렉션의 최상위 인터페이스인 Collection에 stream()이 정의되어 있다.
그래서 Collection의 하위 인터페이스인 List와 Set을 구현한 클래스들은 모두 이 메서드로 생성 가능하다.
Stream<T> Collection.stream()
List로부터 스트림을 생성하는 코드의 예시
List<Integer> list = Arrays.asList(1,2,3,4,5); // 가변인자
Stream<Integer> intStream = list.stream(); // list를 소스로 컬렉션 생성
forEach()는 지정된 작업을 스트림의 모든 요소에 대해 수행한다.
주의할 점은 forEach()가 모든 요소를 소모해 작업 수행 후 같은 스트림에 두번 호출 풀가능하다.
소스의 원본이 소모되는 것이 아닌 생성한 스트림의 요소를 소모한다는 것을 기억하자.
intStream.forEach(System.out::println); // 스트림의 모든 요소 출력
intStream.forEach(System.out::println); // 에러, 스트림이 이미 닫혔다
배열
배열을 소스로 하는 스트림을 생성하는 메서드는 Stream과 Arrays에 static 메서드로 정의되어 있다.
Stream<T> Stream.of(T... values) // 가변인자
Stream<T> Stream.of(T[])
Stream<T> Arrays.stream(T[])
Stream<T> Arrays.stream(T[] array, int startInclusive, int endExclusive)
문자열 배열을 소스로 하는 스트림 생성
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) // Stream이 아닌 IntStream
IntStream IntStream.of(int[])
IntStream Arrays.stream(int[])
IntStream Arrays.stream(int[] array, int startInclusive, int endExclusive)
특정 범위의 정수
IntStream과 LongStream은 지정된 범위의 연속된 정수를 스트림으로 생성해서 반환하는 range()와 rangeClosed() 메서드를 가지고 있다.
IntStream IntStream.range(int begin, int end)
IntStream IntStream.rangeClosed(int begin, int end)
range()의 경우 경계의 끝인 end가 범위에 포함되지 않고 rangeClosed()의 경우는 포함된다.
IntStream intStream = IntStream.range(1, 5); // 1,2,3,4
IntStream intStream = IntStream.rangeClosed(1, 5) // 1,2,3,4,5
임의의 수
난수를 생성하는데 사용하는 Random 클래스에는 아래와 같은 인스턴스 메서드들이 포함된다.
이 메서드들은 해당 타입의 난수들로 이루어진 스트림을 반환한다.
아래 메서드들이 반환하는 스트림은 크기가 정해져있지 않은 ''무한 스트림'' 이므로 limit()을 같이 사용해 스트림의 크기를 제한 해주어야 한다.
IntStream ints()
LongStream longs()
DoubleStream doubles()
IntStream intStream = new Random().ints() // 무한 스트림
intStream.limit(5).forEach(System.out::println); // 5개의 요소만 출력
// 생성할때 유한 스트림으로 만들어주면 limit()을 사용하지 않아도 된다
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
지정된 범위(begin~end)의 난수를 발생시키는 스트림을 얻는 메서드. 단, end는 범위에 포함 X
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)
💡 iterate() & generate()
람다식을 파라미터로 받아 이 람다식에 의해 계산되는 값들을 요소로 무한 스트림 생성
static <T> Stream<T> iterate(T seed, UnaryOperator<T> f)
static <T> Stream<T> generate(Supplier<T> s)
iterate()
iterate()는 씨앗값(seed)로 지정된 값부터 시작해, 람다식 f에 의해 계산된 결과를 다시 seed값으로 해서 계산 반복
아래 스트림은 0부터 시작해서 값이 2씩 계속 증가하는 무한스트림이다.
// 아래 스트림은 0부터 시작해서 값이 2씩 계속 증가하는 무한스트림이다.
Stream<Integer> evenStream = Stream.iterate(0, n->n+2); // 0, 2, 4, 6 ...
evenStream.limit(5).forEach(System.out::println);
System.out.println("-- even 끝 --");
// 결과값
0
2
4
6
8
-- even 끝 --
Generate()
람다식에 의해 계산되는 값을 요소로 하는 무한스트림이지만
iterate()와 달리, 이전 결과를 이용해서 다음 요소를 계산하지 않는다.
// iterate()와 달리, 이전 결과를 이용해서 다음 요소를 계산하지 않는다.
Stream<Double> randomStream = Stream.generate(Math::random);
Stream<Integer> oneStream = Stream.generate(()->1);
randomStream.limit(5).forEach(System.out::println);
System.out.println("-- random 끝 --");
oneStream.limit(5).forEach(System.out::println);
System.out.println("-- one 끝 --");
// 결과값
0.4443310896148389
0.3061832897820761
0.7940177405257327
0.8880947694789408
0.6062985277800407
-- random 끝 --
1
1
1
1
1
-- one 끝 --
Process finished with exit code 0
주의할 점은 generate()의 파라미터 타입은 Supplier이므로 파라미터가 없는 람다식만 허용한다.
공통점
iterate()와 generate()에 의해 생성된 스트림을 아래와 같이 기본형 스트링 타입의 참조변수로 다룰 수 없다.
IntStream evenStream = Stream.iterate(0, n->n+2); // 에러
DoubleStream randomStream = Stream.generate(Math::random); // 에러
굳이 필요하다면 아래와 같이 mapToInt()와 같은 메서드로 변환을 해야 한다.
IntStream evenStream = Stream.iterate(0, n->n+2).mapToInt(Integer::valueOf);
Stream<Integer> stream = evenStream.boxed(); // IntStream -> Stream<Integer> 변환
💡 파일
java.nio.file.Files는 파일을 다루는데 필요한 유용한 메서드들을 제공한다.
list()는 지정된 디렉터리에 있는 파일의 목록을 소스로 하는 스트림을 생성해서 반환한다.
기본 형식
Path는 하나의 파일 또는 경로를 의미한다.
Stream<Path> Files.list(Path dir);
파일의 한 Line을 요소로 하는 스트림도 있다.
아래의 메서드는 BufferedReader 클래스에 속한 메서드로 파일 뿐 아니라,
다른 입력대상으로부터 데이터를 행 단위로 읽을 수 있다.
Stream<String> lines()
💡 Empty Stream
요소가 없는 빈 스트림을 생성한다.
스트림 연산 수행 결과가 하나도 없을때 null 대신 빈 스트림을 반환하게 해준다.
Stream emptyStream = Stream.empty(); // 빈 스트림 생성
long count = emptyStream.count(); // count 값은 0 이다.
💡 concat()
두 스트림을 연결하는 메서드이며, 연결하려는 스트림의 요소 간 타입이 일치해야 한다.
String[] str1 = {"123", "456", "789"};
String[] str2 = {"ABC", "DEF", "GHI"};
Stream<String> strs1 = Stream.of(str1);
Stream<String> strs2 = Stream.of(str2);
Stream<String> reslutStream = Stream.concat(strs1, strs2); // 두 스트림 연결
'Languages > Java' 카테고리의 다른 글
Try-With-Resource (0) | 2023.03.25 |
---|---|
Multi Catch Block (0) | 2023.03.25 |
Stream (0) | 2023.03.01 |
Single & Multi Thread (0) | 2023.03.01 |
Thread (0) | 2023.03.01 |