Java8入门梳理之流(Stream)的使用

前言

1.流 (Stream)是什么

流是Java8引入的新成员,以声明方式处理集合数据,将基础操作链接起来,完成复杂的数据处理流水线,提供透明的并行处理能力。
即从支持数据处理操作的源生成的元素序列,流的来源,可以是集合,数组等。

2. 流与集合的区别
(1). 时间与空间

集合是一个内存中(空间)的数据结构,它需要集合中的每个元素都得算出来(时间)才能添加到集合里(例如add,remove方法,但每个元素都是放在内存里,得算出来之后才能在集合里)。
例如:我们大家都去吃顿饭,等待一个一个菜的上,但是我们又要拍照,所以要等待时间上齐所有菜,这样让我们拍完就可以开始吃哩。
流则是在概念上固定(空间)的数据结构(不能add或者remove元素),其元素则是按需(时间)计算的。
例如:回转寿司,一个寿司接着一个寿司,当寿司来的时候你只需要到的时候想着要吃哪个口味的寿司就好了。

(2).流只遍历一次

和迭代器类似,流只能遍历一次。

(3).外部迭代与内部迭代

外部迭代:使用Collection接口需要用户去做迭代(比如用for-each)。
内部迭代:它帮你把迭代做了,还把得到的流值存在了某个地方,你只要给出一个函数说要干什么就可以了,并且能实现数据并行。

3. 流的组成三要素

(1).数据源、(2).中间操作、(3).终端操作

Set<String> set  = list.stream()   //数据源
.map(sku -> sku.getSkuName())  //中间操作,会返回一个流,只遍历一次
.collect(Collectors.toSet());          // 终端操作
//终端操作是整个流操作的开关,没有终端操作,中间操作就不会执行。
4.流的操作分类

包含中间操作、终端操作。
(1).中间操作是指会返回一个流,每个流都只能遍历一次。既包含(无状态、有状态操作)。
中间操作(无状态):filter、map、flatMap、peek等。
中间操作(有状态):distinct、skip、limit、sorted等。
(2).终端操作是整个流操作的开关,没有终端操作,中间操作就不会执行。既包含(非短路、短路操作)。
终端操作(短路): allMatch、anyMatch、noneMatch、findFirst、findAny等。
终端操作(非短路):collect、forEach、sum、count、max、min等。

5.流的使用

准备好一个练习demo
(1).先创建一个商品类

public class Product {
    // 编号
    private Integer proId;
    // 商品名称
    private String proName;
    // 单价
    private Double proPrice;
    // 购买个数
    private Integer totalNum;
    // 总价
    private Double totalPrice;
    // 商品类型
    private Enum proCategory;

    /**
     * 构造函数
     * @param proId
     * @param proName
     * @param proPrice
     * @param totalNum
     * @param totalPrice
     * @param proCategory
     */
    public Sku(Integer proId, String proName,
               Double proPrice, Integer totalNum,
               Double totalPrice, Enum proCategory) {
        this.proId = proId;
        this.proName = proName;
        this.proPrice = proPrice;
        this.proNum = totalNum;
        this.totalPrice = totalPrice;
        this.proCategory = proCategory;
    }
}

(2).创建一个枚举类

public enum ProCategoryEnum {
    CLOTHING(10, "服装类"),
    ELECTRONICS(20, "数码类"),
    SPORTS(30, "运动类"),
    BOOKS(40, "图书类");

    // 商品类型的编号
    private Integer code;
    // 商品类型的名称
    private String name;

    /**
     * 构造函数
     * @param code
     * @param name
     */
    ProCategoryEnum(Integer code, String name) {
        this.code = code;
        this.name = name;
    }
}

(3).再创建一个CartService

public class CartService {

    // 加入到购物车中的商品信息
    private static List<Product> cartProList =
            new ArrayList<Product>(){
        {
            add(new Product(654032, "无人机",
                    4999.00, 1,
                    4999.00, ProCategoryEnum.ELECTRONICS));

            add(new Product(642934, "VR一体机",
                    2299.00, 1,
                    2299.00, ProCategoryEnum.ELECTRONICS));

            add(new Product(645321, "纯色衬衫",
                    409.00, 3,
                    1227.00, ProCategoryEnum.CLOTHING));

            add(new Product(654327, "牛仔裤",
                    528.00, 1,
                    528.00, ProCategoryEnum.CLOTHING));

            add(new Product(675489, "跑步机",
                    2699.00, 1,
                    2699.00, ProCategoryEnum.SPORTS));

            add(new Product(644564, "Java编程思想",
                    79.80, 1,
                    79.80, ProCategoryEnum.BOOKS));

            add(new Product(678678, "Java核心技术",
                    149.00, 1,
                    149.00, ProCategoryEnum.BOOKS));

            add(new Product(697894, "算法",
                    78.20, 1,
                    78.20, ProCategoryEnum.BOOKS));

            add(new Product(696968, "TensorFlow进阶指南",
                    85.10, 1,
                    85.10, ProCategoryEnum.BOOKS));
        }
    };

