前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java1.8新特性 -- Srream流

Java1.8新特性 -- Srream流

作者头像
Java深度编程
发布2020-06-10 15:56:21
1.1K0
发布2020-06-10 15:56:21
举报
文章被收录于专栏:Java深度编程
Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据,让程序员写出高效率、干净、简洁的代码。这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,分组等。

元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。其形式好比下面的图:

代码语言:javascript
复制
+--------------------+       +------+   +------+   +---+   +-------+
| stream of elements +-----> |filter+-> |sorted+-> |map+-> |collect|
+--------------------+       +------+   +------+   +---+   +-------+

以上的流程转换为 Java 代码为:

代码语言:javascript
复制
List<Integer> newList = list.stream()
             .filter(b -> b.getColor() == RED)
             .sorted((x,y) -> x.getWeight() - y.getWeight())
             .mapToInt(Widget::getWeight)
             .sum();
此方式每次操作都返回一个新的流,可以再转为集合,而不改变原始集合的值。
Strean流的创建:
代码语言:javascript
复制
// 1,校验通过Collection 系列集合提供的stream()或者paralleStream()
List<String> list = new ArrayList<>();
Strean<String> stream1 = list.stream();

// 2.通过Arrays的静态方法stream()获取数组流
String[] str = new String[10];
Stream<String> stream2 = Arrays.stream(str);

// 3.通过Stream类中的静态方法of
Stream<String> stream3 = Stream.of("aa","bb","cc");
//of方法还可以装多个集合
Stream<List<Integer>> stream = Stream.of(Arrays.asList(1, 2, 3), Arrays.asList(4, 5));

// 4.创建无限流
// 迭代
Stream<Integer> stream4 = Stream.iterate(0,(x) -> x+2);
方法介绍:
1.forEach():循环迭代流中的每个数据
代码语言:javascript
复制
    //java 8 前
    System.out.println("java 8 前");
    for(User user: list){
      System.out.println(user);
    }
    // java 8 lambda
    System.out.println("java 8 lambda");
    list.forEach(user -> System.out.println(user));
 
    // java 8 stream lambda
    System.out.println("java 8 stream lambda");
    list.stream().forEach(user -> System.out.println(user));

2.collect(): 从流转成集合

collect方法十分强大,可以将流转成各种集合,甚至还能对进行分组等操作

代码语言:javascript
复制
    List<User> list = Arrays.asList(
      new User("张三", 11),
      new User("王五", 20),
      new User("王五", 91)
    );
   
    //将流转换为list集合
    List<User> newList = list.stream().collect(Collectors.toList());
    System.out.println(newList.toString());

    //将流转换为map集合(以age为key,以name为value值)
    Map<Integer, String> map = list.stream().collect(Collectors.toMap(User::getAge, User::getName));
  //[User{age=11, name='张三'}, User{age=20, name='王五'}, User{age=91, name='王五'}]
    System.out.println(map.toString());//{20=王五, 91=王五, 11=张三}

  //以name相同进行分组
    Map<String, List<User>> groupMap = list.stream()
      .collect(Collectors.groupingBy(User::getName));
    System.out.println(groupMap);
  //{张三=[User{age=11, name='张三'}], 王五=[User{age=20, name='王五'}, User{age=91, name='王五'}]}
这里需要注意的问题是,上面每次调用方法都用list.stream(),如果你想把它提取出来,想下面这样运行就会报错,因为stream流每次使用完以后就自动关闭了。
代码语言:javascript
复制
 //获取stewam流
 Stream<User> stream = list.stream();
 //将流转换为list集合
 List<User> newList = stream.collect(Collectors.toList());
  
 //继续往下面走就会报错,因为此时stream流已经关闭了!!!
 Map<Integer, String> map = stream.collect(Collectors.toMap(User::getAge, User::getName));

错误信息如下:

代码语言:javascript
复制
Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:229)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
at com.wenxue.jdk8.StreamTest.main(StreamTest.java:147)

3.filter(): 过滤,可以对原集合进行过滤,从而输出满足条件的新集合。

代码语言:javascript
复制
  List<Integer> numList = Arrays.asList(1,2,3,4,5);
  List<Integer> collect3 = numList.stream().filter(n -> n>3).collect(Collectors.toList());
  System.out.println(collect3); //[4, 5]

如上所示,filter(n -> n>3)的第一个n是遍历的集合值,第二个表达式n>3表示要输出集合中大于3的数,于是就成功的过滤了原集合,踢掉了小于表达式的值,得到了新的集合[4,5]。

