Java8 Stream小计

作者: Mr_Hospital | 来源:发表于2017-12-27 22:48 被阅读40次

    本文参考java8-stream-tutorial-examples。引用了里面许多例子,所以必须要文章开头便贴出来。

    本文采用QKQ方式。

    Q: 什么是一个stream?

    A: stream,翻译成中文就是“河流,小河,川,溪; ”。查查英文字典:

    1, a small, narrow river (窄的小河)
    2, a continuous flow of liquid, air or gas(一个连续流动的液体,空气或者气体)

    这里,我将stream理解为:

    a series of things that flows (一系列流动的事物)

    两点:

    • 一系列,这个系列也可以只有一个,此时算是一种特殊的stream
    • 流动,即从一个地方到另一个地方。这个系列中的事物有一种时间上的先后顺序

    K: 一系列流动的事物。

    Q: Java8 中的stream是什么样子的?

    A: Java8中的stream主要来自两个地方:

    • List,比如Arrays.asList(1, 2, 3).stream()。通过List的stream()函数将List转变为一个stream。
    • 直接创建,比如Stream.of(1, 2, 3)。此时的返回就直接是一个stream.

    代码:

    Stream<Integer> integers = Arrays.asList(1, 2, 3).
    Stream<Integer> integerStream = Stream.of(1, 2, 3);
    

    注意,此时产生的Stream都是Integer类型,而不是基本类型Int。这是因为Java8规定了Stream的类型必须得是对象类型,而不是原生类型。对于int,,double,,long,Java8提供了几个stream:

            IntStream intStream = IntStream.range(1, 5);
            LongStream longStream = LongStream.range(1L, 5L);
            DoubleStream doubleStream = DoubleStream.of(1.1, 2.2, 3.3);
    

    使用其中的IntStream可以取代一些遍历,比如:

    
    for(int i = 0; i < 4; i++) {
       ...
    }
    
    // stream
    IntStream.range(0, 4).forEach(i -> ...)
    

    K: Stream<T>

    Q: Stream有什么用?

    A: Java8中,凡是遇到a series of data(比如List)的地方就可以考虑是不是可以变成a series of data that flows(就是stream),然后在stream上进行操作。
    stream的操作可以根据操作的返回值分为两种:

    • 中间型,此时操作的返回值依然一个stream
    • 终结型,此时操作的返回值不是一个stream,可能是boolean,Map等

    对stream的操作有许多,这里介绍五个:

    • filter,过滤


      filter.png
    • map,就是说将一个类型的stream转换成另一个类型的stream
    map.png
    • reduce,将一个stream减变为一个值


      reduce.png
    • flatMap,将一个stream变成两一个stream,新stream的元素可能更多


      flatmap.png
    • collect,将一个stream采集变为一个值,可能是一个series of data


      collect.png

    其中Map和FlatMap是中间型,而reduce和collect是终结型。

    K: 处理一系列的数据。有中间型,终结型,map,reduce,flatmap,collect等。
    R: 组合起来完成操作

    Q: Stream中的flow怎么体现?

    A: flow是动态的,所以对于stream没有进行操作的时候,是没有stream的,此时是静态的。只有操作起来了才有stream,而不是静态的a series of data。比如filter操作,一个又一个的元素依次进行filter的操作,此时就是一种flow。代码:

    Stream.of(1, 2, 3).filter(x -> x > 2).forEach(System.out::println)
    

    K: 操作引起flow,动态,静态

    一个大例子

    其中用到了JUnit 4.12和 AssertJ 3.8.0

    package li.koly;
    
    import org.junit.Test;
    
    import java.util.*;
    import java.util.concurrent.ConcurrentHashMap;
    import java.util.function.BiConsumer;
    import java.util.function.BinaryOperator;
    import java.util.function.Function;
    import java.util.function.Supplier;
    import java.util.stream.*;
    
    import static org.assertj.core.api.Assertions.assertThat;
    
    // reference: http://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/
    public class StreamTest {
    
    
        @Test
        public void should_filter() {
            List<Integer> list = prepareList();
            List<Integer> result = list.stream().filter(i -> i > 2).collect(Collectors.toList());
            assertThat(result).containsExactly(4, 3);
        }
    
        private List<Integer> prepareList() {
            List<Integer> list = new ArrayList<>();
            list.add(1);
            list.add(2);
            list.add(4);
            list.add(3);
            return list;
        }
    
        @Test
        public void should_reduce_to_sum() {
            List<Integer> list = prepareList();
            Optional<Integer> sum = list.stream().reduce((i1, i2) -> {
                System.out.println(i1 + ", " + i2);
                return i1 + i2;
            });
            assertThat(sum.get()).isEqualTo(10);
        }
    
        @Test
        public void should_reduce_to_concat() {
            List<String> list = new ArrayList<>();
            list.add("one");
            list.add("two");
            list.add("three");
            Optional<String> concat = list.stream().reduce(new BinaryOperator<String>() {
                @Override
                public String apply(String s1, String s2) {
                    return s1 + ", " + s2;
                }
            });
            assertThat(concat.get()).isEqualTo("one, two, three");
        }
    
        @Test
        public void should_reduce_to_min() {
            List<Integer> list = prepareList();
            Optional<Integer> min = list.stream().reduce(BinaryOperator.minBy(Integer::compareTo));
            assertThat(min.get()).isEqualTo(1);
        }
    
        @Test
        public void should_reduce_to_max() {
            List<Integer> list = prepareList();
            Optional<Integer> max = list.stream().reduce(BinaryOperator.maxBy(Integer::compareTo));
            assertThat(max.get()).isEqualTo(4);
        }
    
        @Test
        public void should_reduce_to_max_manually() {
            List<Integer> list = prepareList();
            Optional<Integer> max = list.stream().reduce((i1, i2) -> i1 > i2 ? i1 : i2);
            assertThat(max.get()).isEqualTo(4);
        }
    
        @Test
        public void should_collect_to_list() {
            List<Integer> list = prepareList();
            Integer sum = list.stream().collect(new Collector<Integer, Integer[], Integer>() {
    
    
                @Override
                public Supplier<Integer[]> supplier() {
                    return () -> new Integer[1];
                }
    
                @Override
                public BiConsumer<Integer[], Integer> accumulator() {
                    return (integers, integer) -> integers[0] = integers[0] + 1;
                }
    
                @Override
                public BinaryOperator<Integer[]> combiner() {
                    return new BinaryOperator<Integer[]>() {
                        @Override
                        public Integer[] apply(Integer[] integers, Integer[] integers2) {
                            integers[0] += integers2[0];
                            return integers;
                        }
                    };
                }
    
                @Override
                public Function<Integer[], Integer> finisher() {
                    return integers -> integers[0];
                }
    
                @Override
                public Set<Characteristics> characteristics() {
                    return Collections.unmodifiableSet(EnumSet.of(Characteristics.IDENTITY_FINISH));
                }
            });
            assertThat(sum).isEqualTo(10);
        }
    
        @Test
        public void should_map() {
            List<Integer> list = prepareList();
            List<String> result = list.stream().map(i -> i.toString()).collect(Collectors.toList());
            assertThat(result).containsExactly("1", "2", "4", "3");
        }
    
    
        @Test
        public void should_distinct() {
            List<Integer> list = prepareList();
            list.add(2);
            List<Integer> distinct = list.stream().distinct().collect(Collectors.toList());
            assertThat(distinct).containsExactly(1, 2, 4, 3);
        }
    
        @Test
        public void should_sorted_return_sorted_stream() {
            List<Integer> list = prepareList();
            List<Integer> result = list.stream().sorted().collect(Collectors.toList());
            assertThat(result).containsExactly(1, 2, 3, 4);
        }
    
        @Test
        public void should_peek_usually_for_logging() {
            List<Integer> list = prepareList();
            List<Integer> peek = list.stream().peek(i -> System.out.println(i)).peek(i -> i.toString()).collect(Collectors.toList());
            assertThat(peek).containsExactly(1, 2, 4, 3);
        }
    
        @Test
        public void should_limit_stream() {
            List<Integer> list = prepareList();
            List<Integer> limit = list.stream().limit(2).collect(Collectors.toList());
            assertThat(limit).containsExactly(1, 2);
        }
    
    
        @Test
        public void should_skip_the_first_n_elements_and_return_left() {
            List<Integer> list = prepareList();
            List<Integer> skip = list.stream().skip(2).peek(System.out::println).collect(Collectors.toList());
            assertThat(skip).containsExactly(4, 3);
        }
    
    
        @Test
        public void should_foreach_which_returns_void() {
            List<Integer> list = prepareList();
            list.stream().forEach(i -> System.out.println(i));
        }
    
    
        @Test
        public void should_foreach_ordered_which_returns_void() {
            List<Integer> list = prepareList();
            list.stream().forEachOrdered(i -> System.out.println(i));
        }
    
    
        @Test
        public void should_max() {
            List<Integer> list = prepareList();
            Optional<Integer> max = list.stream().max(Comparator.naturalOrder());
            assertThat(max.get()).isEqualTo(4);
        }
    
    
        @Test
        public void should_count() {
            List<Integer> list = prepareList();
            long count = list.stream().count();
            assertThat(count).isEqualTo(4);
        }
    
    
        @Test
        public void should_any_match() {
            List<Integer> list = prepareList();
            boolean matched = list.stream().anyMatch(x -> x == 4);
            assertThat(matched).isTrue();
        }
    
    
        @Test
        public void should_all_match() {
            List<Integer> list = prepareList();
            boolean allMatched = list.stream().allMatch(x -> x > 0);
            assertThat(allMatched).isTrue();
        }
    
    
        @Test
        public void should_non_match() {
            List<Integer> list = prepareList();
            boolean nonMatched = list.stream().noneMatch(x -> x < 0);
            assertThat(nonMatched).isTrue();
        }
    
    
        @Test
        public void should_find_first() {
            List<Integer> list = prepareList();
            Optional<Integer> first = list.stream().findFirst();
            assertThat(first.get()).isEqualTo(1);
    
            Optional<Integer> first1 = list.stream().filter(x -> x > 3).findFirst();
            assertThat(first1.get()).isEqualTo(4);
        }
    
    
        @Test
        public void should_find_any() {
            List<Integer> list = prepareList();
            Optional<Integer> any = list.stream().findAny();
            assertThat(any.get()).isEqualTo(1);
        }
    
    
        @Test
        public void should_create_empty_stream() {
            Stream<Object> empty = Stream.empty();
        }
    
    
        @Test
        public void should_of() {
            Stream<Integer> stream = Stream.of(1, 2, 3, 4);
            List<Integer> list = stream.collect(Collectors.toList());
            assertThat(list).containsExactly(1, 2, 3, 4);
        }
    
    
        @Test
        public void should_iterate() {
            List<Integer> iterate = Stream.iterate(1, integer -> integer + 1).limit(5).collect(Collectors.toList());
            assertThat(iterate).containsExactly(1, 2, 3, 4, 5);
        }
    
    
        @Test
        public void should_generate_infinitely() {
            Stream<Integer> infinite = Stream.generate(() -> 1);
            List<Integer> infi = infinite.limit(5).collect(Collectors.toList());
            assertThat(infi).containsExactly(1, 1, 1, 1, 1);
        }
    
    
        @Test
        public void should_concat() {
            Stream<Integer> one = Stream.of(1, 2);
            Stream<Integer> two = Stream.of(3, 4);
            Stream<Integer> result = Stream.concat(one, two);
            assertThat(result).containsExactly(1, 2, 3, 4);
        }
    
    
        @Test
        public void should_parallel() {
            List<Integer> list = prepareList();
            List<String> paralMap = list.stream().parallel().map(Object::toString).collect(Collectors.toList());
            assertThat(paralMap).containsExactly("1", "2", "4", "3");
        }
    
    
        @Test
        public void should_parallel_whoo() {
            Arrays.asList("a1", "a2", "b1", "c2", "c1")
                    .parallelStream()
                    .filter(s -> {
                        System.out.format("filter: %s [%s]\n",
                                s, Thread.currentThread().getName());
                        return true;
                    })
                    .map(s -> {
                        System.out.format("map: %s [%s]\n",
                                s, Thread.currentThread().getName());
                        return s.toUpperCase();
                    })
                    .forEach(s -> System.out.format("forEach: %s [%s]\n",
                            s, Thread.currentThread().getName()));
        }
    
        @Test
        public void should_lazy() {
            Stream.of(1, 2, 3).filter(x -> {
                System.out.println("filter " + x);
                return x > 1;
            }).map(x -> {
                System.out.println("map " + x);
                return "a" + String.valueOf(x);
            });
        }
    
        @Test
        public void should_lazy_until_terminal() {
            Stream.of(1, 2, 3).filter(x -> {
                System.out.println("filter " + x);
                return x > 1;
            }).map(x -> {
                System.out.println("map " + x);
                return "a" + String.valueOf(x);
            }).forEach(System.out::println);
        }
    
        @Test
        public void should_use_stream_build() {
            ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
        }
    
        @Test
        public void should_flat_map() {
            List<Enterprise> enterpriseList = new ArrayList<>();
            IntStream.range(1, 4)
                    .forEach(i -> enterpriseList.add(new Enterprise("enter " + i)));
            enterpriseList
                    .forEach(e -> IntStream.range(1, 4)
                            .forEach(i -> e.users.add(new User("user " + i))));
    
            enterpriseList.stream().flatMap(e -> e.users.stream()).forEach(u -> System.out.println(u.name));
        }
    
        @Test
        public void should_flat_map_fluently() {
            IntStream.range(1, 4)
                    .mapToObj(i -> new Enterprise("enter " + i))
                    .peek(e -> IntStream.range(1, 4).mapToObj(i -> new User("user " + i)).forEach(e.users::add))
                    .flatMap(e -> e.users.stream())
                    .forEach(u -> System.out.println(u.name));
        }
    
        @Test
        public void should_optional_flat_map() {
            Outer outer = new Outer();
            if (outer != null && outer.nested != null && outer.nested.inner != null) {
                System.out.println(outer.nested.inner.name);
            }
    
            // instead
            Optional.of(new Outer())
                    .flatMap(o -> Optional.ofNullable(o.nested))
                    .flatMap(n -> Optional.ofNullable(n.inner))
                    .flatMap(i -> Optional.ofNullable(i.name))
                    .ifPresent(System.out::println);
        }
    
        class Outer {
            Nested nested;
        }
    
        class Nested {
            Inner inner;
        }
    
        class Inner {
            String name;
        }
    
    
        private static class Enterprise {
            String name;
            List<User> users = new ArrayList<>();
    
            public Enterprise(String name) {
                this.name = name;
            }
        }
    
        private static class User {
            String name;
    
            User(String name) {
                this.name = name;
            }
        }
    
    
        private List<Person> persons = Arrays.asList(
                new Person("Max", 18),
                new Person("Peter", 23),
                new Person("Pamela", 23),
                new Person("David", 12)
        );
    
        @Test
        public void should_collect_grouping_by() {
            Map<Integer, List<Person>> personsByAge = persons.stream().collect(Collectors.groupingBy(p -> p.age));
            personsByAge.forEach((age, p) -> System.out.format("age %d : %s\n", age, p));
        }
    
        @Test
        public void should_collect_average_int() {
            Double averageAge = persons.stream().collect(Collectors.averagingInt(p -> p.age));
            System.out.println(averageAge);
        }
    
        @Test
        public void should_collect_summarize() {
            IntSummaryStatistics statistics = persons.stream().collect(Collectors.summarizingInt(p -> p.age));
            System.out.println(statistics);
        }
    
        @Test
        public void should_collect_joining() {
            String result = persons.stream()
                    .map(p -> p.name)
                    .collect(Collectors.joining(" and ", "In China", " are of legal age"));
            System.out.println(result);
        }
    
        @Test
        public void should_collect_to_map() {
            Map<Integer, String> map = persons.stream()
                    .collect(Collectors.toMap(p -> p.age, p -> p.name, (name1, name2) -> name1 + " ; " + name2));
            System.out.println(map);
        }
    
        @Test
        public void should_use_collector_of() {
            Collector<Person, StringJoiner, String> personNameCollector =
                    Collector.of(
                            () -> new StringJoiner(" | "),          // supplier
                            (j, p) -> j.add(p.name.toUpperCase()),  // accumulator
                            (j1, j2) -> j1.merge(j2),               // combiner
                            StringJoiner::toString);                // finisher
            String collect = persons.stream()
                    .collect(personNameCollector);
    
            System.out.println(collect);
        }
    
    
        class Person {
            String name;
            int age;
    
            public Person(String name, int age) {
                this.name = name;
                this.age = age;
            }
    
            @Override
            public String toString() {
                return name;
            }
        }
    
        @Test
        public void should_test(){
            Stream<Integer> integers = Arrays.asList(1, 2, 3).stream();
            Stream<Integer> integerStream = Stream.of(1, 2, 3);
            IntStream intStream = IntStream.range(1, 5);
            LongStream longStream = LongStream.range(1L, 5L);
            DoubleStream doubleStream = DoubleStream.of(1.1, 2.2, 3.3);
    
            Stream.of(1, 2, 3).filter(x -> x > 2).forEach(System.out::println);
    
        }
    
    }
    
    

    参考资料:
    [1] // reference: http://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/

    相关文章

      网友评论

        本文标题:Java8 Stream小计

        本文链接:https://www.haomeiwen.com/subject/iaepgxtx.html