• stream流使用


      stream流类似于lambda表达式的函数式编程,集合使用过滤、添加元素等更加方便。

    根据Collection获取流

    • Collection接口中有一个stream()方法,可以获取流 , default Stream<E> stream():获取一个Stream流

      1. 通过List集合获取:           list.stream()

      2. 通过Set集合获取

    根据Map获取流

    • 使用所有键的集合来获取流

    • 使用所有值的集合来获取流

    • 使用所有键值对的集合来获取流

    list.stream().map(p -> map.get(p.getType())).collect(Collectors.toList());

    根据数组获取流

    • Stream流中有一个static <T> Stream<T> of(T... values)

      • 通过数组获取:             (Stream.of(arr))

      • 通过直接给多个数据的方式

    函数拼接与终结方法

    在上述介绍的各种方法中,凡是返回值仍然为Stream接口的为函数拼接方法,它们支持链式调用;而返回值不再为Stream接口的为终结方法,不再支持链式调用。如下表所示:

    方法名方法作用方法种类是否支持链式调用

    说明

    count 统计个数 终结  
    forEach 逐一处理 终结  
    filter 过滤 函数拼接  
    limit 取用前几个 函数拼接  
    skip 跳过前几个 函数拼接  
    map 映射 函数拼接

    流中的元素映射到另外一个流中

    (转换为其他类型)

    concat 组合 函数拼接 拼接两个流

    收集Stream结果

    1、收集到集合中

    <R,A> R collect(Collector<? super T,A,R> collector): 把流中的数据收集到单列集合中

    参数Collector如何得到? 使用java.util.stream.Collectors工具类中的静态方法:

    • public static <T> Collector<T, ?, List<T>> toList():转换为List集合。

    • public static <T> Collector<T, ?, Set<T>> toSet():转换为Set集合。

    示例:stream.collect(collectors.toList())

       stream.collect(collectors.toSet())

    2、收集到数组中

    Stream提供toArray方法来将结果放到一个数组中,返回值类型是Object[]的:

    Object[] toArray();

    Java中双冒号::的使用

    使用范例

    方法调用

    person -> person.getAge();
    可以替换成
    Person::getAge

    x -> System.out.println(x)
    可以替换成
    System.out::println
    out是一个PrintStream类的对象,println是该类的方法,依据x的类型来重载方法

    创建对象

    () -> new ArrayList<>();
    可以替换为
    ArrayList::new
    new关键字实际上调用的是ArrayList的构造方法

    ----------------------------------更新-------------------------------------------

    flapmap使用

    参考https://leetcode-cn.com/problems/flatten-nested-list-iterator/    

    341. 扁平化嵌套列表迭代器

    扁平化,拆解外层的option

    public String getCarInsuranceName(Optional<Person> person) {
    return person.flatMap(Person::getCar)
    .flatMap(Car::getInsurance)
    .map(Insurance::getName)
    .orElse("Unknown");
    }
    

      

    List<String> words = new ArrayList<>();
    words.add("Hello");
    words.add("World");
    List<String> uniqueCharacters =
    words.stream()
    .map(w -> w.split(""))
    .flatMap(Arrays::stream)
    .distinct()
    .collect(Collectors.toList());

      

    List<Integer> numbers1 = Arrays.asList(1, 2, 3);
            List<Integer> numbers2 = Arrays.asList(3, 4);
            List<int[]> pairs = numbers1.stream()
                    .flatMap(i -> numbers2.stream()
                            .map(j -> new int[] {i, j})
                    )
                    .collect(toList());
    

      输出[[1,3],[1,4],[2,3],[2,4],[3,3],[3,4]]

    查找元素

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

      

    reduce 归约

    int sum = numbers.stream().reduce(0, (a, b) -> a + b);

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

    Optional<Integer> max = numbers.stream().reduce(Integer::max);

    分组groupingBy

    public enum CaloricLevel { DIET, NORMAL, FAT }
    Map<CaloricLevel, List<Dish>> dishesByCaloricLevel = menu.stream().collect(
    groupingBy(dish -> {
    if (dish.getCalories() <= 400) return CaloricLevel.DIET;
    else if (dish.getCalories() <= 700) return
    CaloricLevel.NORMAL;
    else return CaloricLevel.FAT;
    } ));

    //多级分组
    Map<Dish.Type, Map<CaloricLevel, List<Dish>>> dishesByTypeCaloricLevel =
    menu.stream().collect(
    groupingBy(Dish::getType,
    groupingBy(dish -> {
    if (dish.getCalories() <= 400) {
    return CaloricLevel.DIET;
    } else if (dish.getCalories() <= 700) {
    return CaloricLevel.NORMAL;
    } else {
    return CaloricLevel.FAT;
    }
    })
    )
    );

      

     分区partitioningBy

    Map<Boolean, List<Dish>> partitionedMenu =
    menu.stream().collect(partitioningBy(Dish::isVegetarian));
    这会返回下面的Map:
    {false=[pork, beef, chicken, prawns, salmon],
    true=[french fries, rice, season fruit, pizza]}

    partitioningBy工厂方法有一个重载版本,可以像下面这样传递第二个收集器:
    Map<Boolean, Map<Dish.Type, List<Dish>>> vegetarianDishesByType =
    menu.stream().collect(
    partitioningBy(Dish::isVegetarian,
    groupingBy(Dish::getType)));
    这将产生一个二级Map:
    {false={FISH=[prawns, salmon], MEAT=[pork, beef, chicken]},true={OTHER=[french fries, rice, season fruit, pizza]}}

    这里,对于分区产生的素食和非素食子流,分别按类型对菜肴分组,得到了一个二级Map,
    二级分组得到的结果类似。再举一个例子,你可以重用前面的代码来找到素食和非素
    食中热量最高的菜:
    Map<Boolean, Dish> mostCaloricPartitionedByVegetarian =
    menu.stream().collect(
    partitioningBy(Dish::isVegetarian,
    collectingAndThen(
    maxBy(comparingInt(Dish::getCalories)),
    Optional::get)));
    这将产生以下结果:
    {false=pork, true=pizza}

      

    optional对象

    我们决定采用orElse方法读取这个变量的值,使用这种方式你还可以定义一个默认值,遭
    遇空的Optional变量时,默认值会作为该方法的调用返回值。Optional类提供了多种方法读取
    Optional实例中的变量值。
     get()是这些方法中最简单但又最不安全的方法。如果变量存在,它直接返回封装的变量
    值,否则就抛出一个NoSuchElementException异常。所以,除非你非常确定Optional
    变量一定包含值,否则使用这个方法是个相当糟糕的主意。此外,这种方式即便相对于
    嵌套式的null检查,也并未体现出多大的改进。
     orElse(T other)是我们在代码清单10-5中使用的方法,正如之前提到的,它允许你在
    Optional对象不包含值时提供一个默认值。
     orElseGet(Supplier<? extends T> other)是orElse方法的延迟调用版,Supplier
    方法只有在Optional对象不含值时才执行调用。如果创建默认值是件耗时费力的工作,
    你应该考虑采用这种方式(借此提升程序的性能),或者你需要非常确定某个方法仅在
    Optional为空时才进行调用,也可以考虑该方式(这种情况有严格的限制条件)。
     orElseThrow(Supplier<? extends X> exceptionSupplier)和get方法非常类似,
    它们遭遇Optional对象为空时都会抛出一个异常,但是使用orElseThrow你可以定制希
    望抛出的异常类型。
     ifPresent(Consumer<? super T>)让你能在变量值存在时执行一个作为参数传入的
    方法,否则就不进行任何操作。
    Optional类和Stream接口的相似之处,远不止map和flatMap这两个方法

  • 相关阅读:
    常用算法之选择排序
    常用算法之插入排序
    常用算法之冒泡排序
    Python hashlib模块 (主要记录md5加密)
    Django Model
    CSS实现table td中文字的省略与显示
    JS读取文件,Javascript之文件操作 (IE)
    ie6789和其他浏览器之间的鼠标左、中、右键的event.button不一致的办法
    兼容和样式
    kindeditor的docs
  • 原文地址:https://www.cnblogs.com/chenfx/p/14127990.html
Copyright © 2020-2023  润新知