JDK8新特性:Stream语法详解

大家可以把Stream当成一个高级版本的Iterator。原始版本的Iterator,用户只能一个一个的遍历元素并对其执行某些操作;高级版本的Stream,用户只要给出需要对其包含的元素执行什么操作,比如“过滤掉长度大于10的字符串”、“获取每个字符串的首字母”等,具体这些操作如何应用到每个元素上,就给Stream就好了!(这个秘籍,一般人我不告诉他:)

先看如下几个例子:

List<Integer> nums = Lists.newArrayList(1,null,3,4,null,6);
nums.stream().filter(num -> num != null).count();

list.stream()
    .filter(student -> student.getSex().equals("G"))
    .forEach(student -> System.out.println(student.toString()));

List<String> lastStoneList =
                     stoneLine.stream()
                     .filter(s -> s.getWeight() < 500)//挑选出质量小于500g的鹅卵石
                     .sorted(comparing(Stone::getWeight))//按照质量进行排序
                     .map(Stone::getName)//提取满足要求的鹅卵石的名字
                    .collect(toList());//将名字保存到List中
---------------------

  1. 创建Stream;
  2. 转换Stream,每次转换原有Stream对象不改变,返回一个新的Stream对象(**可以有多次转换**);
  3. 对Stream进行聚合(Reduce)操作,获取想要的结果;

2.1 使用Stream静态方法来创建Stream的三种方法:

1. of方法:有两个overload方法,一个接受变长参数,一个接口单一值

Stream<Integer> integerStream = Stream.of(1, 2, 3, 5);
Stream<String> stringStream = Stream.of("taobao");

2. generator方法:生成一个无限长度的Stream,其元素的生成是通过给定的Supplier(这个接口可以看成一个对象的工厂,每次调用返回一个给定类型的对象)

Stream.generate(() -> Math.random());
Stream.generate(Math::random);

3. iterate方法:也是生成无限长度的Stream,和generator不同的是,其元素的生成是重复对给定的种子值(seed)调用用户指定函数来生成的。其中包含的元素可以认为是:seed,f(seed),f(f(seed))无限循环。

Stream.iterate(1, item -> item + 1).limit(10).forEach(System.out::println);

3. 转换Stream:

转换Stream其实就是把一个Stream通过某些行为转换成一个新的Stream。Stream接口中定义了几个常用的转换方法,下面我们挑选几个常用的转换方法来解释。

1. distinct: 对于Stream中包含的元素进行去重操作(去重逻辑依赖元素的equals方法),新生成的Stream中没有重复的元素;

2. filter: 对于Stream中包含的元素使用给定的过滤函数进行过滤操作,新生成的Stream只包含符合条件的元素;

3. map: 对于Stream中包含的元素使用给定的转换函数进行转换操作,新生成的Stream只包含转换生成的元素。这个方法有三个对于原始类型的变种方法,分别是:mapToInt,mapToLong和mapToDouble。

4. flatMap:和map类似,不同的是其每个元素转换得到的是Stream对象,会把子Stream中的元素压缩到父集合中;

5. peek: 生成一个包含原Stream的所有元素的新Stream,同时会提供一个消费函数(Consumer实例),新Stream每个元素被消费的时候都会执行给定的消费函数;

6. limit: 对一个Stream进行截断操作,获取其前N个元素,如果原Stream中包含的元素个数小于N,那就获取其所有的元素;

7. skip: 返回一个丢弃原Stream的前N个元素后剩下元素组成的新Stream,如果原Stream中包含的元素个数小于N,那么返回空Stream;

Stream的类型和创建方式2:

// 从数组创建
        int [] source = {1,2,3,4,5,6};
        IntStream s = Arrays.stream(source);
// 从集合创建
        List list = Arrays.asList(1,2,3,4,5);
        Stream s2 = list.stream();
// 创建1到10的流
        IntStream s3 = IntStream.range(1,10);
//  直接创建
        Stream s4 = Stream.of("wo", "ai", "?")
// 支持串行并行操作的序列,元素只有double,int,Long类型的流 DoubleStream,IntStream,LongStream。

案例:

// 将元素中的所有偶数累加求和
int[] nums = {2, 3, 4, 5, 6};
System.out.println(
        Arrays.stream(nums)
                .map(i -> i % 2 == 0 ? i : 0)
                .reduce(0, Integer::sum)
);

// flatMap处理嵌套的list
        List<List<Integer>> ll =
                Arrays.asList(
                        Arrays.asList(1, 2, 3),
                        Arrays.asList(11, 22, 33),
                        Arrays.asList(0xF1, 0xF2, 0xF3)
                );

        ll.stream()
                .flatMap(list -> list.stream())
                .map(i -> 2 * i)
                .forEach(i -> System.out.println(i));

案例三:假设有N条营业数据,前5条是无关的测试数据,中间10条是要参加考核的,参与考核的需要知道其中超过50w(包括50)的数据的交易额平均值,其他不参与考核的忽略
  Stream<Integer> trans = Stream.of(11, 9, 2, 13, 1, 2, 99, 54, 23, 66, 70, 23, 46, 50, 100, 10, 24, 18, 19, 2);

        IntSummaryStatistics all = trans
// 前5条跳过,2, 99, 54, 23, 66, 70, 23, 46, 50, 100, 10, 24, 18, 19, 2
                .skip(5)
// 取10条考核交易 2, 99, 54, 23, 66, 70, 23, 46, 50, 100
                .limit(10)
// 将50以下的交易剔除 99, 54, 66, 70, 50, 100
                .filter(i -> i >= 50)
// 转换成数字。如果是IntStream 则不需要转换
                .mapToInt(i->i)
// 将流的统计结果放入包装对象中
                .summaryStatistics();
// 交易总量 439w,平均值为439/6
        System.out.println(all.getAverage());

Stream流的特性:

1.不能重复使用。

  Stream<Integer> trans = Stream.of(11, 9, 2);
        trans.forEach(i -> System.out.println(i));
        trans.reduce(0, Integer::sum);

当我第二次使用trans时,报错了。


 

2.验证流延迟操作:流只要在终止操作(及早求值)时,才会对数据统一做操作,在没有遇到求值操作的时候,惰性操作代码不会被执行。

    Stream<Integer> trans = Stream.of(11, 70, 23, 46, 50, 100, 10, 24, 18, 19, 2);
        trans.map(i->{
            System.out.println(i);
            return i;
        });
 


3.不影响源数据。

 
 



 
 
 
 

 

 

 

 

 

 

 

posted @ 2019-06-18 15:37  威兰达  阅读(1752)  评论(0编辑  收藏  举报