完美使用Lambda表达式

完美使用Lambda表达式_第1张图片

一、​简介

Stream,就是JDK8又依托于函数式编程特性为集合类库做的一个类库,它其实就是jdk提供的函数式接口的最佳实践。它能让我们通过lambda表达式更简明扼要的以流水线的方式去处理集合内的数据,可以很轻松的完成诸如:过滤、分组、收集、归约这类操作。

二、操作API

Stream的操作大致分为两类

  • 中间型操作
  • 终结型操作

其中转换型操作又分为有状态和无状态两类。有状态是本次的结果需要依赖于前面的处理结果,而无状态则是不依赖。简单来讲就是无状态方法可以互相调换位置,而有状态方法不能调换位置。

中间型操作

中间型操作就是返回值依旧是stream类型的方法。api如下:

API 功能说明 无状态操作
filter() 按照条件过滤符合要求的元素, 返回新的stream流。         是
map() 将已有元素转换为另一个对象类型,一对一逻辑,返回新的stream流         是
peek() 对stream流中的每个元素进行逐个遍历处理,返回处理后的stream流         是
flatMap() 将已有元素转换为另一个对象类型,一对多逻辑,即原来一个元素对象可能会转换为1个或者多个新类型的元素,返回新的stream流         是
limit() 仅保留集合前面指定个数的元素,返回新的stream流         否
skip() 跳过集合前面指定个数的元素,返回新的stream流         否
concat() 将两个流的数据合并起来为1个新的流,返回新的stream流         否
distinct() 对Stream中所有元素进行去重,返回新的stream流         否
sorted() 对stream中所有的元素按照指定规则进行排序,返回新的stream流         否
takeWhile() JDK9新增,传入一个断言参数当第一次断言为false时停止,返回前面断言为true的元素。         否
dropWhile() JDK9新增,传入一个断言参数当第一次断言为false时停止,删除前面断言为true的元素。         否

终结型操作

终结型操作与中间型相反,返回值是非Stream类型的。api如下:

API 功能说明
count() 返回stream处理后最终的元素个数
max() 返回stream处理后的元素最大值
min() 返回stream处理后的元素最小值
findFirst() 找到第一个符合条件的元素时则终止流处理
findAny() 找到任何一个符合条件的元素时则退出流处理,这个对于串行流时与findFirst相同,对于并行流时比较高效,任何分片中找到都会终止后续计算逻辑
anyMatch() 返回一个boolean值,类似于isContains(),用于判断是否有符合条件的元素
allMatch() 返回一个boolean值,用于判断是否所有元素都符合条件
noneMatch() 返回一个boolean值, 用于判断是否所有元素都不符合条件
*collect() 将流转换为指定的类型,通过Collectors进行指定
*reduce() 将一个Stream中的所有元素反复结合起来,得到一个结果
toArray() 将流转换为数组
iterator() 将流转换为Iterator对象
foreach() 无返回值,对元素进行逐个遍历,然后执行给定的处理逻辑

三、语法

基本语法: (parameters) -> expression 或 (parameters) ->{ statements; }

Lambda表达式由三部分组成:

  1. paramaters:类似方法中的形参列表,这里的参数是函数式接口里的参数。这里的参数类型可以明确的声明也可不声明而由JVM隐含的推断。另外当只有一个推断类型时可以省略掉圆括号。
  2. ->:可理解为“被用于”的意思
  3. 方法体:可以是表达式也可以代码块,是函数式接口里方法的实现。代码块可返回一个值或者什么都不反回,这里的代码块块等同于方法的方法体。如果是表达式,也可以返回一个值或者什么都不反回。

四、优缺点

Lambda表达式的优点很明显,在代码层次上来说,使代码变得非常的简洁。缺点也很明显,代码不易读。

五、基本使用

新建实体对象SysUser 并初始化。

/**
 * @author hope
 * @date 2023年08月22日 16:10
 */
@Data
@Accessors(chain = true)
public class SysUser {
​
  private Long id;
​
  private String name;
​
  private Integer age;
​
  private BigDecimal amount = BigDecimal.ZERO;
​
  public SysUser(Long id, String name, Integer age, BigDecimal amount) {
    this.id = id;
    this.name = name;
    this.age = age;
    this.amount = amount;
  }
}
List userList = new ArrayList<>();
userList.add(new SysUser(10000L, "zhangsan", 18, new BigDecimal("200")));
userList.add(new SysUser(20000L, "lisi", 27, new BigDecimal("180")));
userList.add(new SysUser(30000L, "wangwu", 26, new BigDecimal("210")));

1. list转map

/**
  *  list 转 Map
  *  使用Collectors.toMap的时候,如果有可以重复会报错,所以需要加(k1, k2) -> k1
  *  (k1, k2) -> k1 表示,如果有重复的key,则保留第一个,舍弃第二个
  */
  Map userMap2 = userList.stream().collect(Collectors.toMap(SysUser::getId, userInfo -> userInfo, (k1, k2) -> k1));

