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.不影响源数据。

 
 



 
 
 
 

 

 

 

 

 

 

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM