Java-Function函数式编程-入门

简介: Java-Function函数式编程-入门

Function函数介绍
我们在没深入了解Function函数式相关接口之前,可能只是在使用Stream流处理时,用过它的相关接口。有些同学也就止步于此,并没有深入了解过它的设计理念。
Function中文接口文档
Stream接口文档

对于Stream流大家常用的方法有哪些?

  1. filter(Predicate<? super T> predicate)// 条件筛选
  2. map(Function<? super T, ? extends R> mapper)// 对单个item对象转换操作
  3. flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)// 对item对象操作,并返回一个新的Stream流
  4. forEach(Consumer<? super T> action)// 循环遍历
  5. anyMatch(Predicate<? super T> predicate)// 条件筛选,整个集合item有一个为true
  6. allMatch(Predicate<? super T> predicate)// 条件筛选,全部item为true
  7. reduce(BinaryOperator accumulator);// 累计计算,值累加等
  8. collect(Collector<? super T, A, R> collector);// 集合操作,元素汇总转换计算
  9. 看着这些常用方法,入参都是Function相关接口函数

Function常用函数详解

Predicate函数

Predicate函数

传入一个参数,返回一个boolean值的函数,例如filter方法。
// strList是一个List. filter方法需要传入Predicate函数方法.
// 获取集合数量,并且集合不存在null字符串
long count1 = strList.stream().filter(item -> StringUtils.hasLength(item))
.count();
// 简写
long count2 = strList.stream().filter(StringUtils::hasLength).count();
// 自定义方法,理论上我们只要是一个 传入一个String类型参数并返回一个boolean参数的方法。都可以放入filter方法
long count3 = strList.stream().filter(item -> customHasLength(item)).count()
// 简写
long count4 = strList.stream().filter(FunctionDemoApplication::customHasLength).count();

/**

  • 自定义方法,字符串不为null或空字符串
    */
    public static boolean customHasLength(String str){
    return StringUtils.hasLength(str);
    }

Function函数
传入一个参数,返回一个值的函数。例如map方法。

public static void main(String[] args) {
List planList = new ArrayList<>(Collections.emptyList());
planList.add(new Plan(1L,"SUCCEED"));
planList.add(new Plan(2L,"FAIL"));

// map方法入参,需要传入一个Function函数。item -> item.getPlanNo())写法属于
// Function函数规范。item表示入参,item.getPlanNo()表示返参
Set<Long> planNoList1 = planList.stream().map(item -> item.getPlanNo()).collect(Collectors.toSet());
// 简写
Set<Long> planNoList2 = planList.stream().map(Plan::getPlanNo).collect(Collectors.toSet());

}

static class Plan{
private Long planNo;
private String planStatus;

public Plan(Long planNo, String planStatus){
    this.planNo = planNo;
    this.planStatus = planStatus;
}

public Long getPlanNo() {
    return planNo;
}
public Plan setPlanNo(Long planNo) {
    this.planNo = planNo;
    return this;
}
public String getPlanStatus() {
    return planStatus;
}
public Plan setPlanStatus(String planStatus) {
    this.planStatus = planStatus;
    return this;
}

}
Consumer函数
这是一个传入一个参数,无返回值的函数。例如forEach方法。

public static void main(String[] args) {
List planList = new ArrayList<>();
planList.add(new Plan(1L,"SUCCEED"));
planList.add(new Plan(2L,"FAIL"));
planList.add(new Plan(3L,"SUCCEED"));

List<Long> planNo = new ArrayList<>();
planList.stream()
        .filter(plan -> "SUCCEED".equals(plan.getPlanStatus()))
        // forEarch方法入参,需要传入一个Consumer函数。plan -> planNo.add(plan.getPlanNo())符合函数规范。 plan表示入参。
        .forEach(plan -> planNo.add(plan.getPlanNo()));
System.out.println("count:" + planNo.size());

}
BiFunction函数
与Function区别在于,BiFunction允许传入2个参数,返回一个值。

BiConsumer函数
与Consumer函数区别在于,BiConsumer函数允许传入2个参数,无返回值。

BinaryOperator函数
这是BiFunction的一个子接口,BiFunction可以传入2个参数,返回一个值。BinaryOperator则是传入的2个参数和返回的值类型必须一致,所以用在reduce函数方法入参时,就可以用来进行值累加的操作。例如传入BigDecimal::add,Long::sum,甚至于BigDecimal::max,用来获取最大值。

总结一句话,Function函数作为方法入参,核心原因就是把具体业务逻辑交由外层处理。使方法只处理核心逻辑,从而减少业务逻辑对方法的侵入性,使代码更加简洁优雅,易于维护。
例如map(Function<? super T, ? extends R> mapper)方法,就是把集合中单个item对象的处理逻辑交由外部逻辑处理。 map方法内只需获取结果进行核心逻辑处理。
image.png

再例如filter(Predicate<? super T> predicate)方法,把具体校验逻辑交由外部处理,filter方法内只需获取结果进行核心逻辑处理。
image.png

实际场景Function函数应用
当我了解Stream对Function的函数运用后,我佩服这些源码编写大佬的思路与才华。所以我认为核心是需要学习他们的编码设计思路,在日常编写代码中,真的碰到了类似场景,就可以想起并运用这套思想去设计代码,使得我们代码更加优雅,简洁高效。这也是我们学习源码的初衷。

例如有这样一个场景,我们对接了很多支付渠道,每家对接口参数的加密方式不同。我们可以针对支付渠道设计一个抽象类。在抽象类中定义一个签名方法。具体不同渠道的签名规则以Function函数传入。

抽象类中公共签名方法