2. filter()过滤

从数组集合中,过滤掉不符合条件的元素,留下符合条件的元素。

/**
  * filter 过滤,查询出超过18岁且金额大于100的用户
  */
  List userResultList = userList.stream().filter(user -> user.getAge() > 18 && user.getAmount().compareTo(new BigDecimal("100"))==1).collect(Collectors.toList());

3. foreach遍历

foreach 遍历list,遍历map。

/**
 * 遍历
 */
userList.stream().forEach(sysUser -> System.out.println(sysUser.getName()));

4. groupingBy分组

使用Java8的groupingBy分组器:

/**
  *  分组
  */
  Map> userMap = userList.stream().collect(Collectors.groupingBy(SysUser::getId));

5. sorted+Comparator 排序

/**
 *  sorted + Comparator.comparing 排序列表,
 */
userList = userList.stream().sorted(Comparator.comparing(SysUser::getAge)).collect(Collectors.toList());
​
​
/**
 * 降序排序,则可以使用加reversed()
 */
userList = userList.stream().sorted(Comparator.comparing(SysUser::getAge).reversed()).collect(Collectors.toList());

6.distinct去重

distinct可以去除重复的元素

/**
 *  distinct去重
 */
userList = userList.stream().distinct().collect(Collectors.toList());

7. findFirst 返回第一个

/**
 *  获取第一个对象
 */
Optional optional = userList.stream().findFirst();
SysUser user = optional.get();

8. anyMatch是否至少匹配一个元素

anyMatch 检查流是否包含至少一个满足给定谓词的元素。

/**
 *  是否匹配
 */
Boolean b = userList.stream().anyMatch(user->user.getAge()>18);

9. allMatch 匹配所有元素

allMatch 检查流是否所有都满足给定谓词的元素。

/**
 *  匹配所有元素
 */
Boolean b = userList.stream().allMatch(user->user.getAge()>18);

10. map转换

/**
 *  map转换
 */
List ret = userList.stream().map(SysUser::getAmount).collect(Collectors.toList());

11. Reduce

Reduce可以合并流的元素,并生成一个值

/**
 *  reduce求和
 */
BigDecimal money = userList.stream().map(SysUser::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
​
Optional num = userList.stream().map(SysUser::getAge).reduce(Integer::sum);
​
int sum = Stream.of(10, 20, 30, 40).reduce(0, (a, b) -> a + b);

12. peek 打印个日志

peek()方法是一个中间Stream操作,使用peek来打印日志。

/**
 *  peek打印日志
 */
userList = userList.stream().filter(u -> u.getAge() > 18).peek(p-> System.out.println("年轻人:" + p.getName())).collect(Collectors.toList());

13. Max,Min最大最小

使用lambda流求最大,最小值。

/**
 *  Max-最大值
 */
Optional optional = userList.stream().max(Comparator.comparingInt(SysUser::getAge));
System.out.println(optional.get().getAge()); // 27
​
/**
 *  Min-最小值
 */
Optional optional2 = userList.stream().min(Comparator.comparingInt(SysUser::getAge));
System.out.println(optional2.get().getAge()); // 18

14. count统计

count()获取流数据元素总数。

/**
 *  count统计
 */
long count = userList.stream().filter(u -> u.getAge() > 18).count();

15. 常用函数式接口

  • Function(转换型): 接受一个输入参数,返回一个结果

  • Consumer (消费型): 接收一个输入参数,并且无返回操作

  • Predicate (判断型): 接收一个输入参数,并且返回布尔值结果

  • Supplier (供给型): 无参数,返回结果

Function 是一个功能转换型的接口,可以把将一种类型的数据转化为另外一种类型的数据:

/**
 *  获取每个字符串的长度,并且返回
 */
Function function = String::length;
Stream stream = Stream.of("zhangsan", "lisi", "wangwu");
Stream resultStream = stream.map(function);
resultStream.forEach(System.out::println);

Consumer是一个消费性接口,通过传入参数,并且无返回的操作:

/**
 *  通过传入参数,并且无返回的操作
 */
Consumer comsumer = System.out::println;
Stream stream = Stream.of("zhangsan", "lisi", "wangwu");
stream.forEach(comsumer);

Predicate是一个判断型接口,并且返回布尔值结果:

/**
 *  判断并且返回布尔值结果
 */
Predicate predicate = a -> a > 18;
SysUser userInfo = new SysUser(40000L, "wangwu", 25, new BigDecimal("150"));
System.out.println(predicate.test(userInfo.getAge())); // true

Supplier是一个供给型接口,无参数,有返回结果。

Supplier supplier = () -> Integer.valueOf("888888");
System.out.println(supplier.get());

六、结语

Java 8最大的特性就是引入Lambda表达式,即函数式编程。日常开发中,我们很多时候需要用到Java 8的Lambda表达式,它允许把函数作为一个方法的参数,让我们的代码更优雅、更简洁。

完美使用Lambda表达式_第2张图片

你可能感兴趣的:(Java,java)