美文网首页
第五章:使用流

第五章:使用流

作者: 杨殿生 | 来源:发表于2018-09-27 11:42 被阅读0次

    筛选和切片

    用谓词筛选

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

    相关文章

      网友评论

          本文标题:第五章:使用流

          本文链接:https://www.haomeiwen.com/subject/upcdoftx.html