Java8.0 新特性二之Stream

Stream流
  • 概述
    说道Stream便容易想到I/O Stream, 而实际上,谁规定“流” 就一定是“IO流”呢?在Java8中,得益于Lambda所带来的函数式编程,引入一个全新的Stream概念,用于解决已有集合类库既有的弊端

  • 传统集合遍历的弊端
    需求:筛选出姓张且名字长度为3的人名并打印。

      public class Demo01 {
    
      public static void main(String[] args) {
      // 筛选出姓张且名字长度为3的人名并打印.
      List<String> nameList = new ArrayList<>();
      nameList.add("张芷若");
      nameList.add("赵敏");
      nameList.add("鑫磊");
      nameList.add("吴莫愁");
      nameList.add("张天爱");
      nameList.add("张广仁仁");
      //存储的是姓张
      List<String> nameList1 = new ArrayList<>();
      for (String name : nameList) {
          if (name.startsWith("张")) {
              nameList1.add(name);
          }
      }
      System.out.println(nameList1);
      //存储的姓张且长度为3的名字
      List<String> nameList2 = new ArrayList<>();
    
      for (String name : nameList1) {
          if (3 == name.length()) {
              nameList2.add(name);
          }
      }
    
      System.out.println(nameList2);
      }
      }
    

通过以上代码发现,传统的for循环不仅要专注做什么,还要专注怎么做,Java8的Lambda让我们可以更贱专注于做什么(What),而不是怎么做(How)

public class Demo01 {

public static void main(String[] args) {
// 筛选出姓张且名字长度为3的人名并打印.
    List<String> nameList = new ArrayList<>();
    nameList.add("张芷若");
    nameList.add("赵敏");
    nameList.add("老邱");
    nameList.add("吴莫愁");
    nameList.add("张天爱");
    nameList.add("张广仁仁");

   
    nameList.stream()
            .filter(name -> name.startsWith("张"))
            .filter(name -> 3 == name.length() )
            .forEach(name -> System.out.println(name));
 
}
}

直接阅读代码的字面意思即可完美展示无关逻辑方式的语义:获取流,过滤姓张、过滤长度为3、逐一打印。代码中并没有体现使用线性循环或是其他任何算法进行遍历,我们真正要做的事情是内容被更好地体现在代码中

流式思想
  • 概述
    整体来看,流式思想类似工厂车间的“生产流水线”。Stream(流)是一个来自数据源的元素队列是特定类型 的对象,形成一个队列。Java中Stream并不会存储元素,而是按需计算。数据源流的来源。可以是集合,数组等。备注:“Stream流”其实是一个集合元素的函数模型,它并不是集合,也不是数据机构,其本身并不存储任何元素(或其地址值)。

  • 流的获取
    java.util.strean.Stream 是Java8 新加入的常用的流接口。(这并不是一个函数式接口。)
    获取一个流非常简单,有以下两种常用的方式:

    • 所有的Collection集合都可以通过stream默认方法获取流
    • stream接口的静态方法of可以获取数组对应的流
  • 获取Collection对应的流

  • 获取Map对应的流
    将map拆分成健集合和值结合,在分别获取对应的流

  • 获取数组对应的流