/**

  • 排序并签名
    *
  • @param params 要签名参数
  • @param append 待签名字符串追加内容
  • @param signName 签名参数
  • @param signer 签名函数
  • @return 最终签名
    */
    protected final String sign(Map params,

                         String append,
                         String signName,
                         Function<String, String> signer) {
    

    String signStr = params.keySet().stream()

         .filter(key -> StringUtils.hasLength(key)
                 && !key.equals(signName)
                 && StringUtils.hasLength(params.get(key)))
         .sorted()
         .map(key -> key + "=" + params.get(key))
         .collect(Collectors.joining("&"));
    

    signStr += append;

    if (logger.isDebugEnabled()) logger.debug("待签名字符串:{}", signStr);
    return signer.apply(signStr);
    }

/**

  • md5 大写加密
    */
    protected final String md5Upper(String signStr) {
    return md5Origin(signStr).toUpperCase();
    }

/**

  • md5 加密
    */
    protected final String md5Origin(String signStr) {
    return DigestUtils.md5Hex(signStr);
    }
    具体支付渠道进行签名调用

// 调用抽象类中的sign签名方法
String sign = sign(params, "&key=" + "私钥字符串", "sign"
// 这里不同渠道类中也可自定义加密规则
, this::md5Origin);

// 另外一种写法
String sign2 = sign(params, "&key=" + "私钥字符串", "sign"
, (signStr) -> DigestUtils.md5Hex(signStr));

类似的场景其实有很多,在很多源码使用上,都会把业务逻辑通过函数式入参,交由你来处理。使得源码方法的公用性会更强,代码更加简洁易于维护。
以上便是我对于Function函数入门的介绍,如果要更加深入的了解与运用,需要对源码贡献者的编程思路达成共鸣,才能一劳永逸。最后愿你我的头发茂盛。
End.

相关文章
|
8天前
|
Java API 容器
Java 8中的函数式编程特性
【5月更文挑战第28天】 本文将深入探讨Java 8中引入的函数式编程特性,包括Lambda表达式、Stream API和Optional类。我们将通过实例和代码示例来展示这些特性如何简化代码、提高可读性和性能。我们还将讨论一些常见的使用场景和最佳实践,以帮助您更好地利用Java 8的函数式编程特性。
|
6天前
|
监控 Java 测试技术
性能工具之Java分析工具BTrace入门
【5月更文挑战第25天】性能工具之Java分析工具BTrace入门
16 2
|
7天前
|
Java 程序员 API
Java 8新特性之函数式编程实践
【5月更文挑战第29天】本文将深入探讨Java 8引入的函数式编程特性,重点解析Lambda表达式、Stream API以及Optional类的应用。我们将通过实例演示如何利用这些工具简化代码,提高程序的可读性和效率。文章不仅涉及理论知识,更注重实战技巧,旨在帮助开发者掌握并有效应用Java 8的函数式编程特性。
14 0
|
9天前
|
Java 编译器
<JAVA> java入门面向0基础教程(数据类型,运算符)
<JAVA> java入门面向0基础教程(数据类型,运算符)
18 1
<JAVA> java入门面向0基础教程(数据类型,运算符)
|
10天前
|
Oracle Java 程序员
java基础篇-java入门认知
# Day01 —— Java基础入门概览 本文介绍了Java语言的背景知识、快速入门、开发工具以及基础语法。Java由Sun公司(现属Oracle)开发,创始人是詹姆斯·高斯林。Java可应用于桌面应用、企业级应用、移动应用、服务器系统和大数据开发等多个领域。Java技术体系包括Java SE(标准版)、Java EE(企业版)和Java ME(小型版)。 在开始编程前,需安装JDK,通过`javac`和`java`命令进行编译和运行。Java程序的执行依赖于Java虚拟机(JVM),实现跨平台运行。IDEA是常用的Java集成开发环境,提供代码提示、错误检查等功能,提高开发效率。
|
11天前
|
存储 Java 开发者
探索Java编程的奥秘:从入门到实践
本文是关于Java编程的简介,首先介绍了Java作为广泛应用的编程语言对初学者和专业人士的吸引力。接着,讲解了Java的基础概念,包括数据类型(如基本和引用类型)和变量,以及运算符和表达式。文章还提到了控制流语句,如条件语句和循环语句,用于控制程序执行流程。然后,转向面向对象编程,阐述了类与对象的概念,以及封装和继承的重要性。最后,简述了Java在Web开发、移动应用和桌面应用等领域的实际应用,并给出一个使用Swing创建简单GUI的示例。
|
12天前
|
前端开发 JavaScript Java
JAVA Web开发入门与实战
本文引导读者入门JAVA Web开发,介绍了Web开发的基本概念,如Servlet、JSP和JavaBean,并详细阐述了JAVA Web开发环境的搭建。文章通过一个在线书店系统的实战项目,展示了从需求分析、数据库设计到前后端开发的全过程,涵盖Servlet处理请求、JSP动态生成页面及表单添加书籍功能。最后,文章提及了进阶技术,如框架使用、前端集成和安全性考虑,鼓励读者深入探索JAVA Web开发的广阔世界。
|
19天前
|
移动开发 搜索推荐 Java
Java如何支持函数式编程?,作为移动开发程序员应该怎样去规划自己的学习路线
Java如何支持函数式编程?,作为移动开发程序员应该怎样去规划自己的学习路线
|
19天前
|
算法 Java C++
刷题两个月,从入门到字节跳动offer丨GitHub标星16k+,美团Java面试题
刷题两个月,从入门到字节跳动offer丨GitHub标星16k+,美团Java面试题
|
20天前
|
算法 Java Python
保姆级Java入门练习教程,附代码讲解,小白零基础入门必备
保姆级Java入门练习教程,附代码讲解,小白零基础入门必备