티스토리 뷰

JAVA/정리

[Stream] 스트림 part1

란텔 2016. 7. 16. 19:30

Stream을 사용하면 배열, 컬렉션 클래스 또는 파일에 저장된 데이터들을 같은 방식으로 접근하고 다룰 수 있다.




ex) 컬렉션 클래스와 배열을 스트림으로 선언

        ArrayList<String> list = new ArrayList<>();
        list.add("전북");
        list.add("익산시");
        list.add("신동");
        list.add("영등동");
        list.add("부송동");
        
        Stream<String> stream = list.stream(); //컬렉션 클래스를 스트림으로 선언하는법
        
        //2번째 요소까지만 출력
        stream.limit(2).forEach(System.out::println);
        
 
        int[] arr = {1,2,3};
        IntStream iStream = Arrays.stream(arr); //배열을 스트림으로 선언하는법


forEach메서드를 인자에 콜론을 기준으로 왼쪽에는 참조변수 오른쪽에는 메서드명이 위치 하는 것을 볼 수 있다. 람다식을 사용해보면 알겠지만 람다식의 구현부가 단순히 메서드 하나만을 호출하는 것이라면 위와 같은 형식으로 사용이 가능하다.



Stream은 Iterator(컬렉션클래스에 접근을 도와주는 클래스)와 마찬가지로 한번 사용하고 나면 더 이상 사용할 수 없다. 다시 사용하려면 해당 객체에 대하여 다시 Stream을 선언해야 한다.

        stream.limit(2).forEach(System.out::println);
        //위에서 이미 스트림을 가지고 작업을 하고 있으므로 또 다시 사용하려면 다음과 같이 스트림을 다시 선언
        stream = list.stream(); 
        stream.forEach(System.out::println);





Stream에는 리턴타입이 Stream자체인 중간연산과 최종적으로 한번만 사용하는 최종연산이 있다.


  • 중간 연산 메서드 목록

   메서드

  설명 

 Stream<T> distinct()

 요소 중복 제거

 Stream<T> filter(Predicate<T> p)

 조건에 안맞는 요소 제외

 Stream<T> limit(int size)

 스트림의 요소를 size만큼만 선택

 나머지는 잘라냄

 Stream<T> skip(long n)

 스트림의 요소를 건너 뜀

 Stream<T> peek(Consumer<T> action)

 스트림의 요소 작업 수행 

 Stream<T> sorted()

 Stream<T> (Comparator<T> c)

 스트림 요소를 정렬

 Stream<R> map(Funtion<T,R> mapper)

 DoubleStream mapToDouble(ToDoubleFuntion<T,R> mapper)

 IntStream mapToInt(ToIntFuntion<T,R> mapper)

 LongStream mapToLong(ToLongFuntion<T,R> mapper)

 스트림의 요소를 반환

 Stream<R> flatMap(Function<T, Stream<R>> mapper)

 DoubleStream flatMapToDouble(Function<T, DoubleStream> mapper) 

 IntStream flatMapToInt(Function<T, IntStream> mapper)

 LongStream flatMapToLong(Function<T, LongStream> mapper)

 스트림의 요소를 반환 

  • 최종 연산 메서드 목록

 void forEach() 

 각 요소에 접근. 지정된 작업 수행 

 long count()

 스트림 요소의 갯수 반환

 Optional<T> max(Comparator<? super T> comparator)

 Optional<T> min(Comparator<? 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,? super T,U> accumulator,                

    BinaryOperator<U> combiner)

스트림의 요소를 하나씩 줄여가면서 계산 

 R collect(Collector<? super T,A,R> collector)

 R collect(Supplier<R> supplier, BiConsumer<R,? super T> accumulator,         BiConsumer<R,R> combiner)

스트림의 요소를 수집 

****중간 연산 메서드는 map과 flatMap 최종 연산 메서드는 collect가 핵심****




  • Collection 구현체를 스트림으로..생성

컬렉션의 최고 조상 인터페이스 Collection에 stream() 메서드가 정의되어 있다.

그렇기 때문에 그 자손인 List, Set을 구현한 클래스들은 모두 이 stream()메서드로 Stream의 생성이 가능하다.

List<String> list =  new ArrayList<>();
Stream<String> s = list.stream();



  • 배열을 스트림으로....생성

배열을 Stream으로 생성하는 메서드는 Stream과 Arrays에 static메서드로 정의되어 있다.

        String[] sArr = new String[]{"홍","길","동"};
        Stream<String> lStream =  Arrays.stream(sArr);
        Stream<String> lStream1 =  Arrays.stream(sArr, 13);
        Stream<String> lStream2 =  Stream.of(sArr);


Arrays.stream(T[] t)

Arrays.stream(T[] t, int start, int end)

Stream.of(T[] t)

두번째 메서드의 start와 end인자는 배열을 스트림으로 생성하되 시작값과 끝값 사이를 대상으로 한다는 것이다. 끝값은 포함되지 않는다.



  • 지정된 범위의 정수를 스트림으로 생성
        IntStream is1 = IntStream.range(110);
        IntStream is2 = IntStream.rangeClosed(110);


LongStream과 IntStream의 range, rangeClosed메서드를 이용하면 지정된 범위의 정수를 요소로 하는 스트림을 생성할 수 있다.



  • 임의의 난수 생성