Stream常用方法
  • 概述
    流模型的操作很丰富,这里介绍一些常用的API。这些方法可以被分成两种:

    • 延迟方法:返回值类型仍是Stream接口自身类型的方法,因此支持链式调用。(除了终结方法外,其余方法均为延迟方法。)
    • 终结方法:返回值类型不再是Stream接口自身类型的方法,因此不再支持类似StringBuilder那样的链式调用。比如:终结方法包括count和forEach方法。
  • 逐一处理:forEach

      public class Demo03 {
    
      public static void main(String[] args) {
      		// 语法 
      		// void forEach(Consumer<? super T> action);
      		
      		// 基本使用
      		List<String> nameList = new ArrayList<>();
      		nameList.add("张芷若");
      		nameList.add("赵敏");
      		nameList.add("鑫磊");
      		nameList.add("吴莫愁");
      		nameList.add("张天爱");
      		nameList.add("张广仁仁");
      		// Performs an action for each element of this stream.  终结方法
      		// 遍历流中的元素
      		nameList.stream().forEach(name -> System.out.println(name));
      		//判断流中的元素是否满足条件
      		nameList.stream().filter(name->name.startsWith("张")).forEach(name-> System.out.println(name));
      }
      }
    
  • 过滤filter

      //语法 
      // Stream<T> filter(Predicate<? super T> predicate);
      // 基本使用
      List<String> nameList = new ArrayList<>();
      nameList.add("张芷若");
      nameList.add("赵敏");
      nameList.add("鑫磊");
      nameList.add("吴莫愁");
      nameList.add("张天爱");
      nameList.add("张广仁仁");
      long count = nameList.stream()
              .filter(name -> name.startsWith("张"));
      System.out.println(count);
    
  • 统计个数:count

      // 语法
      // long count();
      
      // 基本使用
      List<String> nameList = new ArrayList<>();
      nameList.add("张芷若");
      nameList.add("赵敏");
      nameList.add("鑫磊");
      nameList.add("吴莫愁");
      nameList.add("张天爱");
      nameList.add("张广仁仁");
      long count = nameList.stream()
              .filter(name -> name.startsWith("张"))
              .count();
      System.out.println(count);
    
  • 取前几个:limit
    limit方法可以对流进行截取,只取用前n个。参数是一个long型,如果集合当亲长度大于参数则进行截取;否则不进行操作

      // 语法
      // Stream<T> limit(long maxSize);
    
      // 基本使用
      List<String> nameList = new ArrayList<>();
      nameList.add("张芷若");
      nameList.add("赵敏");
      nameList.add("鑫磊");
      nameList.add("吴莫愁");
      nameList.add("张天爱");
      nameList.add("张广仁仁");
      // 前三个
      // nameList.stream().limit(3).forEach(name-> System.out.println(name));
      // 后三个
      nameList.stream().skip(3).forEach(name-> System.out.println(name));
    
跳过几个:skip

如果希望跳过前几个元素,可以使用skip.方法获取一个截取之后的新流。如果流的当前长度大于n,则跳过前n个;否则将会得到一个长度为0的空流

	// 语法
	// stream<T> skip(long n);
	// 基本使用
	List<String> nameList = new ArrayList<>();
    nameList.add("张芷若");
    nameList.add("赵敏");
    nameList.add("鑫磊");
    nameList.add("吴莫愁");
    nameList.add("张天爱");
    nameList.add("张广仁仁");
	long count = nameList.stream().skip(2).count();
  • 组合:concat
    如果有两个流,希望合并成为一个流,那么可以使用Stream接口的静态方法concat

      Stream<String> s1 = Stream.of("鑫磊"); 
      Stream<String> s2 = Stream.of("小冰"); 
      Stream<String> s3 = Stream.concat(s1, s2); 
      s3.forEach((name)‐>System.out.println(name));
    
Stream的综合案例
  • 需求
    • 第一个队伍只要名字为三个字的成员名字;

    • 第一个队伍筛选之后只要前三个;

    • 第二队只要姓张的成员姓名;

    • 第二个队伍筛选之后不要前2个人;

    • 将两个队伍合并为一个队伍;

    • 打印整个队伍的Person对象信息

        List<String> nameList = new ArrayList<>();
        nameList.add("张芷若");
        nameList.add("赵敏");
        nameList.add("鑫磊");
        nameList.add("吴莫愁");
        nameList.add("张天爱");
        nameList.add("张广仁仁");
        nameList.add("田宝路");
        nameList.add("万里");
        nameList.add("逍遥");
        nameList.add("想静静");
        nameList.add("张无忌");
        nameList.add("张三丰");
      
        // a. 第一个队伍只要名字为3个字的成员姓名;
        // b. 第一个队伍筛选之后只要前3个人;
        Stream<String> stream1 = nameList.stream().filter(name -> name.length() == 3).limit(3);
      
        // c. 第二个队伍只要姓张的成员姓名;
        // d. 第二个队伍筛选之后不要前2个人;
        Stream<String> stream2 = nameList.stream().filter(name -> name.startsWith("张")).skip(2);
      
        // e. 将两个队伍合并为一个队伍;
        // f. 打印整个队伍的Person对象信息
        Stream.concat(
            nameList.stream().filter(name -> name.length() == 3).limit(3),
            nameList.stream().filter(name -> name.startsWith("张")).skip(2))
        	.forEach(name -> System.out.println(name));
      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值