java中lambda表达式的使用案例技巧

Functional Interface

一个接口仅有一个抽象方法,比如Runnable、Comparator等。在任何一个需要Functional Interface对象的地方,都可以使用lambda表达式。

Method Reference

将lambda表达式的参数作为参数传递给一个方法,他们的执行效果是相同的,则该lambda表达式 可以使用Method Reference表达,以下两种方式是等价的:

 System.out::println
 (x) -> System.out.println(x)
       
 Math::pow 
 (x, y) -> Math.pow(x, y)
  1. Object::instanceMethod

  2. Class::staticMethod

  3. Class::instanceMethod

对于前两种方式,对应的lambda表达式的参数和method的参数是一致的

对于第三种方式,对应的lambda表达式的语句体中,第一个参数作为对象,调用method,将其它参数

 String::compareToIgnoreCase
 (s1, s2) -> s1.compareToIgnoreCase(s2)

Constructor Reference与Method Reference类似,只不过是特殊的method:new,具体调用的是哪个构造函数,由上下文环境决定,比如:

 List<String> labels = ...;
 Stream<Button> stream = labels.stream().map(Button::new);

Button::new等价于(x) -> Button(x),所以调用的构造函数是:Button(x); 除了创建单个对象,也可以创建对象数组,如下面两种方式等价:

 int[]::new 
 (x) -> new int[x]

Map

  1. map遍历

     itemsMap.forEach((k,v)->System.out.println("Item : " + k + " Count : " + v));

List

注意排序中的元素不能存在null值

  1. List排序

     // 原始版
     words.sort((Word first, Word second) -> first.getName().compareTo(second.getName()));
     // 精简版
     Collections.sort(words, Comparator.comparing(Word::getName));
     // 精简版,推荐使用这种
     words.sort(Comparator.comparing(Word::getName));
     // 多重排序(连个都升序)
     words.sort(Comparator.comparing(Word::getName).thenComparingInt(Word::getCountry));
     // 多重排序(第一个升,第二个降)
     words.sort(Comparator.comparing(Word::getName).reversed().thenComparingInt(Word::getCountry).reversed());
     ​
     // 排序默认是升序,降序其实就是多调用一下reversed()方法
     words.sort(Comparator.comparing(Word::getName).reversed());
  2. list遍历

     words.forEach(System.out::println);
  3. list转map(key去重)

     Map<String, Word> wordMapMap = wordList.stream().collect(Collectors.toMap(Word::getName, k -> k, (k1, k2) -> k1));
  4. list转map(key不能重复)

     Map<Integer,Word> userMap = wordList.stream().collect(Collectors.toMap(Word::getCountry, k -> k));
  5. list分组

     Map<String, List<Word>> groupMap = wordList.stream().collect(Collectors.groupingBy(Word::getName));
  6. list多重分组

     // 先按名称分组,再在名称分组的基础上按国家分组
     Map<String, Map<Integer, List<Word>>> map2 = words.stream().collect(Collectors.groupingBy(Word::getName,Collectors.groupingBy(Word::getCountry)));
  7. list匹配过滤

     // 过滤出名称等于tiger的元素
     List<Word> filterList = wordList.stream().filter(v -> v.getName().equals("tiger")).collect(Collectors.toList());
     // 打印出名称包含老子的元素
     wordList.stream().filter(v -> v.getName().contains("老")).forEach(System.out::println);
     // 过滤出国家编码大于2的元素
     List<Word> filterList = wordList.stream().filter(v -> v.getCountry() > 2).collect(Collectors.toList());
     // 过滤出国家编码等于1且名称包含tiger的元素
     Predicate<Word> equals1 = v -> v.getCountry().equals(1);
     Predicate<Word> contains1 = v -> v.getName().contains("tiger");
     List<Word> filterList = wordList.stream().filter(contains1.and(equals1)).collect(Collectors.toList());
     // 过滤出值大于25的元素
     List<Double> filteredCost = cost.stream().filter(x -> x > 25.0).collect(Collectors.toList());
  8. list统计求和

     int sum = wordList.stream().mapToInt(Word::getCountry).sum();
     double sum = words.stream().mapToDouble(Word::getCountry).sum();
  9. list分组统计个数

     按名称分组统计个数
     Map<String, Long> collectCnt = wordList.stream().collect(Collectors.groupingBy(Word::getName, Collectors.counting()));
  10. list统计分析

     // 
     Map<String, LongSummaryStatistics> map3 = words.stream().collect(Collectors.groupingBy(Word::getName,Collectors.summarizingLong(Word::getCountry)));
  11. list多重分组统计分析

     Map<String, Map<Integer, LongSummaryStatistics>> map3 = words.stream().collect(Collectors.groupingBy(Word::getName,Collectors.groupingBy(Word::getCountry,Collectors.summarizingLong(Word::getCountry))));
  12. list去重(需根据实际情况重写Word的equals与hashCode)

     List<Word> list1= list.stream().distinct().collect(Collectors.toList());
  13. list元素字符串拼装

     String result = words.stream().map(Word::getName).collect(Collectors.joining("," , "[" , "]"));
  14. list对象集合转属性集合

     ​
     List<String> result = words.stream().map(Word::getName).collect(Collectors.toList());
     // 转属性集合时顺便做下处理
     List<String> result = words.stream().map(y -> y.getName().concat(".jpg")).collect(Collectors.toList());
  15. list求交集

     List<String> intersection = list1.stream().filter(item -> list2.contains(item)).collect(Collectors.toList());
  16. list求差集

     List<String> reduce1 = list1.stream().filter(item -> !list2.contains(item)).collect(Collectors.toList());

