第五章:使用流

筛选和切片

用谓词筛选

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不依赖新生成的值
无限流不能做排序和归约

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

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