美文网首页
Java8_初识流(Stream)

Java8_初识流(Stream)

作者: 大鹏_xzlp | 来源:发表于2017-10-19 14:07 被阅读0次

    Java8中新增的特性中,对核心类库的改进是很关键的一部分,这部分主要包括了集合类的API和新引入的流(Stream),流使得我们可以站在更高的抽象层次上对集合进行操作,下面我们就来熟悉一下什么是流。

     Stream<String> stream1 = Stream.of("hello", "world", "hello world");
    

    这样就创建了一个流,如果我们要找到流中字符串长度小于6的字符串个数,我们可以这样写

    long count = stream1.filter(item -> item.length() < 6).count();//2
    

    可以看到我们用了两步来求值
    1.filter(item -> item.length() < 6)过滤字符串长度小于6
    2.count() 计算数量
    看起来像是进行了两次循环,其实不然

     stream1.filter(item -> item.length() < 6)
    

    这行代码并未做什么实质性的工作,只是描述了Stream,我们可以测试一下

    stream1.filter(item ->{
                    System.out.println("filter");
                    return item.length() < 6;
                    }
                );
    

    运行程序,发现并没有打印任何东西,我们继续加上count看一下

     stream1.filter(item ->{
                    System.out.println("filter");
                    return item.length() < 6;  
                    }
                ).count();
    

    这时打印出了

    filter
    filter
    filter
    

    之所以是这样,是因为流操作分为两类:
    1.惰性求值:返回一个Stream
    2.及早求值:返回具体的值

    一个流操作有三部分组成:
    1.源
    2.零个或多个中间操作
    3.终止操作
    在执行终止操作前,流中间的多个操作都不会运行,只有当执行了终止操作后,流才会根据所有的条件去综合执行。

    常用的流操作


    1. collect(toList())
      collect(toList())是由Stream里的值生成一个列表,是一个及早求值操作。
    List<String> list = Stream.of("a", "b", "c").collect(Collectors.toList());
    list.forEach(System.out::print);//abc  
    
    1. map
      将一个流中的值转换成一个新的流
      Java8之前如果我们要将一个列表中的字符串转换成大写,要这样写
    List<String> newList = new ArrayList();
    List<String> list = Arrays.asList("a", "b", "c");
    for (String str : list) {
        newList.add(str.toUpperCase());
    }
    newList.forEach(System.out::print);//ABC
    

    使用map我们只需要这样写,map所接收的Lambda表达式必须是一个Function接口的一个实例。

    List<String> list = Arrays.asList("a", "b", "c");
    List<String> newList = list.stream().map(String::toUpperCase).collect(Collectors.toList());
    newList.forEach(System.out::print);//ABC
    

    在Stream中对原生类型的map操作进行了几个扩展,有mapToInt、mapToLong、mapToDouble,所以在进行具体使用的时候最好具体指定具体类型的方法,这样可以避免自动装箱拆箱带来的损耗

    Stream.iterate(1,item-> item+2).limit(6).filter(value -> value>200).mapToInt(value -> value * 2).skip(2).limit(2).min().ifPresent(System.out::print);
    
    1. filter
      这个在最上面也讲过了,filter接收的Lambda表达式必须是一个Predicate接口的一个实例。
    Stream<String> stream1 = Stream.of("hello", "world", "hello world");
    long count = stream1.filter(item -> item.length() < 6).count();
    System.out.println(count);
    
    1. flatMap
      flatMap方法可用Stream替换值,然后将多个Stream连接成一个Stream
    <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
    

    假设有一个包含多个列表的流,现在要得到所有数字的序列

    Stream<List<Integer>> stream = Stream.of(Arrays.asList(1, 2, 3), Arrays.asList(4), Arrays.asList(5, 6, 7));
    List<Integer> list = stream.flatMap(item->item.stream()).collect(Collectors.toList());
    System.out.println(list);//[1, 2, 3, 4, 5, 6, 7]
    
    1. max和min
      求最大最小值是很常用的操作,方法接收一个Comparator对象,Java8提供了一个新的静态方法comparing,该方法接收一个函数,返回一个函数,max方法返回的是一个Optional对象
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
    list.stream().max(Comparator.comparing(item -> item)).ifPresent(System.out::println);//7
    

    6.reduce
    max和min都属于一种通用的编程模式,这种模式可以用以下伪代码体现:

    Object accumulator = initialValue;
    for(Object element : collection){
            accumulator = combine(accumulator,element);
    }
    

    首先赋给accumulator一个初始值:initialValue,然后在循环体中,通过调用combine函数,拿accumulator和集合中的每一个元素做运算,再将运算结果赋给accumulator,最后accumulator的值就是想要的结果。

    上面例子中用到的count、max、min方法,其实都是reduce操作,因为常用所以被纳入标准库中。

    来看几个例子
    求和:

    int count = Arrays.asList(1, 2, 3).stream().reduce(0,(acc,item)->acc+item);
    System.out.println(count);//6
    

    求最大值:

     List<Integer> list2 = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
    list2.stream().reduce((maxitem,item)->{
               System.out.println("maxitem:"+maxitem + "item:"+item);
                if(maxitem < item){
                    return item;
                }else{
                    return maxitem;
                }
            }).ifPresent(System.out::println);//7
    

    log打印:

    maxitem:1item:2
    maxitem:2item:3
    maxitem:3item:4
    maxitem:4item:5
    maxitem:5item:6
    maxitem:6item:7
    

    可以看出reduce执行的逻辑,上面程序是为了看内部实现,其实可以简短的写成

    list2.stream().reduce(BinaryOperator.maxBy(Comparator.comparingInt(Integer::new))).ifPresent(System.out::println);
    

    总结

    本次主要介绍了Stream的基本概念以及用法,作为一个初步了解,关于Stream还有着更加复杂的操作以及一些陷阱,后续我们再逐步分析。

    相关文章

      网友评论

          本文标题:Java8_初识流(Stream)

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