🏃♂️ 들어가기 앞서..
본 게시물은 스터디 활동 중에 작성한 게시물로 자바의 정석-기초편 교재를 학습하여 정리하는 글입니다.
※ 스터디 Page : 〔투 비 마스터 : 자바〕
*해당 교재의 목차 순서와 구성을 참고하여 작성하며
각 내용마다 부족할 수 있는 내용이나 개인적으로 궁금한 점은
추가적인 검색을 통해 채워나갈 예정입니다.
Stream
) 만들기스트림(Stream)으로 작업을 하기 위해서는
당연히 무엇보다도 스트림을 생성하는 방법을 알아야 하는데
이 스트림의 데이터 소스가 될 수 있는 대상은
배열 / 컬렉션 / 임의의 난수 / 람다식 등등 다양하고
각자 만드는 방법이 있다.
Collection
)List, Set 등의 조상,
컬렉션의 최고 조상인 Collection
에는 stream()
메서드가 정의되어 있다.
Stream<E> stream() // Collection 인터페이스에 정의되어 있는 메서드
그렇기 때문에
자연스레 자손인 List나 Set를 구현한 컬렉션 클래스들은
모두 이 stream()
메서드를 통해 스트림을 생성할 수 있다.
List<Integer> list = Arrays.asList(1,2,3,4,5) ; // 가변인자 ( 배열의 길이를 정하지 않고 ) 로
//List 만들기 위한 .asList
Stream<Integer> intStream = list.stream() ; // List -> Stream
Arrays
)배열을 데이터 소스로 하는 스트림을 생성하는 메서드는
Stream
과 Arrays
에
static메서드로 정의되어 있다.
/* Stream */
Stream<T> Stream.of(T...values) // 가변
Stream<T> Stream.of(T[])
/* Arrays */
Stream<T> Arrays.stream(T[])
// index로 원하는 구간의 값들만으로 stream 생성 가능
Stream<T> Arrays.stream(T[] array, int startInclusive, int endExclusive)
Integer[] intArr = {1,2,3,4,5}; //int[] 는 불가능 --> 쓰고싶으면 IntStream 사용해야함.
Stream<Integer> intStream = Arrays.stream(intArr) ; // intArr가 참조형(Integer)이여야 가능하다.
/* String(문자열) Stream 만들기 */
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);
이전 게시물에서도 알아봤던
" 기본형 배열로부터 생성된 스트림 "
즉, 참조형이 아닌 기본형 Stream에서 또한
기본형 배열을 소스로 하는 스트림을 생성하는 메서드도 있다.
/* 기본형 IntStream */
IntStream IntStream.of(int...values)
IntStream IntStream.of(int[])
IntStream Arrays.stream(int[])
IntStream Arrays.stream(int[] array, int startInclusive, int endExclusive)
// IntStream 뿐만 아니라 LongStream과 DoubleStream도 위 방법과 동일하다.
Random
) & 범위 (Range
)난수를 생성하는데 사용되는 Random
클래스에는
각 타입별 난수로 이루어진 기본형 스트림을 반환하는 메서드를 포함하고 있다.
IntStream ints()
LongStream longs()
DoubleStream doubles()
이 메서드들은 기본적으로
크기가 정해지지 않은 무한 스트림을 반환하기 때문에
limit()
라는 " 스트림 개수 지정(크기 제한) 메서드 "를 사용해서 유한 스트림으로 만들어줘야 한다.
IntStream intStream = new Random().ints(); // 매개변수 값 없기 때문에 " 무한 스트림 "
intStream.limit(5).forEach(System.out::println) ; // 임의의 난수 "5개" 요소만 출력
유한 스트림 : 크기가 정해져있는 스트림
무한 스트림 : 무한한 크기로 값을 가지는 ( 매개변수 값 없는 ints()
, longs()
, doubles()
등 ) 스트림
limit()
말고 유한 스트림으로 만들기 위한 방법으로는
위 난수 스트림 생성 메서드에 매개변수로 크기를 지정해주면 된다.
IntStream ints(long streamSize)
LongStream longs(long streamSize)
DoubleStream doubles(long streamSize)
// 매개변수값 활용 유한 스트림 만들기
IntStream intStream = new Random().ints(5); // 매개변수 값 5 : " 5개의 요소를 가지는 유한 스트림 "
intStream.forEach(System.out::println) ; // 임의의 난수 "5개" 요소만 출력
위 메서드들에 의해 생성된 스트림의 난수는
Integer.MIN_VALUE <= ints() <= Integer.MAX_VALUE
Long.MIN_VALUE <= longs() <= Long.MAX_VALUE
0.0 <= doubles() < 1.0
범위를 갖는다.
※ Random 클래스 _ 지정된 범위의 난수를 요소로 갖는 스트림을 생성하는 메서드
단,end
는 범위에 포함되지 않는다./* 무한 스트림 */ 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)
흔히 범위를 지정해서 사용할 때 range()
를 주로 사용한다.
이는 특정 범위의 정수 요소를 반환하는데
Stream에서도 range
키워드를 통해 특정 범위의 정수 요소를 가지며
당연히 정수 요소이기 때문에
IntStream
과 LongStream
이 해당 메서드를 가지고 있다.
IntStream IntStream.range(int begin, int end)
IntStream IntStream.rangeClosed(int begin, int end)
두 메서드의 차이는
end 값 포함 여부 이다.
range
: end 값 포함 XrangeClosed
: end 값 포함 OIntStream intS = IntStream.range(1, 5) ; // 1,2,3,4
IntStream intS = IntStream.rangeClosed(1, 5) ; // 1,2,3,4,5
lambda
)Stream 클래스에서 람다식을 매개변수를 받는 메서드로는
크게 iterate()
와 generate()
가 있다.
이 두 메서드는
매개변수로 받은 람다식에 의해 계산되는 값들을 요소로 하는
" 무한 스트림 "을 생성한다.
static <T> Stream<T> iterate(T seed, UnaryOperator<T> f)
static <T> Stream<T> generate(Supplier<T> s)
딱 보기에도 두 함수 사이의 차이점이 확연히 보인다.
바로 seed값 이다.
iterator()
는
씨앗값부터 " 시작 "해서
" 람다식 f에 의해 계산된 결과 "를
다시 씨앗값(seed)으로 지정해서 계산을 반복한다.
Stream<Integer> evenStream = Stream.iterate(0, n -> n+2) ;
/*
0 으로 2
2 로 4
4 로 6
.....(무한 스트림)
*/
generate()
는
람다식에 의해 계산되는 값을 요소로하는 무한스트림을 생성 및 반환하는 것은 맞지만
iterator()
와는 달리
이전 결과를 통해 다음 요소를 계산하지 않는다.
또한
위에서 눈치 챘다시피
매개변수인 람다식의 타입이 매개변수가 없는 람다식 인터페이스인 Supplier<T> s
이다.
Stream<Double> randStream = Stream.generate(Math::random) ;
Stream<Integer> oneStream = Stream.generate(() -> 1) ;
❗ *주의점* ❗
▶iterate()
와generate()
에 의해 생성된 스트림을 기본형 스트림 타입 참조변수로 다룰 수 없다.
- 기본형 스트림으로 사용하려면
mapToInt()
mapToLong()
,mapToDouble()
등을 사용해야 함.- 기본형 스트림을 일반적인 제네릭 타입 지정 스트림으로 사용할 땐, 오토박싱 해주는
boxed()
를 사용한다.
Files
) & 빈 (empty
) Streamjava.nio.file.Files
에서는
파일을 다루는데 필요한
유용한 메서드들을 제공한다.
Files.list()
는
지정 디렉토리(dir)에 있는
파일 목록을 소스로 하는 스트림을 생성해 반환한다.
Stream<Path> Files.list(Path dir)
파일 목록에서 더 들어가
한 파일의 한 행(line)을 요소로 하는 스트림을 생성하는 메서드도 있다.
(*보통 로그(Log)파일을 읽을 때 사용한다. )
파일뿐만 아니라
다른 입력대상으로부터도 행 단위 Read가 가능하다.
Stream<String> Files.lines(Path path)
Stream<String> Files.lines(Path path, Charset cs)
Stream<String> lines() // BufferedReader 클래스의 메서드
" 요소가 하나도 없는 말 그대로 비어있는 스트림 "
*" 연산 수행 결과가 없을 땐 ", null보단 빈 스트림을 반환하는 것이 낫다.
Stream emptyStream = Stream.empty(); // 비어있는 스트림 생성 및 반환
long cnt = emptyStream.count(); // 비어있기 때문에 당연히 0