Java8_初识流(Stream)

2017-10-19  本文已影响0人  大鹏_xzlp

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还有着更加复杂的操作以及一些陷阱,后续我们再逐步分析。

上一篇下一篇

猜你喜欢

热点阅读