4.map(): 增强集合,可以对集合中的值进行操作,得到新的值,从而得到新的集合。

代码语言:javascript
复制
   List<String> list = Arrays.asList("a", "b", "c", "d");
  List<String> newList = list.stream()
        .map(String::toUpperCase)
        .collect(Collectors.toList());
  System.out.println(newList); //[A, B, C, D]

如上所示,调用map方法,将原list的值都按表示式增强,进而转成大写,于是得到了增强后的集合。

map()与filter()的区别:

map()可以对集合原始进行操作,自定义返回新的结果集;而fliter是过滤(取满足条件的值),不能修改集合元素的值

5.sorted():排序

代码语言:javascript
复制
 public void testSort() {
   
   List<Integer> nums = Arrays.asList(3, 1, 2, 5);

    // java 1.8 前
    System.out.println("java 8 前");
    Collections.sort(list, new Comparator<User>() {
      @Override
      public int compare(User o1, User o2) {
        return o1.getAge().compareTo(o2.getAge());
      }
    });
   
    // java 1.8 stream 方法引用
   nums.stream().sorted().forEach(a -> System.out.println(a));//1 2 3 5
  }

从上面我们可以看出,在jdk1.8以前要实现一个排序十分的麻烦,而使用jdk1.8却可以很简单的就做到了。

如果你还想指定一个排序规则,1.8也能满足你,sorted()方法还可以提供一个参数,来用于指定比较规则:

代码语言:javascript
复制
//使用User对象的年龄排序
list.stream().sorted(Comparator.comparing(User::getAge))
       .forEach(user -> System.out.println(user));

6.limit():截断,将集合截断,取截断前的值

代码语言:javascript
复制
 @Test
  public void testLimit(List<User> list) {
    // 从第三个开始截断,只输出前三个
    // java 8 前
    System.out.println("java 8 前");
    for (int i = 0; i < 3; i++) {
      System.out.println(list.get(i));
    }
    // java 8 stream
    System.out.println("java 8 stream");
    list.stream().limit(3).forEach(user -> System.out.println(user));
  }
7.skip():截断,将集合截断,取截断后的值(与limi相反)
代码语言:javascript
复制
 @Test
  public void testSkip() {
    // 跳过前三个元素,从第四个开始输出
    // java 8 前
    System.out.println("java 8 前");
    for (int i = 3; i < list.size(); i++) {
      System.out.println(list.get(i));
    }
    // java 8 stream
    System.out.println("java 8 stream");
    list.stream().skip(3).forEach(user -> System.out.println(user));
  }
8.distinct():去重,注意:必须重写对应泛型的hashCode()和equals()方法
代码语言:javascript
复制
   /**
   * 使用jdk1.8的distinct() 去重,注意:必须重写对应泛型的hashCode()和equals()方法
   */
  @Test
  public void testDistinct() {
    // 注意使用Arrays.asList() 返回的是Arrays的内部类ArrayList,操作remove,add会报错
    List<User> users = new ArrayList(list);
    // 为list去除重复数据
    // java 8 前
    System.out.println("java 8 前");
    for (int i = 0; i < users.size() - 1; i++) {
      for (int j = users.size() - 1; j > i; j--) {
        if (users.get(j).getAge() == users.get(i).getAge() && users.get(j).getName()
            .equals(users.get(i).getName())) {
          users.remove(i);
        }
      }
    }
    for (User user : users) {
      System.out.println(user);
    }
    // java 8 stream
    System.out.println("java 8 stream");
    users.stream().distinct().forEach(user -> System.out.println(user));
  }
实战例子: 按照年龄大于18去重,从小到大排序,并且只取前二个
代码语言:javascript
复制
  list.stream().filter(user1 -> user1.getAge() > 18).distinct().sorted(
                Comparator.comparing(User::getAge)).limit(2)
            .forEach(user1 -> System.out.println(user));

9.mapToInt():计算,使用该方法可进行max,min,sum,avg,count等计算

代码语言:javascript
复制
  /**
   * 测试计算,mapToInt()方法是先返回一个可计算的对象,进而才能调用计算方法
   */
  @Test
  public void testNum() {
    IntSummaryStatistics num = list.stream().mapToInt(u -> u.getAge())
        .summaryStatistics();
    System.out.println("总共人数:" + num.getCount());
    System.out.println("平均年龄:" + num.getAverage());
    System.out.println("最大年龄:" + num.getMax());
    System.out.println("最小年龄:" + num.getMin());
    System.out.println("年龄之和:" + num.getSum());
  }