임의의 난수를 생성하는 Random클래스에는 다음과 같은 인스턴스 메서드가 멤버로 존재한다.

 IntStream 

 ints()

 ints(long size)

 ints(int begin, int end)

 ints(long size, int begin, int end)

 LongStream

 longs()

 longs(long size)

 longs(long begin, long end)

 longs(long size, long begin, long end)

 DoubleStream

 doubles()

 doubles(long size)

 doubles(double begin, double end)

 doubles(long size, double begin, double end)


        //1번        
        IntStream iStream  = new Random().ints(); 
        iStream.limit(3).forEach(System.out::println);
        //2번
        IntStream is = new Random().ints(1,46);
        is.distinct().limit(5).forEach(System.out::println);    
        //3번
        DoubleStream ds1 = new Random().doubles(5, 0, 0.5);
        ds1.forEach(System.out::println);
        
        System.out.println(Integer.MIN_VALUE+"<= ints의 값 범위 <="+Integer.MAX_VALUE);
        System.out.println(Long.MIN_VALUE+"<= longs의 값 범위 <="+Long.MAX_VALUE);
cs

1번 코드를 보면 Random인스턴스를 생성하면서 ints()를 호출하고 있다.

하지만 ints(), longs(), doubles()는 스트림의 길이에 제한이 없기 때문에 무한하게 난수를 가져오게 된다.

그렇기 때문에 그 밑에 limit(int size)를 이용해서 무한 스트림에 길이를 정해주면 더이상 무한하지 않게 된다.


2번 코드에서는 ints(1, 46)처럼 ints메서드에 인자값을 넣었다.

맨 밑에 Integer.MIN_VALUE, Integer.MAX_VALUE가 ints가 생성하는 난수의 범위인데, 이 범위 대신 위처럼 인자값을 넣으면 1에서 45값(end는 포함되지 않는다.)을 대상으로 난수를 생성하는 스트림을 반환하게 된다.


그 다음을 보면 distinct()메서드로 스트림 요소의 중복을 제거하고 limit(int n)으로 대상으로 할 스트림 요소의 길이를 제한하고 있다.(로또 번호를 생각하면서 짬.)


3번 코드는 doubles를 호출해봤다. 3개의 인자가 있는데 첫번째는 스트림 요소의 길이를 제한하는 값이고, 두번째와 세번째는 난수를 생성하는 대상의 시작값과 끝값이다.(끝값은 포함하지 않음.)





Stream클래스에는 iterate()와 generate()메서드가 있는데, 이 두 메서드는 람다식을 매개변수로 받아서 계산되는 값을 요소로 하는 무한한 스트림을 생성한다.

 static <T> Stream<T>     iterate(T seed, UnaryOperator<T> f)

 static <T> Stream<T>     generate(Supplier<T> s)


        Stream<Integer> s = Stream.iterate(1, n->n+2);        
        s.limit(10).forEach((n) -> {System.out.print(n+",");});
        
        Stream<Integer> s1 = Stream.generate(()->1);
        s1.limit(10).forEach((n) -> {System.out.print(n+",");});

        

iterate의 첫번 째 인자값은 씨앗값 이라고 해서  두 번째 인자의 람다식이 맨 처음 이 씨앗값을 대상으로 계산하게 된다.

그래서 람다식의 결과로 나온 값을 대상으로 다시 두 번째 람다식의 계산으로 나온 값이 스트림의 요소로 추가 되며, 무한한 스트림을 생성하게 되는데 limit메서드로 길이를 제한 함으로써 유한하도록 하고있다.

첫값은 1이고 2씩 증가하기 때문에 결과는 1,3,5,7,9,11,13,15,17,19이 나온다.


generate는 람다식에 의해서 계산되는 값을 요소로 하는 무한한 스트림을 생성하지만, iterate와는 달리 이전 결과를 이용해서 다음요소를 계산하지 않는다. (본인이 생각하기에는 별로 쓸모가 없어 보인다.)


iterate()와 generate()로 생성된 스트림은 IntStream, LongStream, DoubleStream과 같은 기본형 타입 스트림이 참조변수가 될 수 없다.




  • 지정된 디렉토리에 있는 파일의 목록을 요소로 하는 스트림을 반환

java.nio.file패키지에 있는 Files클래스의 list(Path dir)메서드를 이용하면 파일 목록을 요소로 가지고 있는 스트림을 생성 가능하다.


메서드 정보

         static Stream<Path>  list(Path dir)



예제

         Stream<Path> fileStream = null;
         Path path = FileSystems.getDefault().getPath("C:\\tmps\\");
 
         try {
 
            fileStream = Files.list(path);
            fileStream.forEach(p -> { System.out.println(p.getFileName()); });
 
         } catch (IOException e) {
            e.printStackTrace();
         }
cs





  • 비어 있는 스트림

요소가 없는 비어있는 스트림을 생성할 수도 있다. null보다 비어있는 스트림을 반환하는 것이 낫다.

        Stream<String> empty = Stream.empty();



'JAVA > 정리' 카테고리의 다른 글

[Stream] 스트림의 정렬(sorted), 요소 변환(map), 배열요소를 요소로 변환(flatMap)  (0) 2016.07.16
[Lambda Expression] 람다식  (0) 2016.05.02
[generics] 제네릭스  (0) 2016.04.21
익명 클래스  (0) 2016.04.07
Thread  (0) 2016.01.14
Comments
최근에 올라온 글
최근에 달린 댓글
TAG
more
Total
Today
Yesterday