Stream API函数式编程

Stream API函数式编程

  • 为什么需要Stream
  • 中间操作
  • 终止操作
  • filter
  • distinct
  • sorted
  • map
  • flatMap
  • limit/skip
为什么需要Stream
Stream它与java.io包下的inputStream和outputStream是完全不同的概念。Java 8 中的 Stream 是对集合对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作,或者大批量数据操作。

在Stream出现之前java代码经常依赖关系型数据库完成如操作:
1、订单数据中会员订单商品均价;
2、最昂贵的售卖商品;
3、本周完成的有效订单(排除待支付,已取消);
4、取五个商品作为场景化推荐商品;

Example:
从商品实例集合中获取交易类型trade_type=1的GoodInst,原来的处理模式:

Iterator iterator = list.iterator();
while(iterator.hasNext()) {
    GoodInst good= iterator.next();
    if (good.getTradeType()==1) {
        System.out.println(good.toString());
    }
}

传统写法是获取list对象迭代器,通过迭代器的hasNext()和next()方法对元素进行处理,在java 8 Stream中写法如下:

list.stream()
    .filter(good -> good.getTradeType()==1)
    .forEach(good-> System.out.println(good.toString()));

使用stream可以减少迭代次数,避免了存储中间结果,并行情况下第一种写法要执行完才能释放资源给第二个线程。
剖析Stream通用语法:
Stream API函数式编程_第1张图片

例子中是获取Stream中元素不为null的个数:
1、红色框中的语句是一个Stream的生命开始的地方,负责创建一个Stream实例;
2、绿色框中的语句是赋予Stream灵魂的地方,过绿框的filter方法以后,重新生成了一个过滤掉原nums列表所有null以后的Stream;
3、蓝色框中的语句是丰收的地方,把Stream的里面包含的内容按照某种算法来汇聚成一个值;

总结以上Stream特点 :

  • 无存储
  • 不改变源对象
  • 延迟操作,需要结果的时候才执行
  • 只消费一次,一旦遍历过就会失效

中间操作

执行中间操作的时候实际上并没有进行任何的过滤操作,而是创建了一个新的流

方法 描述
filter(Predicate p) 接收 Lambda从流中排除某些元素
distinct() 筛选,通过流所生成元素的 hashCode() 和 equals()去重
limit(long maxSize) 截断流,使其元素不超过给定数量
map(Function f) 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
sorted(Comparator comp) 产生一个新流,其中按比较器顺序排序
sorted() 产生一个新流,其中按自然顺序排序
skip(n) 跳过流中前n个元素
flatMap(Function f) 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流

终止操作

执行到终结操作的时候我就要开始遍历数据源并且执行中间操作这个过程了,不会再去等谁了。而且一旦pipeline中的终结操作完成了,那么这个pipeline的使命就完成了

方法 描述
forEach(Consumer c) 内部迭代
max(Comparator c) 返回流中最大值
min(Comparator c) 返回流中最小值
count() 返回流中元素总数

下面详细看下各个API操作的用法:

filter

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

// 过滤出商品价格为11的所有商品;
GoodInst g1 = new GoodInst("会员商品",11,1); GoodInst g2 = new GoodInst("刷新器",12,2); GoodInst g3 = new GoodInst("增值商品",13,3); GoodInst g4 = new GoodInst("小项商品",14,4); GoodInst g5 = new GoodInst("抢单器",11,5);
List<GoodInst> list = Arrays.asList(g1,g2,g3,g4,g5); Stream<GoodInst> result = list.stream().filter(good -> 11 == good.getPrice()); result.forEach(System.out::println);

Output:
GoodInst[name=会员商品,price=11,tradeType=1]
GoodInst[name=抢单器,price=11,tradeType=5]

distinct

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

List<Integer> list = Arrays.asList(1, 1, 2, 2, 3, 3, 3, 3, 4, 5, 6);
Stream<Integer> distinct = list.stream().distinct();//去掉重复元素
distinct.forEach(System.out::print);

output:
123456  

sorted

sorted() ——自然排序(根据流中元素实现的Comparable接口的compareTo()方法来排序的)
sorted(Comparator com) ——定制排序(根据特定的比较器来排序)

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
GoodInst g1 = new GoodInst(1,"会员商品",11,1,sdf.parse("2017-11-02"));
GoodInst g5 = new GoodInst(5,"抢单器",11,5,sdf.parse("2017-11-07"));
GoodInst g2 = new GoodInst(2,"刷新器",12,2,sdf.parse("2017-11-03"));
GoodInst g3 = new GoodInst(3,"增值商品",12,3,sdf.parse("2017-11-05"));
GoodInst g4 = new GoodInst(4,"小项商品",14,4,sdf.parse("2017-11-06"));
GoodInst g6 = new GoodInst(6,"小项商品",15,4,sdf.parse("2017-11-06"));

List list = Arrays.asList(g1,g2,g3,g4,g5,g6);
// order by price,createTime desc;
Stream result = list.stream().sorted(Comparator.comparing(GoodInst::getPrice)
            .thenComparing(Comparator.comparing(GoodInst::getCreateTime)).reversed());
result.forEach(System.out::println);

map

map 生成的是个 1:1 映射,对于Stream中包含的元素使用给定的转换函数进行转换操作,新生成的Stream只包含转换生成的元素

List<GoodInst> list = Arrays.asList(g1,g2,g3,g4,g5,g6);
Stream<Integer> result = list.stream().map(GoodInst::getId);
result.forEach(System.out::println);

 flatMap

flatMap 把 input Stream 中的层级结构扁平化,就是将最底层元素抽出来放到一起,最终 output 的新 Stream 里面已经没有 List了,都是直接的对象

Stream> input = Stream.of(
                Arrays.asList(g1),
                Arrays.asList(g1,g2),
                Arrays.asList(g2,g3),
                Arrays.asList(g4,g5),
                Arrays.asList(g6)
        );
 Stream output = input.flatMap((child) -> child.stream());
 System.out.println(JSON.toJSONString(output.collect(Collectors.toList())));

limit/skip

limit 返回 Stream 的前面 n 个元素;skip 则是扔掉前 n 个元素

List list = Arrays.asList(u,u2,u3,u4,u5,u6,u7);
list.stream().limit(4).skip(2);

limit如果原Stream中包含的元素个数小于N,那就获取其所有的元素
skip如果原Stream中包含的元素个数小于N,那么返回空Stream

原始做法:截取前4个元素通过for循环遍历list调用list.get(index),既要判断list.size()大小,又要考虑到list.get(index)是否数组越界的问题,容易出错。

int size = list.size();
int count = size >= 4? 4:size;
List result = new ArrayList<>();
for(int index=0;index<count;index++){
    User temp = list.get(index);
    result.add(temp);
}

文档内容整理成word

你可能感兴趣的:(stream,JAVA)