第五章:使用流

筛选和切片

用谓词筛选

filter

使用Stream接口中的filter方法
筛选有所的素菜

        List<Dish> vegetairanMenu = menu.stream()
                .filter(Dish::isVegetarian)
                .collect(Collectors.toList());
谓词筛选一个流.png

distinct

筛选各异的元素
Stream的distinct方法,它会返回一个元素各异(根据流所生成元素的hashCode和equals方法实现)的流,通俗的说就是不去除重复元素

        List<Integer> number = Arrays.asList(1,2,1,3,3,2,4);
        number.stream()
                .filter(integer -> integer%2==0)
                .distinct()
                .forEach(System.out::println);
image.png

limit

截断流
limit(n),返回一个不超过给定长度的流
热量超过300卡路里的头三道菜

        List<Dish> dishes = menu.stream()
                .filter(dish -> dish.getCalories() > 300)
                .limit(3)
                .collect(Collectors.toList());

注意该方法只选出了复合谓词的头三个元素,就立刻返回结果

skip

skip(n) 返回丢掉了前n个元素的流。如果流中不足n个,则返回一个空流
跳过超过300卡路里的头两道菜,并返回剩下的

        List<Dish> dishes = menu.stream()
                .filter(dish -> dish.getCalories() > 300)
                .skip(2)
                .collect(Collectors.toList());

映射

map

对流中每一个元素应用函数
提取流中菜肴的名称

        List<String> dishes = menu.stream()
                .map(Dish::getName)
                .collect(Collectors.toList());

给定一个单词列表,返回另一个列表,显示有几个字母

        List<String> words = Arrays.asList("Java 8","Lambda","In","Action");
        List<Integer> wordLengths =words.stream()
                .map(String::length)
                .collect(Collectors.toList());

找出每到菜名有多长

        List<Integer> dishes = menu.stream()
                .map(Dish::getName)
                .map(String::length)
                .collect(Collectors.toList());

flatmap

流的扁平化
一张词表,返回一张列表,列出里面个不相同的字符
这个使用map是不可以的,如下

         words.stream()
                 .map(word -> word.split(""))
                 .distinct()
                 .collect(Collectors.toList());

把单词映射成一个字符表,然后去重,map方法的lambda表达式为每个单词返回一个String[]。因此map返回的流实际上是Stream<String[]>类型,我们想要的事用Stream<String>类表示一个字符流,这时候要使用flatmap

1,尝试使用map和Arrays.stream()
我们需要一个字符流,而不是数组流,Arrays.stream()的方法可以接受一个数组并产生一个流,还是不行因为我们得到的是一个独立的流
2,使用flatmap

        List<String> words = Arrays.asList("Java 8", "Lambda", "In", "Action");
        List<String> uniqueCharacters = words.stream()
                .map(word -> word.split(""))
                .flatMap(Arrays::stream)
                .distinct()
                .collect(Collectors.toList());

flatMap方法效果,个数组不是分别映射成一个流,而是映射成流内容,所有使用map(Arrays::stream)时生成的单个流都被合并起来,即扁平化为一个流

使用flatMap找出单词列表中各不相同的字符.png

map主要是用于遍历每个参数,然后进行参数合并或者返回新类型的集合。
flatMap主要是用于流合并,流转换,这个功能非常实用,他是默认实现多CPU并行执行的,所以我们合并集合优先实用这种方式。

查找和匹配

anyMatch

流中是否有一个已结元素能匹配给定的谓词

        if (menu.stream().anyMatch(Dish::isVegetarian)){
            
        }

会返回一个boolean值,因此是一个终端操作

allMatch

流中元素是否都能匹配给订的谓词

boolean isHealthy = menu.stream().allMatch(dish -> dish.getCalories() < 1000);

noneMatch

确保流中没有任何元素与给定谓词匹配

 boolean isHealthy = menu.stream().noneMatch(dish -> dish.getCalories() >= 1000);

短路求值
比如and操作只要检测到一个为false就不需要检测后面的表达式了,对于流而言allMatch,anyMacth,noneMatch,findFiirst,findAny

查找元素

findAny

返回当前流中的任意元素
找出一到素食菜肴

        Optional<Dish> dish = menu.stream()
                .filter(Dish::isVegetarian)
                .findAny();

Optional