    /**
     * 获取商品信息列表
     * @return
     */
    public static List<Product> getCartProList() {
        return cartProList;
    }
}

*(5.1).流的操作-filter
filter 使用: 过滤掉不符合断言判断的数据

public class StreamOperator {

    List<Product> list = CartService.getCartProList();

    @Before
    public void init(){
        list = CartService.getCartProList();
    }

    /**
     * filter 使用: 过滤掉不符合断言判断的数据
     */
    public void filterTest(){
        list.stream()
                // filter
                .filter(pro ->           ProCategoryEnum.BOOKS.equals(pro.getProCategory()))
                .forEach(item ->
                        System.out.println(
                                JSON.toJSONString(
                                        item,true)));
    }
}
// 输出结果
{
    "proCategory":"BOOKS",
    "proId":644564,
    "proName":"Java编程思想",
    "proPrice":79.8,
    "totalNum":1,
    "totalPrice":79.8
}........
.....

(5.2).流的操作-map
将一个元素转换成另一个元素

   public void mapTest(){
        list.stream()
                .map(pro -> pro.getProName())
                .forEach(item -> System.out.println(
                        JSON.toJSONString(
                                item,true)));
    }
// 输出结果
"无人机"
"VR一体机"
"纯色衬衫"
"牛仔裤"
"跑步机"
"Java编程思想"
"Java核心技术"
"算法"
"TensorFlow进阶指南"

(5.3).流的操作-flatMap
flatMap使用: 将一个对象转换成流

  public void flatMapTest(){
        list.stream()
                //flatMap
                  .flatMap(pro -> Arrays.stream(pro.getProductName().split("")))
                .forEach(item -> System.out.println(
                        JSON.toJSONString(
                                item,true)));
    }
// 输出结果
"无"
"人"
"机"
"V"
"R"
"一"
"体"
"机"
"纯"
"色"
.....

(5.4).流的操作-peek
peek使用: 对流中元素进行遍历操作,与forEach类似,但不会销毁元素

    public void peekTest(){
        list.stream()
                //peek
                .peek(pro ->
                        System.out.println(pro.getProName()))
                .forEach(item ->
                        System.out.println(
                                JSON.toJSONString(item,true)));
    }
//输出结果
无人机
{
    "proCategory":"ELECTRONICS",
    "proId":654032,
    "proName":"无人机",
    "proPrice":4999.0,
    "totalNum":1,
    "totalPrice":4999.0
}
VR一体机....
....

(5.5).流的操作-sort
sort使用: 对流中元素进行排序,可选择自然排序或指定排序规则 有状态操作

    public void sortTest(){
        list.stream()
                .peek(pro -> System.out.println(pro.getSkuName()))
                //sort
                .sorted(
                        Comparator.comparing(Product::getTotalPrice))
                .forEach(item ->
                        System.out.println(JSON.toJSONString(item,true)));
    }
//输出结果
无人机
VR一体机
纯色衬衫
牛仔裤
跑步机
Java编程思想
Java核心技术
算法
TensorFlow进阶指南
{
    "proCategory":"BOOKS",
    "proId":697894,
    "proName":"算法",
    "proPrice":78.2,
    "totalNum":1,
    "totalPrice":78.2
}....
....

(5.6).流的操作-distinct
distinct使用:去除重复的元素

  public void distinctTest(){
        list.stream()
                .map(pro -> pro.getSkuCategory())
                // distinct
                .distinct()
                .forEach(item ->
System.out.println(JSON.toJSONString(item,true)));
    }
//输出结果
"ELECTRONICS"
"CLOTHING"
"SPORTS"
"BOOKS"

(5.7).流的操作-skip
skip:使用:跳过前N条记录。有状态操作

    public void skipTest(){
        list.stream()
              .sorted(Comparator.comparing(Product::getTotalPrice))
                .skip(3)
                .forEach(item ->                System.out.println(JSON.toJSONString(item,true)));
    }
