[JAVA] 스트림 - reduce, collectors클래스, 그룹화

DANI·2023년 12월 20일
0

JAVA를 공부해보자

목록 보기
29/29
post-thumbnail

📝 reduce()


  • 스트림의 요소를 줄여나가면서 연산을 수행하고 최종결과를 반환한다.
  • 매개변수의 타입은 BinaryOperator이다.
  • 처음 두 요소를 가지고 연산한 결과를 가지고 그 다음 요소를 연산한다.

💾 API - 1

Optional<T> reduce(BinaryOperator<T> accumulator)

🔴 예시

public class StreamMain7 {
    public static void main(String[] args) {
        /**
         * 1에서 10까지의 합
         */
        int[] nums = {4, 5, 10, 55, 71, 2, 51};

        // 최대값 구하기
        OptionalInt max = Arrays.stream(nums).reduce((a, b) -> a>b?a:b);
        System.out.println(max.getAsInt());

        // 최소값 구하기
        OptionalInt min = Arrays.stream(nums).reduce((a,b)-> a<b?a:b);
        System.out.println(min.getAsInt());
    }
}

🔵 실행결과

71
2

💾 API - 2

T reduce(T identity, BinaryOperator<T> accumulator)

🔴 예시

public class StreamMain5 {
    public static void main(String[] args) {
        /**
         * 1에서 10까지의 합
         */
        int[] nums = {1, 3, 5, 7, 9, 11, 13, 15, 17, 19};

        /**
         * 0이 처음에 acc에 들어감
         * el은 nums의 배열을 하나씩 불러옴
         * acc에 nums의 합을 불러온다.
         */
        int total = Arrays.stream(nums).reduce(0, (acc, el)-> {
            System.out.printf("acc=%d, el=%d\n", acc, el);
            acc += el;
            return acc;
        });
    }
}

🔵 실행결과

acc=0, el=1
acc=1, el=3
acc=4, el=5
acc=9, el=7
acc=16, el=9
acc=25, el=11
acc=36, el=13
acc=49, el=15
acc=64, el=17
acc=81, el=19


🔍 BinaryOperator란?


같은 타입의 파라미터 2개를 받아 결과값을 리턴하는 functional interface다. 주로 람다와 메서드 참조를 위해 사용된다.



❓ 차이점


리턴타입이 다르고, 첫번째의 경우 배열의 첫 요소가 시작값이 된다.





📝 Collectors 클래스



💾 API - toList()

static <T> Collector<T,?,List<T>>

🔴 예시

public class StreamMain8 {
    public static void main(String[] args) {
        // 배열을 리스트로
        List<String> names = Arrays.asList("이름1", "이름2", "이름3", "이름4", "이름2");
        System.out.println(names);

        // 셋으로 변환하기 : 중복이 제거됨
        Set<String> names2 = names.stream().collect(Collectors.toSet());
        System.out.println(names2);

        // 리스트를 ArrayList로 변경하기
        ArrayList<String> names3 = names.stream()
                .collect(Collectors.toCollection(ArrayList::new));
        System.out.println(names3);
    }
}

🔵 실행결과

[이름1, 이름2, 이름3, 이름4, 이름2]
[이름3, 이름2, 이름1, 이름4]
[이름1, 이름2, 이름3, 이름4, 이름2]

💾 API - toMap()

static <T,K,U> Collector<T,?,Map<K,U>>
static <T,K,U> Collector<T,?,Map<K,U>>
static <T,K,U,M extends Map<K,U>>
Collector<T,?,M>

🔴 예시 - book클래스

public class Book implements Comparable<Book> {
    private String title;
    private String publisher;
    private String author;
    public Book(){}
    
    public String getTitle() {
        return title;
    }

    public String getAuthor() {
        return author;
    }

    public Book(String title, String publisher, String author) {
        this.title = title;
        this.publisher = publisher;
        this.author = author;
    }

    @Override
    public int hashCode() {
        return Objects.hash(title, author, publisher);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Book book = (Book) o;
        return Objects.equals(title, book.title) && Objects.equals(author, book.author) && Objects.equals(publisher, book.publisher);
    }
    
    @Override
    public String toString() {
        return "Book{" +
                "title='" + title + '\'' +
                ", publisher='" + publisher + '\'' +
                ", author='" + author + '\'' +
                '}';
    }
    @Override
    public int compareTo(Book o) {
        return o.title.compareTo(this.title);
    }

}

🔴 예시 - main클래스

public class StreamMain9 {
    public static void main(String[] args) {
        List<Book> books = IntStream.rangeClosed(1, 10)
                .mapToObj(i->new Book("책" + i, "저자" +i, "출판사"+i))
                .toList();
        Map<String, String> data = books.stream().collect(toMap(Book::getAuthor, Book::getTitle));
        data.entrySet().stream().forEach(e-> System.out.printf("key=%s, value=%s\n", e.getKey(), e.getValue()));
    }
}

🔵 실행결과

key=출판사8, value=8
key=출판사9, value=9
key=출판사6, value=6
key=출판사7, value=7
key=출판사4, value=4
key=출판사10, value=10
key=출판사5, value=5
key=출판사2, value=2
key=출판사3, value=3
key=출판사1, value=1

💾 API - joining()

static Collector<CharSequence,?,String> joining()
static Collector<CharSequence,?,String> joining(CharSequence delimiter
static Collector<CharSequence,?,String> joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix)

🔴 예시

public class StreamMain10 {
    public static void main(String[] args) {
        List<String> fruits = Arrays.asList("Apple", "Orange", "Mango", "Melon");
        String collect = fruits.stream().collect(Collectors.joining(","));
        System.out.println(collect);
    }
}

🔵 실행결과

Apple,Orange,Mango,Melon

💾 API - groupingBy()

static <T,K> Collector<T,?,Map<K,List<T>>> groupingBy(Function<? super T,? extends K> classifier)
static <T,K,D,A,M extends Map<K,D>>
Collector<T,?,M> groupingBy(Function<? super T,? extends K> classifier, Supplier<M> mapFactory, Collector<? super T,A,D> downstream)
static <T,K,A,D> Collector<T,?,Map<K,D>> groupingBy(Function<? super T,? extends K> classifier, Collector<? super T,A,D> downstream)

🔴 예시

public class StreamMain11 {
    public static void main(String[] args) {
        // 저자가 0, 1, 2만 나오도록한 후 그룹화를 해보자!
        List<Book> books = IntStream.rangeClosed(1, 10)
                .mapToObj(i->new Book("책" + i, "저자" +i, "출판사"+(i%3)))
                .toList();

        // books.forEach(System.out::println);
        Map<String, List<Book>> collect = books.stream().collect(Collectors.groupingBy(Book::getAuthor));
        // 그룹으로 나눠서 가져오고 싶을 때 사용
        List<Book> books1 = collect.get("출판사1");
        books1.forEach(System.out::println);
    }
}

🔵 실행결과

Book{title='책1', publisher='저자1', author='출판사1'}
Book{title='책4', publisher='저자4', author='출판사1'}
Book{title='책7', publisher='저자7', author='출판사1'}
Book{title='책10', publisher='저자10', author='출판사1'}





0개의 댓글