Java8 Stream小计

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

Proudly powered by 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/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,099评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,473评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,229评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,570评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,427评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,335评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,737评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,392评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,693评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,730评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,512评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,349评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,750评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,017评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,290评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,706评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,904评论 2 335

推荐阅读更多精彩内容