//输出结果
{
    "proCategory":"BOOKS",
    "proId":678678,
    "proName":"Java核心技术",
    "proPrice":149.0,
    "totalNum":1,
    "totalPrice":149.0
}
{
    "proCategory":"CLOTHING",
    "proId":654327,
    "proName":"牛仔裤",
    "proPrice":528.0,
    "totalNum":1,
    "totalPrice":528.0
}
....
...

(5.8).流的操作-limit
lmit使用: 截断前N条记录

    public void limiTest(){
        list.stream()
           .sorted(Comparator.comparing(Product::getTotalPrice))
                // limit
                // 制作假分页
                .skip(0 * 3) //跳过前三条   0   .skip(1 * 3 )以此类推
                .limit(3)   // 3 条数据
                .forEach(item ->                        System.out.println(JSON.toJSONString(item,true)));
    }
//输出结果

(5.9).流的操作-allMatch
allMatch使用: 终端操作,短路操作.所有元素匹配返回true

   public void allMatchTest(){
        boolean match =
                list.stream()
                        //allMatch
                     .peek(pro -> System.out.println(pro.getProName()))
                     .allMatch(pro -> pro.getTotalPrice() > 100);
                System.out.println(match);
    }
//输出结果
无人机
VR一体机
纯色衬衫
牛仔裤
跑步机
Java编程思想
false

(5.10).流的操作-anyMatch
anyMatch使用: 任何元素匹配,返回true

    public void anyMatchTest(){
        boolean match = list.stream()
                //anyMatch
                .peek(pro -> System.out.println(pro.getSkuName()))
                .anyMatch(pro -> pro.getTotalPrice() > 100);
        System.out.println(match);
        Set<String> set  = list.stream().map(pro -> pro.getProName()).collect(Collectors.toSet());
    }
//输出结果
无人机
true

(5.11).流的操作-noneMatch
noneMatchTest 使用: 任务元素都不匹配,返回true

    public void noneMatchTest(){
        boolean match = list.stream()
                .peek(sku -> System.out.println(pro.getProName()))
                //noneMatch
                .noneMatch(pro -> pro.getTotalPrice() > 10_000);
        System.out.println(match);
    }
//输出结果
无人机
VR一体机
纯色衬衫
....
....
true

(5.12).流的操作-findFirst
findFirst使用:找到第一个

public void findFirstTest(){
        Optional<Product> otlPro
                = list.stream()
                //findFirst
                .findFirst();     System.out.println(JSON.toJSONString(otlPro.get(),true));
    }
//输出结果
{
    "proCategory":"ELECTRONICS",
    "proId":654032,
    "proName":"无人机",
    "proPrice":4999.0,
    "totalNum":1,
    "totalPrice":4999.0
}

(5.13).流的操作-findAny
findAny使用:找到任意一个

    public void findAnyTest(){
        Optional<Product> otlPro
                = list.stream()
                // findAny
                .findAny();    System.out.println(JSON.toJSONString(otlPro.get(),true));
    }
//输出结果
{
    "proCategory":"ELECTRONICS",
    "proId":654032,
    "proName":"无人机",
    "proPrice":4999.0,
    "totalNum":1,
    "totalPrice":4999.0
}

(5.14).流的操作-max
max使用: 找出最大值

    public void maxTest(){
      OptionalDouble optionalDouble  =
              list.stream()
                //获取总价
              .mapToDouble(Product::getTotalPrice)
              .max();
      System.out.println(optionalDouble.getAsDouble());
    }
//输出结果
4999.0

(5.15).流的操作-min
min使用: 找出最小值

    public void minTest(){
        OptionalDouble optionalDouble  =
                list.stream()
                        //获取总价
                        .mapToDouble(Product::getTotalPrice)
                        .min() ;
        System.out.println(optionalDouble.getAsDouble());
    }
//输出结果
78.2

(5.16).流的操作-count
count使用: 总计数量

    public void countTest(){
        long count = list.stream()
                .count();
        System.out.println(count);
    }
//输出结果
9

测试 main主函数

    public static void main(String args[]){
        StreamOperator streamOperator = new StreamOperator();
        streamOperator.countTest();
    }
6.结语

大致就把基本用到Stream流梳理完,该文章是通过某课视频学习而练习总结做记录的应用Demo。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,366评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,521评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,689评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,925评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,942评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,727评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,447评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,349评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,820评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,990评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,127评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,812评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,471评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,017评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,142评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,388评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,066评论 2 355