자바 스트림 정리1-스트림 생성

Published: by Creative Commons Licence

오랜만에 내가 하고싶은 공부를 하고 정리를 해보려고 한다. 거의 한달동안은 이직을 준비하면서 코테공부나 회사에 맞는 공부를 하다보니 노트정리도 못하고 방치를 하고 살았다. 이직이 확정된 오늘 부터는 다시 공부를 시작해 보려고 한다. 그동안 JDK 버전은 계속 올라가는데 난 항상 예전 방식으로 개발을 했었고 왠지 모르게 세련되지 못한 코딩을 한 것 같아 모던한 자바 코딩을 학습해 보려고 한다. 내가 알고 써보고 좋다고 느껴야 주변에 전파를 할 수 있지 않을까 라는 생각으로 열심히 해봐야 겠다.

Stream이란?

자바 8에서 추가한 스트림(Streams)은 함수형 인터페이스 람다를 활용할 수 있는 기술이다. 자바 8 이전에는 배열 또는 컬렉션 인스턴스를 다루는 방법은 for 또는 foreach 문을 돌면서 요소 하나씩을 꺼내서 처리를 했다면 java 8 이후에는 스트림과 람다를 이용하여 코드의 양을 대폭 줄이고 조금 더 간결하게 코드를 작성할 수 있다. 또 하나의 장점은 parallel을 이용해서 병렬처리(multi-threading)가 가능하다는 점이다. 쓰레드를 이용해 많은 요소들을 빠르게 처리할 수 있다.

스트림은 크게 3단계로 동작한다. 배열,컬렉션,파일 등으로부터 스트림을 생성, 스트임을 필터링하거나 요소를 알맞게 변환하는 중간연산, 최종적으로 결과를 도출하는 단말연산으로 나뉜다.

컬렉션으로 Stream 생성

@Test
void test1(){
    // 컬렉션 구현 클래스의 stream 생성
    List<String> list = List.of("test1", "test2", "test3");
    Stream<String> stream = list.stream();
    stream.forEach(System.out::println);
}

배열(Arrays)로 Stream 생성

@Test
void test2(){
    // Arrays.stream 메소드를 이용해 배열스트림 생성
    String[] arr = new String[]{"test1", "test2", "test3"};
    Stream<String> stream = Arrays.stream(arr, 0, 2);
    stream.forEach(System.out::println);
}

병렬 Stream 생성

병렬 Stream 생성

나의 개인PC의 경우 CPU가 8코어라 기본 쓰레드가 8개가 생성되어 병렬로 처리된다. 총 11개의 리스트는 두번의 병렬처리로 처리된다.

@Test
    void test3(){
        // 병렬스트림(parallelStream) 생성
        List<String> list = List.of("test1", "test2", "test3", "test4", "test5", "test6", "test7", "test8", "test9", "test10", "test11");
        Stream<String> stream = list.parallelStream();
        stream.forEach(str -> {
            System.out.println(str + " : " + Thread.currentThread().getName());
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) { }
        });
    }
}

IntStream, LongStream, DoubleStream, 가변 매개변수 스트림(Stream.of)

자바의 기본타입에 특화된 Stream생성 및 가변 매개변수(variable parameter)를 전달받아 스트림을 생성할 수 있다.

@Test
void test4(){
    IntStream intStream = IntStream.range(1, 5);
    intStream.forEach(System.out::println);

    IntStream closedIntStream = IntStream.rangeClosed(1, 5);
    closedIntStream.forEach(System.out::println);

    LongStream longStream = LongStream.range(1, 5);
    longStream.forEach(System.out::println);

    DoubleStream doubleStream = DoubleStream.of(0.1, 0.2, 0.3, 0.4);
    doubleStream.forEach(System.out::println);
}

Random클래스를 활용한 난수 Stream

@Test
void test5(){
    IntStream intStream = new Random().ints().limit(5);
    intStream.forEach(System.out::println);

    DoubleStream doubleStream = new Random().doubles(5);
    doubleStream.forEach(System.out::println);
}

Files(java.nio.Files)로 Stream 생성

@Test
void test6() throws Exception{
    Path path = Paths.get("C:\\IdeaProjects\\StreamExample\\src\\file");
    Stream<Path> list = Files.list(path);
    list.forEach(p -> System.out.println(p.getFileName()));

    System.out.println("============================================================");

    Path filePath = Paths.get("C:\\IdeaProjects\\StreamExample\\src\\file\\file1.txt");
    Stream<String> lines = Files.lines(filePath);
    lines.forEach(System.out::println);
}

BufferedReader를 이용한 Stream 생성

@Test
void test7() throws Exception{
    BufferedReader br = new BufferedReader(new FileReader("C:\\IdeaProjects\\StreamExample\\src\\file\\file2.txt"));
    Stream<String> lines = br.lines();
    lines.forEach(System.out::println);
}

Pattern을 이용한 Stream 생성

@Test
void test8() {
    Stream<String> stream = Pattern.compile(",").splitAsStream("aaa,bbb,ccc,ddd,eee");
    stream.forEach(System.out::println);
}

Stream.builder() 로 생성

@Test
void test9() {
    Stream<String> stream = Stream.<String>builder()
            .add("aaa")
            .add("bbb")
            .add("ccc")
            .add("ddd")
            .add("eee").build();
    stream.forEach(System.out::println);
}

Stream.iterate() 로 생성

iterate 메서드를 이용하면 초기값과 람다를 인수로 받아 스트림을 생성한다. 무한 스트림을 생성하기 때문에 limit로 제한을 해줘야 한다.

@Test
void test10(){
    Stream<Integer> stream = Stream.iterate(1, x -> x + 2).limit(3);
    stream.forEach(System.out::println);
}

Stream.generate() 로 생성

generate 메서드는 iterate 메서드와 다르게 인자가 없고 리턴값만 있는 Supplier를 인수로 받는다. 무한 스트림을 생성하기 때문에 limit로 제한을 해줘야 한다.

@Test
void test11(){
    Stream<Double> randomStream = Stream.generate(Math::random).limit(3);
    randomStream.forEach(System.out::println);
}

Stream.concat() 으로 생성

@Test
void test12(){
    List<String> list1 = List.of("111", "222");
    List<String> list2 = List.of("333", "444");
    Stream<String> stream = Stream.concat(list1.stream(), list2.stream());
    stream.forEach(System.out::println);
}

비어있는 Stream 생성

@Test
void test13(){
    Stream<Object> empty = Stream.empty();
    System.out.println(empty.count());
}

참고

자바 스트림 정리: 1. API 소개와 스트림 생성 연산

Github

https://github.com/sisipapa/StreamExample.git