본문 바로가기
java

Lambda 05 Stream

by 킹차니 2021. 12. 27.

 

스트림

다양한 데이터 소스를 표준화된 방법으로 다루기 위한 것

(데이터 소스 = 컬렉션, 표준화된 방법 = List, Set, Map)

List, Set, Map, 배열은 모두 사용 방법이 다르다. 하지만 JDK 1.8부터 Stream 등장하면서 이들을 같은 방법으로 사용할 수 있게 되었다.

public class Ex{
    public static void main(String[] args) {
    
		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);
        Stream<Double> randomStream = Stream.generate(Math::random);
        IntStream intStream2 = new Random().ints(5);
    }
}

 

 

스트림 사용 순서 :

  1. 스트림 만들기
  2. 중간 연산(n번 가능)
  3. 최종 연산(0~1번)
stream.distinct().limit(5).sorted().forEach(System.out::println);
     //distinct ~ sorted까지 중간연산   forEach는 최종연산

 

 

스트림은 데이터 소스로부터 데이터를 읽기만할 뿐 변경하지 않는다.

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> sortedList = list.steam().sorted() // list를 정렬해서
			.collect(Collectors.toList());//새로운 list에 저장

System.out.println(list);        // [3, 1, 5, 4, 2] 데이터를 변경하지는 않는다!!!
System.out.println(sortedList);  // [1, 2, 3, 4, 5]

 

 

스트림은 Iterator처럼 일회용이다. (필요하면 다시 스트림을 생성해야 한다.)

strStream.forEach(System.out::println); //모든 요소를 화면에 출력 (최종연산)
int numOfStr = strStream.count(); // ERROR! 스트림이 이미 닫힘

 

 

최종연산 전까지 중간연산이 수행되지 않는다. - 지연된 연산

IntStream intStream = new Random().ints(1, 46);  // 1~46범위의 무한 스트림
intStream.distinct().limit(6).sorted()           //중간 연산
			.forEach(i -> System.out.print(i+","); //최종 연산

 

 

스트림은 작업을 내부 반복으로 처리한다.

for(String str : strList)
	System.out.println(str);

//스트림을 사용하여 아래처럼 바꿀 수 있다.
stream.forEach(System.out::println);

//스트림으로 사용한 부분은 결국 아래 부분과 같다.
void forEach(Consumer<? super T> action){
	Objects.requireNonNull(action); // 매개변수 null체크
	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>보다 더 많이 제공 (예로 IntStream은 sum, average같은 메소드를 제공한다.)

 

 

 


스트림 만들기

Collection인터페이스의 stream()으로 컬렉션을 스트림으로 변환

Stream<E> stream(); //Collection인터페이스의 메소드

 

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> intStream = list.stream(); // list를 스트림으로 변환

//스트림의 모든 요소를 출력 (forEach는 최종연산)
intStream.forEach(System.out::print); //12345
intStream.forEach(System.out::print); //ERROR!!! Stream is already closed

//Stream에 대해 최종연산을 수행하면 Stream은 닫힌다.

 

🟢 객체 배열

< !! 객체 배열로부터 스트림 생성하기 >

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"}, 0, 3); //인덱스0~2까지로

 

🟢 기본형 배열

< !! 기본형 배열로부터 스트림 생성하기 >

InsStream intStream1 = IntStream.of(int... values) //Stream이 아니라 IntStream
InsStream intStream2 = IntStream.of(int[])
InsStream intStream3 = Arrays.stream(int[])
InsStream intStream4 = Arrays.stream(int[], array, int startInclusive, int endExclusive);

 

🟢 난수

< !! 난수를 갖는 스트림 생성하기 >

IntStream intStream = new Random().ints(); //무한 스트림
intStream.limit(5).forEach(System.out::println); //5개의 요소만 출력한다.

IntStream intStream = new Random().ints(5); //크기가 5인 난수 스트림을 반환
// ints(), longs(), doubles()는 각 범위 내에서 난수 스트림을 만들어서 반환해준다.

 

🟢  특정 범위

< !! 특정 범위의 정수를 요소로 갖는 스트림 생성하기 >

IntStream intStream = IntStream.range(int begin, int end)
IntStream intStream = IntStream.rangeClosed(int begin, int end)

IntStream intStream = IntStream.range(1, 5);        // 1, 2, 3, 4
IntStream intStream = IntStream.rangeClosed(1, 5);  // 1, 2, 3, 4, 5

 

🟢  람다식

< !! 람다식으로 부터 스트림 만들기 - iterate(), generate() >

static <T> Stream<T> iterate(T seed, UnaryOperator<T> f); //이전 요소에 종속적
static <T> Stream<T> generate(Supplier<T> s); //이전 요소에 독립적

iterate()는 이전 요소를 seed로 해서 다음 요소를 계산한다.

Stream<Integer> evenStream = Stream.iterate(0, n→n+2); // 0, 2, 4, 6
// n -> n + 2
// 0 -> 0 + 2
// 2 -> 2 + 2
// 4 -> 4 + 2

generate()는 seed를 사용하지 않는다.

Stream<Double> randomStream = Stream.generate(Math::random);
Stream<Integer> oneStream = Stream.generate(()-> 1); // 1, 1, 1, 1.....

 

 

🟢  파일

< !! 파일을 소스로 하는 스트림 생성하기 >

Stream<Path> Files.list(Path dir) //Path는 파일 또는 디렉토리

Stream<String> Files.lines(Path path) // 파일내용을 라인 단위로
Stream<String> Files.lines(Path path, Charset cs)
Stream<String> Files.lines() // BufferedReader 클래스의 메소드

 

 

출처: 남궁성님 유튜브 강의
https://www.youtube.com/user/MasterNKS

'java' 카테고리의 다른 글

Optional  (0) 2021.12.30
Lambda 06 Stream의 연산 (중간 연산과 최종 연산)  (0) 2021.12.29
Lambda 04 메소드 참조  (0) 2021.12.26
Lambda 03 Predicate의 결합  (0) 2021.12.26
Lambda 02 - java.util.function 패키지  (0) 2021.12.23