Java 8 中的 Streams API 详解

本文转载于陈争云,占宇剑和司磊的《Java8中的Streams API详解》一文。

  1. 归类
  • Intermediate 操作
    一个流可以后面跟随零个或多个intermediate操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历。

    map (mapToInt, 等) :对集合中的每个元素操作,返回一个值,1对1的
    flatMap :对集合中的每个元素操作,一个元素可以返回多个结果,1对多
    filter:过滤,返回符合条件的
    distinct、
    sorted:排序
    peek、
    limit、
    skip、
    parallel:并行执行
    sequential、
    unordered

  • Terminal 操作
    一个流只能有一个terminal操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以,这必定是流的最后一个操作。Terminal操作的执行,才会真正开始流的遍历,并且会生成一个结果,或者一个side effect。
    forEach:循环
    forEachOrdered、
    toArray、
    reduce:有初始值 a,a和第一个元素操作结果a1,结果a1和第二个元素操作结果a12,依次类推;
    collect:收集元素 collect(Collectors.toList())
    min、
    max、
    count、
    anyMatch、
    allMatch、
    noneMatch、
    findFirst、
    findAny、
    iterator

  • Short-circuiting 操作
     还有一种操作被称为short-circuiting。用以指:对于一个intermediate操作,如果它接受的是一个无限大(infinite/unbounded)的Stream,但返回一个有限的新Stream;对于一个terminal操作,如果它接受的是一个无限大的Stream,但能在有限的时间计算出结果。
    当操作一个无限大的 Stream,而又希望在有限时间内完成操作,则在管道内拥有一个short-circuiting操作是必要非充分条件。

在对一个Stream进行多次转换操作(Intermediate 操作),每次都对Stream的每个元素进行转换,而且是执行多次,这样时间复杂度就是N(转换次数)个for循环里把所有操作都做掉的总和吗?其实不是这样的,转换操作都是lazy的,多个转换操作只会在Terminal操作的时候融合起来,一次循环完成。我们可以这样简单的理解,Stream里有个操作函数的集合,每次转换操作就是把转换函数放入这个集合中,在Terminal 操作的时候循环Stream对应的集合,然后对每个元素执行所有的函数。

@RunWith(JUnit4.class)
public class DemoApplicationTests {
    private List<DataBean> totalStocks = new ArrayList<>();

    @Before
    public void b(){
        DataBean stock1 = new DataBean();
        stock1.setDeptId(2);
        stock1.setType(2);
        stock1.setNum(2);
        totalStocks.add(stock1);

        DataBean stock2 = new DataBean();
        stock2.setDeptId(2);
        stock2.setType(2);
        stock2.setNum(3);
        totalStocks.add(stock2);

        DataBean stock3 = new DataBean();
        stock3.setDeptId(3);
        stock3.setType(3);
        stock3.setNum(5);
        totalStocks.add(stock3);

        DataBean stock4 = new DataBean();
        stock4.setDeptId(3);
        stock4.setType(3);
        stock4.setNum(4);
        totalStocks.add(stock4);

        DataBean stock5 = new DataBean();
        stock5.setDeptId(4);
        stock5.setType(4);
        stock5.setNum(10);
        totalStocks.add(stock5);
    }

    //groupingBy一个参数的:参数就是分组的key; 按key( e.getDeptId()+":"+e.getType() )分组,返回值 Map<String, List<DataBean>>
    @Test
    public void groupingBy1() {
        Optional.ofNullable( totalStocks.stream().collect(Collectors.groupingBy(e->e.getDeptId()+":"+e.getType()) ))
                .ifPresent(System.out::println);
    }
    //groupingBy两个参数的:第一个参数就是分组的key,第二个参数是分组后计算
    @Test
    public void groupingBy2() {
        Optional.ofNullable( totalStocks.stream().collect(Collectors.groupingBy(e->e.getDeptId()+":"+e.getType(),Collectors.averagingInt(DataBean::getNum) ) ))
                .ifPresent(System.out::println);
    }

    //平均值, int long double
    @Test
    public void testAveraging(){
        Optional.ofNullable(totalStocks.stream().collect(Collectors.averagingInt(DataBean::getNum)))
                .ifPresent(System.out::println);
    }

    //collectingAndThen(收集方法,对收集方法的结果进一步处理)
    @Test
    public void testcollectingAndThen(){
        Optional.ofNullable(totalStocks.stream().collect(Collectors.collectingAndThen(Collectors.averagingInt(DataBean::getNum), e->e+"=平均数" )  )  )
                .ifPresent(System.out::println);
    }

    //.count()  == .collect(Collectors.counting()  )
    @Test
    public void testcounting(){
        Optional.ofNullable(totalStocks.stream().count())
                .ifPresent(System.out::println);
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值