数组

  1. 数组排序

     // 原始版
     Arrays.sort(people, (first, second) -> Integer.compare(first.length(),  second.length()));
     // 精简版
     Arrays.sort(people, Comparator.comparingInt(String::hashCode));
     ​
     // 数组降序
     Arrays.sort(people, (second, first) -> Integer.compare(first.length(), second.length()));
  2. 数组统计某元素个数

     long num = Arrays.stream(name).filter(x -> x.equals("tiger")).count();
  3. 数组去重过滤并转化成集合

     List<String> filterList = Arrays.stream(name).filter(x -> !x.equals("赵强")).collect(Collectors.toList());
  4. 数组过滤,并对元素加后缀并转集合

     List<String> filterList = Arrays.stream(name).filter(x -> !x.equals("tiger")).map(y -> y.concat(".jpg")).collect(Collectors.toList());
  5. 数组统计求和

     int num = Arrays.stream(arr).reduce(0, Integer::sum);
     double sum =  Arrays.asList(10.0, 20.0, 30.0).stream().map(x -> x + x * 0.05).reduce(Double::sum).get();
     double sum = Stream.of(10.0, 20.0, 30.0).map(x -> x + x * 0.05).reduce(Double::sum).get();
     int sum = Stream.of(1, 2, 3, 4, 5).map(x -> x + x * 5).reduce(Integer::sum).get();

求和

 BinaryOperator<Integer> add = Integer::sum;
 Integer x = add.apply(20, 30);

线程

 private static void lambdaRunnable() {
     int age = 20;
     Runnable r2 = () -> {
         System.out.println(age);
         System.out.println("Hello world two!"+age);
     };
     r2.run();
 }

 

流的筛选/切片/查找/匹配/映射/归约操作

1.先来两个概念:

  • 流(Stream):一个元素序列。位于包java.util.stream.Stream,注意这个序列是可以串行或并行处理的。有多种方式建立流,最常见的是从集合(Collection)对象获取,有序集合如List的流有序,Set的流则无序。

  • Lambda表达式:流式处理的绝佳搭档!什么是Lambda表达式?略。哪里可以用Lambda表达式?需要实现一个函数式接口(只定义了一个抽象函数的接口)的地方就可以使用Lambda表达式,代替匿名类方式。

2.流式处理特点:

  • 流水线:流操作可返回一个流,多个操作从而可形成一个链,

  • 内部迭代:使用Iterator/forEach显式迭代器为外部迭代,流的迭代是流内部完成的,只需声明,是内部迭代,

  • 一次使用:每个流只能消费一次,不能结束后又从头开始!