10.findFirst() :使用该方法获取第一个元素
代码语言:javascript
复制
    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    Intger num = list.stream().findFirst().get();
    System.out.println(num);//1
11.flatMap():合并流,将原来的stream中的所有元素都展开组成一个新的stream。

上面我们讲到了使用of()方法可以创建集合,并且可以包裹多个集合,那么又怎样将多个再合并呢?使用flatMap()方法就能做到。

代码语言:javascript
复制
  @Test
  public void testFlatMap() {
    //创建一个 装有两个泛型为integer的集合
    Stream<List<Integer>> stream = Stream.of(Arrays.asList(1, 2, 3), Arrays.asList(4, 5));
    // 将两个合为一个
    Stream<Integer> newStream = stream.flatMap(
        (Function<List<Integer>, Stream<Integer>>) integers -> integers.stream());
    // 转为新的集合
    List<Integer> collect = newStream.collect(toList());
    System.out.println("新stream大小:"+collect.size());//5
    System.out.println("-----合并后-----");
    collect.forEach(o -> System.out.println(o));//1,2,3,4,5
  }
12.reduce() :智能运算

reduce 操作可以实现从一组元素中生成一个值

sum()max()min()count()等都是reduce操作,因为常用所以设为单独函数

例子1:找到年龄最大的,并求所有人的年龄之和
代码语言:javascript
复制
  @Test
  public void reduce() {
    List<User> list = Arrays.asList(
        // name,age
        new User("张三", 11),
        new User("王五", 20),
        new User("王五", 91)
    );
 
    Optional<User> reduce = list.stream().reduce((s1, s2) -> s1.getAge() > s2.getAge() ? s1 : s2);
    User user = reduce.get();
    System.out.println(user); //User{age=91, name='王五'}
    
    //当然也可以使用更简单的方法max()
    Optional<User> max = list.stream().max(Comparator.comparing(User::getAge));
        User user2 = max.get();
        System.out.println(user2);// //User{age=91, name='王五'}
    
    // 求年龄之和
    Integer reduce3 = list.stream().reduce(0, // 该参数为初始值
                (integer, user3) -> integer + user3.getAge(), // 该参数为累加器
                (integer, integer2) -> integer + integer2);// 多个部分累加
    System.out.println(reduce); //122
  }

这里我要说明的是reduce类似于智能运算,它是一种设计思想,其中的max,count等之类的方法已经实现了这种模式。

13.使用collect()做字符串join
代码语言:javascript
复制
  @Test
  public void reduce() {
    // 使用Collectors.joining()拼接字符串
    Stream<String> stream = Stream.of("张三","李四","王五","赵六");
//    String s = stream.collect(Collectors.joining()); // 张三李四王五赵六
//    String s = stream.collect(Collectors.joining("-")); // 张三-李四-王五-赵六
    String s = stream.collect(Collectors.joining("-", "(", ")")); // (张三-李四-王五-赵六)
    System.out.println(s);
  }

以上就是java1.8的Stream流的所有操作方法,看以看出1.8的版本还是蛮强大的,同学们赶紧学习下吧! -- 龚文学

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-12-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java深度编程 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据,让程序员写出高效率、干净、简洁的代码。这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,分组等。
  • 此方式每次操作都返回一个新的流,可以再转为集合,而不改变原始集合的值。
  • Strean流的创建:
  • 方法介绍:
  • 1.forEach():循环迭代流中的每个数据
    • 这里需要注意的问题是,上面每次调用方法都用list.stream(),如果你想把它提取出来,想下面这样运行就会报错,因为stream流每次使用完以后就自动关闭了。
      • map()与filter()的区别:
        • 7.skip():截断,将集合截断,取截断后的值(与limi相反)
          • 8.distinct():去重,注意:必须重写对应泛型的hashCode()和equals()方法
            • 实战例子: 按照年龄大于18去重,从小到大排序,并且只取前二个
              • 10.findFirst() :使用该方法获取第一个元素
                • 11.flatMap():合并流,将原来的stream中的所有元素都展开组成一个新的stream。
                  • 12.reduce() :智能运算
                    • 例子1:找到年龄最大的,并求所有人的年龄之和
                      • 13.使用collect()做字符串join
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档