资讯专栏INFORMATION COLUMN

Java 8之stream介绍和使用

gxyz / 2558人阅读

摘要:使用我们来看下面这段代码,里面有一个属性代表菜品的卡路里值,现在的需求是按卡路里对菜品进行排序再返回菜名,并且要求卡路里的值大于。

前言:

在实际开发中经常需要获取各种各样不同格式的数据,因为数据库的表结构是一开始就设计好的所以很多时候我们不得不先从数据库里或其他地方获得数据后再根据需求去一层一层的筛选数据,在Java 8之前的做法不外乎就是各种List、Set一起上,各种循环判断。如果只是简单的需求还好说,循环个一两次再判断一下就可以解决,但是需求复杂的话就会写出很复杂的代码出来,时间久了后不仅自己看不懂,而且因为代码太复杂测试的时候不敢保证覆盖到所有的地方,万一代码到了线上出问题,不仅不好改还可能影响到以前的功能,而在Java 8中就提供了新的特性stream,专门用于对集合中的数据进行筛选、分类等操作,下面我们就会介绍stream的使用。

stream使用:

我们来看下面这段代码,Dish里面有一个属性calories代表菜品的卡路里值,现在的需求是按卡路里对菜品进行排序再返回菜名,并且要求卡路里的值大于400。我们可以看到下面的操作非常繁琐,先筛选出卡路里大于400的放入集合中,然后对这个集合进行排序,最后循环这个集合把名字放入一个新的集合,这是一个很常见的代码,在Java 8之前都是这么写的,但是这还只是对一个属性的筛选、排序就这么繁琐了,如果是多个属性会更加麻烦,下面我们就看看用stream是怎么实现的。

//将卡路里低于400的对象都放到集合中
List lowCaloricDishes = new ArrayList<>();
    for(Dish d: menu){
        if(d.getCalories() < 400){
            lowCaloricDishes.add(d);
        }
    }

//把这个集合排序
Collections.sort(lowCaloricDishes, new Comparator() {
    public int compare(Dish d1, Dish d2){
        return Integer.compare(d1.getCalories(), d2.getCalories());
    }
});

//再新建一个String类型的集合来存放菜名
List lowCaloricDishesName = new ArrayList<>();
for(Dish d: lowCaloricDishes){
    lowCaloricDishesName.add(d.getName());
}

这是Java 8中stream的用法,我们会发现这段代码写起来非常舒服,首先调用stream()方法获取了集合menu的流,然后调用了filter方法来筛选出卡路里超过400的元素,接着调用了sorted方法对筛选出来的元素进行排序,再调用map方法把筛选出来的元素里面的name属性抽出来作为一个新的流,最后一步则是调用collect方法把存放name的流转为List格式返回,得到的结果和上面一模一样,但是整个步骤一目了然,先做什么后做什么,非常清晰,这就是stream的用法。

import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.toList;

List menu = ...

List lowCaloricDishesName = menu.stream()
    //筛选出卡路里大于400的
    .filter(d -> d.getCalories() < 400)
    //按卡路里值排序
    .sorted(comparing(Dish::getCalories))
    //抽取名字属性创建一个新的流
    .map(Dish::getName)
    //这个流按List类型返回
    .collect(toList());
stream的定义:

讲到这里大家可能会产生疑惑,流到底是什么,为什么它可以进行这样的操作。简单来说流其实就是 “从支持数据处理操作的源生成的元素序列” ,这句话到底是什么意思呢?下面我们来看看流的各种特性就明白了。

元素序列,可以通过流访问到特定类型的一组有序的值,就像我们通过集合访问这些数据一样,只不过集合是为了存储数据,而流则注重与对数据的计算和处理。

源,流可以会从一个数据源那里获取数据并生成流,例如上面讲的从集合中获取,生成的流里面的元素和数据源里的一致。

数据处理操作,就像第一条里说的,流是注重与对数据的计算和处理,所以它有很多不同的方法可以对数据进行操作,例如筛选、分类、排序等等。

流水线,顾名思义,流的很多操作都会返回一个新的流,所以我们上面可以使用连缀的方式调用那些方法,其实每个操作都是基于它前面的那个操作返回的流进行的。

我们来看下面的这段代码和它的流程图。它一开始从menu这个集合中获取到了流,流里面的数据和集合是相同的,然后调用filter方法之后筛选出符合条件的元素组成一个新的流传递给了map方法,然后map方法又从这个流里面把元素的名字取出来组成一个新流传递给limit方法,limit方法则只取了前3个组成一个流传递给collect方法然后返回一个List,这就是流的工作原理

