프로그래밍언어/Java

Java Functional Programming 스트림 설명 종류 그리고 고차함수

by 앵과장 2022. 8. 13. 10:05
반응형
스트림 (Stream)

Stream 은 Java 8버전부터 추가되었습니다. 아래 제공하는 여러가지 데이터를 처리할수 있는 기능들을 제공합니다.

상당히 편리하지만 제대로 알고써야 편리한 기능입니다.

 

Filter, Sorted, Map, Match, Reduce, groupingBy  

 

원시 타입을 위한 IntStream, LongStream 같은 원시타입을 다루는 스트림과 

레퍼런스 타입(클래스, 일반 컬렉션 객첵)등을 다루는 일반 스트림이 존재합니다.

 

스트림은 아래와같이 일련의 작업등을 특정한 조건에 대입하여 원하는 데이터를 제어하는 기술입니다.

 

 

스트림을 가장 쉽게 설명한건데 우리가 데이터를 받을때

첨부터 원하는 데이터만 받을수도 있지만 위에 그림처럼 

 

데이터(꽃게, 물고기, 해파리) 들 중에 원하는 물고기만 걸러내기위해서 

.filter( 해파리, 꽃께는 걸러줘) 라는 기능을 넣고 물고기를 배에서 잡아서 바로 포장하는것이 필요하기에 

.map 이라는 불변하면서 유일한 식별자 key로 MAP을 만들고 

원하는 형태로 제공하기위한 포장지역활을 하는 .collect 라는 여러가지 자료구조 리턴타입을 사용하게 되는것 같습니다. 

 

스트림은 고차함수(filter, map)과 종단 고차함수(collect, count, xxxMatch)등으로 구성 됩니다.

 

Filter
List.of(
            "aaa0", "bbb0", "ccc0",
            "aaa1", "bbb1", "ccc1",
            "aaa2", "bbb2", "ccc2",
            "aaa3", "bbb3", "ccc3"
)
.stream()
.filter(StringFilter::startWith_A)
.forEach(System.out::println);
Sorted
int desc( String s1, String s2 ){
    return s2.compareTo(s1);
}
 
 
List.of(
            "aaa0", "bbb0", "ccc0",
            "aaa1", "bbb1", "ccc1",
            "aaa2", "bbb2", "ccc2",
            "aaa3", "bbb3", "ccc3"
)
.stream()
.sorted(this::desc)
.forEach(System.out::println);

 

Map
List.of(
            "aaa0", "bbb0", "ccc0",
            "aaa1", "bbb1", "ccc1",
            "aaa2", "bbb2", "ccc2",
            "aaa3", "bbb3", "ccc3"
)
.stream()
.map(String::toUpperCase)
.collect(joining(", ")));

 

Match
List<String> dummyNameList = List.of(
            "aaa0", "bbb0", "ccc0",
            "aaa1", "bbb1", "ccc1",
            "aaa2", "bbb2", "ccc2",
            "aaa3", "bbb3", "ccc3"
);
 
 
System.out.println("anyMatch(t->t.startsWith(\"a\")) 한개라도 맞으면 true :\n\t" + dummyNameList.stream()
      .anyMatch(t->t.startsWith("a"))
);
 
System.out.println("allMatch(t->t.startsWith(\"a\")) 모두 맞으면 true:\n\t" + dummyNameList.stream()
      .allMatch(t->t.startsWith("a"))
);
System.out.println("noneMatch(t->t.startsWith(\"a\")) 모두 맞지 않으면 true : \n\t" + dummyNameList.stream()
      .noneMatch(t->t.startsWith("a"))
);
Reduce
List<String> dummyStringList = List.of("a", "ab", "ccc", "aefff", "ae", "zzzzzzz");
 
Optional<String> reduce = dummyStringList
                .stream()
                .reduce((s0, s1) -> (s0.length() >= s1.length()) ? s0 : s1);
 
 
 
 
List<Integer> dummyIntegerList = List.of(1,2,3,4,5,6, 7, 8, 9, 10);
Integer reduce = dummyIntegerList
    .stream()
    .filter(n ->  0 == (n%2))
    .reduce(0, Integer::sum);
groupingBy
    enum BlogPostType {
        NEWS,
        REVIEW,
        GUIDE
    }
 
    @Getter
    @ToString
    @EqualsAndHashCode(exclude = {"title", "likes"})
    @RequiredArgsConstructor
    static final class BlogPost {
        private final String author;
        private final BlogPostType type;
        private final String title;
        private final int likes;
    }
 
    @Test
    void objToGrouping() {
        var posts = List.of(
                new BlogPost("test_01", BlogPostType.NEWS, "테스트 NEWS 입니다. ", 1),
                new BlogPost("test_01", BlogPostType.REVIEW, "테스트 REVIEW 입니다. ", 2),
                new BlogPost("test_01", BlogPostType.GUIDE, "테스트  GUIDE 입니다. ", 5),
                new BlogPost("test_01", BlogPostType.REVIEW, "테스트 입니다. ", 7),
                new BlogPost("test_01", BlogPostType.GUIDE, "테스트 입니다. ", 9),
                new BlogPost("test_01", BlogPostType.REVIEW, "테스트 입니다. ", 1)
        );
 
        Map<BlogPostType, List<BlogPost>> postsPerType = posts.stream()
                .collect(groupingBy(BlogPost::getType));
        postsPerType.forEach(toDisplay());
    }
 
<K, V> BiConsumer<? super K, ? super V> toDisplay(){
        return (k,v)->System.out.println(k + " : "+ v );
    }