是一个容器,代表一个值存在或者不存在
isPresent() 有值返回true,否则返回false
ifPresent(Consumer<T>) 值存在是执行给定的代码块
T get() 会在值存在是范湖值,否则抛出NoSuchElement异常
T orElse(T other) 会在值不存在时返回值,否则返回默认值
检测Optional对象中是否存在一道菜可以访问其名称

        menu.stream()
                .filter(Dish::isVegetarian)
                .findAny()
                .ifPresent(dish -> System.out.println(dish.getName()));

findFirst

查找流中第一个元素

        Optional<Dish> dish = menu.stream()
                .filter(Dish::isVegetarian)
                .findFirst();

为什么会同时有findFirst findAny?
因为并行,findFirst在并行上限制很多,如果不关心返回的数据是哪个那么使用findAny

规约

reduce

元素求和

        int sum = 0;
        for (int x:first){
            sum = +x;
        }

使用流

        int sum2 = first.stream().reduce(0,(a,b) -> a + b);
使用reduce来对流中的数字求和.png

首先0作为lambda(a)的第一个参数,从流中获取4作为第二个参数。0+4=4,生成新的累计值,累计值在和下一个5调用lambda,依次类推
也可以简写成

int sum3 = first.stream().reduce(0,Integer::sum);

无初始值

        Optional<Integer> sum4 = first.stream().reduce(Integer::sum);

最大值和最小值

        Optional<Integer> min = first.stream().reduce(Integer::min);

数值流

        int calories = menu.stream()
                .map(Dish::getCalories)
                .reduce(0,Integer::sum);

这段代码的问题是,暗含装箱操作,每一个Integer都必须拆箱成一个原始类型,在进行求和

原始类型流特化

映射到数值流
IntStream,DoubleStream,LongStream

        int calories = menu.stream()
                .mapToInt(Dish::getCalories)
                .sum();

使用mapToInt,mapToDouble,mapToLong,如果流失空返回为0
转换回对象流

        IntStream intStream = menu.stream().mapToInt(Dish::getCalories);
        Stream<Integer> stream = intStream.boxed();

OptionalInt,OptionalLong,OptionalDouble
找到IntStream中的最大值,如果没有则为1

        OptionalInt maxCalories = menu.stream().mapToInt(Dish::getCalories).max();
        int max = maxCalories.orElse(1);

数值范围
IntStream,LongStream静态方法用用于生成范围值range,rangeClosed

        IntStream evenNumbers = IntStream.rangeClosed(1,100);

构建流

由值创建流

Stream<String> stringStream = Stream.of("java 8 ","lambda","in","action");

由数组创建流

        IntStream intStream = Arrays.stream(nums);

由文件生成流

        long uniqueWords = 0;
        try (Stream<String> lines = Files.lines(Paths.get("data.txt"), Charset.defaultCharset())) {
            uniqueWords = lines.flatMap(l -> Arrays.stream(l.split("")))
                    .distinct()
                    .count();
        } catch (IOException io) {

        }

由函数生成流

Stream.iterate Stream.generate创建无限流
生成10和偶数

        Stream.iterate(0,n -> n + 2)
                .limit(10)
                .forEach(System.out::println);
        Stream.generate(Math::random)
                .limit(10)
                .forEach(System.out::println);

他们两个的区别是iterate依赖每次新生成的值,generate不依赖新生成的值
无限流不能做排序和归约

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

推荐阅读更多精彩内容

  • 概要 流让你从外部迭代转向内部迭代。这样,你就用不着写下面这样的代码来显式地管理数据集合的迭代(外部迭代)了: 现...
    浔它芉咟渡阅读 1,506评论 1 2
  • 第一章 为什么要关心Java 8 使用Stream库来选择最佳低级执行机制可以避免使用Synchronized(同...
    谢随安阅读 1,494评论 0 4
  • 章节内容筛选、切片和匹配查找、匹配和规约使用数值范围等数值流从多个源创建流无限流 筛选和切片 用谓词筛选 Stre...
    谢随安阅读 3,871评论 0 0
  • Java8 in action 没有共享的可变数据,将方法和函数即代码传递给其他方法的能力就是我们平常所说的函数式...
    铁牛很铁阅读 1,235评论 1 2
  • 流提供了一种让我们可以在比集合更高的概念级别上指定计算的数据试图,用来解决“做什么而非怎么做”的问题。 从迭代到流...
    _gitignore阅读 1,210评论 0 1