zoukankan      html  css  js  c++  java
  • Lambda表达式和stream

    Lambda表达式

    语法格式一:无参数,无返回值

    ()->System.out.println("Hello,Lambda")

    语法格式二:有一个参数,并且无返回值

    (x)->System.out.println(x)

    语法格式三:若只有一个参数,小括号可以省略不写

    x->System.out.print(x)

    语法格式四:有两个以上的参数,有返回值,并且Lambda体中有多条语句

    Comparator<Integer>com=(x,y)->{     System.out.print("函数式接口");     return Integer.compare(x,y);}

    语法格式五:若Lamdba体中只有一条语句,return和大括号都可以省略不写

    Comparator<Integer>com=(x,y)->Integer.compare(x,y);

    语法格式六:Lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型,即“数据推断”

    (Integer x,Integer y)->Integer.compare(x,y)

    Stream API代替for循环

    List<String> nameStrs = Arrays.asList("Monkey", "Lion", "Giraffe","Lemur");
    // 将字符串list转为管道流Stream
    List<String> list = nameStrs.stream()
       // 使用filter过滤所有是L大写字母开头的字符串
          .filter(s -> s.startsWith("L"))
       // 然后过滤的字符串全部转为大写字母
          .map(String::toUpperCase)
       // 使用sorted方法进行排序
          .sorted()
       // 使用collect方法将管道流转为List
          .collect(toList());
    System.out.println(list);
    • 首先,我们使用Stream()函数,将一个List转换为管道流

    • 调用filter函数过滤数组元素,过滤方法使用lambda表达式,以L开头的元素返回true被保留,其他的List元素被过滤掉

    • 然后调用Map函数对管道流中每个元素进行处理,字母全部转换为大写

    • 然后调用sort函数,对管道流中数据进行排序

    • 最后调用collect函数toList,将管道流转换为List返回

    Limit与Skip管道数据截取

    List<String> limitN = Stream.of("Monkey", "Lion", "Giraffe", "Lemur")
          .limit(2)
          .collect(Collectors.toList());
    List<String> skipN = Stream.of("Monkey", "Lion", "Giraffe", "Lemur")
          .skip(2)
          .collect(Collectors.toList());
    • limt方法传入一个整数n,用于截取管道中的前n个元素。经过管道处理之后的数据是:[Monkey, Lion]。

    • skip方法与limit方法的使用相反,用于跳过前n个元素,截取从n到末尾的元素。经过管道处理之后的数据是: [Giraffe, Lemur]

    Distinct元素去重

    List<String> uniqueAnimals = Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion")
          .distinct()
          .collect(Collectors.toList());

    上面代码去重之后的结果是: ["Monkey", "Lion", "Giraffe", "Lemur"]

    Sorted排序

    默认的情况下,sorted是按照字母的自然顺序进行排序。如下代码的排序结果是:[Giraffe, Lemur, Lion, Monkey],字数按顺序G在L前面,L在M前面。第一位无法区分顺序,就比较第二位字母。

    List<String> alphabeticOrder = Stream.of("Monkey", "Lion", "Giraffe", "Lemur")
          .sorted()
          .collect(Collectors.toList());

    学习一下HashMap的merge()函数

    • 参数一:向map里面put的键

    • 参数二:向map里面put的值

    • 参数三:如果键发生重复,如何处理值。可以是一个函数,也可以写成lambda表达式。

            String k = "key";
           HashMap<String, Integer> map = new HashMap<String, Integer>() {{
               put(k, 1);
          }};
           map.merge(k, 2, (oldVal, newVal) -> oldVal + newVal);

    看上面一段代码,我们首先创建了一个HashMap,并往里面放入了一个键值为k:1的元素。当我们调用merge函数,往map里面放入k:2键值对的时候,k键发生重复,就执行后面的lambda表达式。表达式的含义是:返回旧值oldVal加上新值newVal(1+2),现在map里面只有一项元素那就是k:3。

    按Map的键排序

    // 创建一个Map,并填入数据
    Map<String, Integer> codes = new HashMap<>();
    codes.put("United States", 1);
    codes.put("Germany", 49);
    codes.put("France", 33);
    codes.put("China", 86);
    codes.put("Pakistan", 92);

    // 按照Map的键进行排序
    Map<String, Integer> sortedMap = codes.entrySet().stream()    
          .sorted(Map.Entry.comparingByKey())
          .collect(
                   Collectors.toMap(
                       Map.Entry::getKey,
                       Map.Entry::getValue,
                      (oldVal, newVal) -> oldVal,
                       LinkedHashMap::new
                  )
          );

    // 将排序后的Map打印
    sortedMap.entrySet().forEach(System.out::println);

    看上文中第二段代码:

    • 首先使用entrySet().stream() 将Map类型转换为Stream流类型。

    • 然后使用sorted方法排序,排序的依据是Map.Entry.comparingByKey(),也就是按照Map的键排序

    • 最后用collect方法将Stream流转成LinkedHashMap。 其他参数都好说,重点看第三个参数,就是一个merge规则的lambda表达式,与merge方法的第三个参数的用法一致。由于本例中没有重复的key,所以新值旧值随便返回一个即可。

    上面的程序将在控制台上打印以下内容,键(国家/地区名称)以自然字母顺序排序:

    China=86
    France=33
    Germany=49
    Pakistan=92
    United States=1
    请注意使用LinkedHashMap来存储排序的结果以保持顺序。默认情况下,Collectors.toMap()返回HashMap。HashMap不能保证元素的顺序。

    按Map的键排序

    Map<String, Integer> sortedMap2 = codes.entrySet().stream()
          .sorted(Map.Entry.comparingByValue())
          .collect(Collectors.toMap(
                   Map.Entry::getKey,
                   Map.Entry::getValue,
                  (oldVal, newVal) -> oldVal,
                   LinkedHashMap::new));

    sortedMap2.entrySet().forEach(System.out::println);

    这是显示Map按值排序的输出:

    United States=1
    France=33
    Germany=49
    China=86
    Pakistan=92

    使用TreeMap按键排序

    大家可能都知道TreeMap内的元素是有顺序的,所以利用TreeMap排序也是可取的一种方法。您需要做的就是创建一个TreeMap对象,并将数据从HashMapput到TreeMap中,非常简单:

    // 将 `HashMap` 转为 `TreeMap`
    Map<String, Integer> sorted = new TreeMap<>(codes);

    输出:

    China=86
    France=33
    Germany=49
    Pakistan=92
    United States=1

    ForEach和ForEachOrdered

    如果我们只是希望将Stream管道流的处理结果打印出来,而不是进行类型转换,我们就可以使用forEach()方法或forEachOrdered()方法。

    Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion")
          .parallel()
          .forEach(System.out::println);
    Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion")
          .parallel()
          .forEachOrdered(System.out::println);
    • parallel()函数表示对管道中的元素进行并行处理,而不是串行处理,这样处理速度更快。但是这样就有可能导致管道流中后面的元素先处理,前面的元素后处理,也就是元素的顺序无法保证

    • forEachOrdered从名字上看就可以理解,虽然在数据处理顺序上可能无法保障,但是forEachOrdered方法可以在元素输出的顺序上保证与元素进入管道流的顺序一致。也就是下面的样子(forEach方法则无法保证这个顺序):

    Monkey
    Lion
    Giraffe
    Lemur
    Lion

    元素的收集collect

    java Stream 最常见的用法就是:一将集合类转换成管道流,二对管道流数据处理,三将管道流处理结果在转换成集合类。那么collect()方法就为我们提供了这样的功能:将管道流处理结果在转换成集合类。

    1.收集为Set

    通过Collectors.toSet()方法收集Stream的处理结果,将所有元素收集到Set集合中。

    Set<String> collectToSet = Stream.of(
      "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
    )
    .collect(Collectors.toSet());

    //最终collectToSet 中的元素是:[Monkey, Lion, Giraffe, Lemur],注意Set会去重。

    2.收集到List

    同样,可以将元素收集到List使用toList()收集器中。

    List<String> collectToList = Stream.of(
      "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
    ).collect(Collectors.toList());

    // 最终collectToList中的元素是: [Monkey, Lion, Giraffe, Lemur, Lion]

    3.通用的收集方式

    上面为大家介绍的元素收集方式,都是专用的。比如使用Collectors.toSet()收集为Set类型集合;使用Collectors.toList()收集为List类型集合。那么,有没有一种比较通用的数据元素收集方式,将数据收集为任意的Collection接口子类型。 所以,这里就像大家介绍一种通用的元素收集方式,你可以将数据元素收集到任意的Collection类型:即向所需Collection类型提供构造函数的方式。

    LinkedList<String> collectToCollection = Stream.of(
      "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
    ).collect(Collectors.toCollection(LinkedList::new));

    //最终collectToCollection中的元素是: [Monkey, Lion, Giraffe, Lemur, Lion]

    注意:代码中使用了LinkedList::new,实际是调用LinkedList的构造函数,将元素收集到Linked List。当然你还可以使用诸如LinkedHashSet::newPriorityQueue::new将数据元素收集为其他的集合类型,这样就比较通用了。

    4.收集到Array

    通过toArray(String[]::new)方法收集Stream的处理结果,将所有元素收集到字符串数组中。

    String[] toArray = Stream.of(
      "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
    ) .toArray(String[]::new);

    //最终toArray字符串数组中的元素是: [Monkey, Lion, Giraffe, Lemur, Lion]

    5.收集到Map

    使用Collectors.toMap()方法将数据元素收集到Map里面,但是出现一个问题:那就是管道中的元素是作为key,还是作为value。我们用到了一个Function.identity()方法,该方法很简单就是返回一个“ t -> t ”(输入就是输出的lambda表达式)。另外使用管道流处理函数distinct()来确保Map键值的唯一性。

    Map<String, Integer> toMap = Stream.of(
       "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
    )
    .distinct()
    .collect(Collectors.toMap(
          Function.identity(),   //元素输入就是输出,作为key
          s -> (int) s.chars().distinct().count()// 输入元素的不同的字母个数,作为value
    ));

    // 最终toMap的结果是: {Monkey=6, Lion=4, Lemur=5, Giraffe=6}  

    6.分组收集groupingBy

    Collectors.groupingBy用来实现元素的分组收集,下面的代码演示如何根据首字母将不同的数据元素收集到不同的List,并封装为Map。

    Map<Character, List<String>> groupingByList =  Stream.of(
       "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
    )
    .collect(Collectors.groupingBy(
          s -> s.charAt(0) ,  //根据元素首字母分组,相同的在一组
          // counting()       // 加上这一行代码可以实现分组统计
    ));

    // 最终groupingByList内的元素: {G=[Giraffe], L=[Lion, Lemur, Lion], M=[Monkey]}
    //如果加上counting() ,结果是: {G=1, L=3, M=1}

    #### 其他常用方法

    boolean containsTwo = IntStream.of(1, 2, 3).anyMatch(i -> i == 2);
    // 判断管道中是否包含2,结果是: true

    long nrOfAnimals = Stream.of(
       "Monkey", "Lion", "Giraffe", "Lemur"
    ).count();
    // 管道中元素数据总计结果nrOfAnimals: 4


    int sum = IntStream.of(1, 2, 3).sum();
    // 管道中元素数据累加结果sum: 6


    OptionalDouble average = IntStream.of(1, 2, 3).average();
    //管道中元素数据平均值average: OptionalDouble[2.0]



    int max = IntStream.of(1, 2, 3).max().orElse(0);
    //管道中元素数据最大值max: 3



    IntSummaryStatistics statistics = IntStream.of(1, 2, 3).summaryStatistics();
    // 全面的统计结果statistics: IntSummaryStatistics{count=3, sum=6, min=1, average=2.000000, max=3}

     

  • 相关阅读:
    FFT-C语言
    C语言解析WAV音频文件
    图基(Tukey)检验
    方差分析中均值比较的方法
    模拟信号采样过程
    FS,FT,DFS,DTFT,DFT,FFT的联系和区别
    枚举enum类型
    样本概率统计
    宏和内联函数
    变量的生存期和存储分配
  • 原文地址:https://www.cnblogs.com/liuli-warriors/p/12659529.html
Copyright © 2011-2022 走看看