3.流的一般使用:

  • 建立流:创建一个Stream对象,如从一个数据源来执行一个查询;

  • 操作流:一个包含了各种操作的操作链;

  • 结束流:一个终端操作,形成一个结果集或值

  1. 筛选/切片:使用filter/skip/limit/distinct方法过滤

    // 创建流
    Stream<Fruit> fruitStream = fruitList.stream();
    // 过滤
    Stream<Fruit> filteredStream = fruitStream.filter(d -> "中国".equals(d.getOrigin()));
    // 去掉重复元素
    Stream<Fruit> distinctStream = filteredStream.distinct();
    // 打印流中元素,forEach是终端操作,如果这里使用了,则collect方法无法使用,即一个流只能消费一次
    // distinctStream.forEach(System.out::println);
    // 跳过1个元素,
    Stream<Fruit> skippedStream = distinctStream.skip(1);
    // 切片,参数为maxSize
    Stream<Fruit> limitStream = skippedStream.limit(4);
    // 结束,collect方法是收集器,如果这里使用了,则forEach无法使用,即一个流只能有一个终端操作
    List<Fruit> newList = limitStream.collect(Collectors.toList());
    // 打印结果,lambda方式
    newList.forEach(System.out::println);
    
    // 链式操作,和上面效果一样,一气呵成,真爽!
    List<Fruit> newList2 = fruitList.stream()
            .filter(d -> "中国".equals(d.getOrigin()))
            .distinct()
            .skip(1)
            .limit(4)
            .collect(Collectors.toList());
    // 打印结果集
    newList2.forEach(System.out::println);
  2. 映射:对流中的每个元素应用映射函数,变换成新的对象

    // 创建流
    Stream<Fruit> fruitStream = fruitList.stream();
    //转换,变为String流
    Stream<String> stringStream = fruitStream.map(Fruit::getName);
    //过滤,名称以A开头
    Stream<String> filteredStream = stringStream.filter(str -> "A".equals(String.valueOf(str.charAt(0))));
    //终端操作,set自动去重复
    Set<String> stringSet = filteredStream.collect(Collectors.toSet());
    //打印结果集
    stringSet.forEach(System.out::println);
    
    //链式语法实现,请君想象下JDK7的实现,
    fruitList.stream()
          .map(Fruit::getName)
          .filter(str -> "A".equals(str.substring(0,1)))
          .collect(Collectors.toSet())
          .forEach(System.out::println);
  3. 查找/匹配:StreamAPI通过allMatch,anyMatch,noneMatch,findFirst,findAny方法找到符合的元素

    // 注意这里每个都要重建一个流
    // 是否全部价格大于50
    boolean almach = fruitList.stream().allMatch(fruit -> fruit.getPrice() > 50);
    // 是否至少有一种产自America
    boolean anyMatch = fruitList.stream().anyMatch(fruit -> "America".equals(fruit.getOrigin()));
    // 找出流中第3个,
    Optional<Fruit> thirdOne = fruitList.stream().skip(2).findFirst();
    // 存在则打印,防止NPE
    thirdOne.ifPresent(System.out::println);
    // 找出流中任意一个,,
    Optional<Fruit> anyOne = fruitList.stream().findAny();
    // ifPresent,值存在则执行操作,否则 do nothing!
    anyOne.ifPresent(System.out::println);
  4. 归约:使用reduce对流中元素累积计算,最后得到一个值

     // 注意这里每个都要重建一个流
     // reduce求和
     int totalPrice = fruitList.stream()
             .filter(fruit -> "Japan".equals(fruit.getOrigin()))
             // 映射转换为Integer流
             .map(Fruit::getPrice)
             // reduce归约计算
             // 也可使用reduce(0,(a,b) -> a+b);
             .reduce(0,Integer::sum);
     totalPrice.ifPresent(System.out::println);
     ​
     // reduce计算最大
     Optional<Integer> maxPrice = fruitList.stream()
             .map(Fruit::getPrice)
             // 归约计算最大值:
             // 这里也可以使用reduce((x,y) -> x>y?x:y)
             .reduce(Integer::max);
     // ifPresent,值存在则执行操作,否则 do nothing!
     maxPrice.ifPresent(System.out::println);
     ​
     // reduce计算最小值
     Optional<Integer> minPrice = fruitList.stream()
             .map(Fruit::getPrice)
             // 归约计算最小值:也可以使用reduce((x,y) -> x<y?x:y)
             .reduce(Integer::min);
     // ifPresent,值存在则执行操作,否则 do nothing!
     minPrice.ifPresent(System.out::println);
  5.  

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ljt-tiger

thanks

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值