List list = menu.stream()
    //筛选出卡路里高于300的元素
    .filter(d -> d.getCalories() > 300)
    //获取名字组成的流
    .map(Dish::getName)
    //只取前3个
    .limit(3)
    //返回List格式
    .collect(toList());
System.out.println(list );

stream只能遍历一次:

流和集合不一样,集合可以想遍历多少次就遍历多少次,但是流只能遍历一次,如果你做了下面这样的操作,那代码会抛出一个java.lang.IllegalStateException异常,流已被操作或关闭。

List title = Arrays.asList("Java8", "In", "Action");
Stream s = title.stream();
s.forEach(System.out::println);
s.forEach(System.out::println);
stream的两种操作:

还是继续看这段代码,其中filtermaplimit操作被称为 中间操作中间操作 会返回一个新的流,而collect则被称为 终端操作 ,只有终端操作才会让整个流执行并关闭,也就是说只有当collect被执行时filtermaplimit才会被执行,上面讲到流只能遍历一次就是因为forEach就是一个终端操作,执行完后就关闭流了。

List list = menu.stream()
    //筛选出卡路里高于300的元素
    .filter(d -> d.getCalories() > 300)
    //获取名字组成的流
    .map(Dish::getName)
    //只取前3个
    .limit(3)
    //返回List格式
    .collect(toList());

以上就是stream的基本使用方法了,当然它的功能还远远不止这些,后面我们还会讲到筛选、分组、查找等更强大的操作。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/76443.html

相关文章

  • Top stackoverflow 问答系列Java 8 Stream 篇 (一)

    摘要:从发布到现在,已有三年多了,也得到了广泛的应用,但似乎里面最重要的特性和对很多人来说还是很陌生。想通过介绍一些实际的问题和答案来讲解在现实开发中我们可以通过和可以做些什么,以及什么是正确的姿势。 从Java 8 2014 发布到现在,已有三年多了,JDK 8 也得到了广泛的应用,但似乎Java 8里面最重要的特性:Lambdas和Stream APIs对很多人来说还是很陌生。想通过介绍...

    z2xy 评论0 收藏0
  • Java 8stream进阶

    摘要:获取每个元素的字符串长度放入新流中,然后转为类型。归约归约就是把整个流归约成一个值的操作,比如求集合中最大的元素所有元素值的和之类的操作。 前言: 上一篇文章 Java 8之stream介绍和使用 中讲解了stream的定义和用法,简单介绍几个最基本最常用的方法,其实stream还有更强大的功能,这篇文章就会给大家介绍stream的进阶用法。 筛选: 在上一篇文章中我们介绍了使用fi...

    Jaden 评论0 收藏0
  • Java 8数值流使用构建流的方式

    摘要:数值流的使用想要使用数值流其实很简单,只需要调用方法就可以获得一个数值流了,我们会发现数值流有更多的封装好的计算方法,更加方便我们对数值的计算。运行结果有时候我们可能会想将数值流转换回原来的流,我们可以调用方法。 数值流: 数值流,顾名思义就是专门用来操作基础数据类型的流,那它的作用是什么呢?先看下面的代码。这段代码是获取集合每个对象的num字段的值,然后求所和。得出的结果是15,看上...

    Tychio 评论0 收藏0
  • Java 8stream实际应用

    摘要:前言在前面的之介绍和使用和之进阶中讲了的使用方式和一些常用的方法,这篇文章就来演示一下的实际应用。实际应用先创建一个订单类和商品类,每个订单都有年份商品数量和商品对象属性,而商品类里面则包含了名字和价格属性。 前言: 在前面的 Java 8之stream介绍和使用 和 Java 8之stream进阶 中讲了stream的使用方式和一些常用的方法,这篇文章就来演示一下stream的实际应...

    jonh_felix 评论0 收藏0
  • 乐字节-Java8新特性Stream流(上)

    摘要:需要注意的是很多流操作本身就会返回一个流,所以多个操作可以直接连接起来,如下图这样,操作可以进行链式调用,并且并行流还可以实现数据流并行处理操作。为集合创建并行流。 上一篇文章,小乐给大家介绍了《Java8新特性之方法引用》,下面接下来小乐将会给大家介绍Java8新特性之Stream,称之为流,本篇文章为上半部分。 1、什么是流? Java Se中对于流的操作有输入输出IO流,而Jav...

    dingda 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<