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.

相关文章
|
13天前
|
安全 Java 数据库连接
2025 年最新 Java 学习路线图含实操指南助你高效入门 Java 编程掌握核心技能
2025年最新Java学习路线图,涵盖基础环境搭建、核心特性(如密封类、虚拟线程)、模块化开发、响应式编程、主流框架(Spring Boot 3、Spring Security 6)、数据库操作(JPA + Hibernate 6)及微服务实战,助你掌握企业级开发技能。
130 3
|
22天前
|
前端开发 Java 数据库
Java 项目实战从入门到精通 :Java Web 在线商城项目开发指南
本文介绍了一个基于Java Web的在线商城项目,涵盖技术方案与应用实例。项目采用Spring、Spring MVC和MyBatis框架,结合MySQL数据库,实现商品展示、购物车、用户注册登录等核心功能。通过Spring Boot快速搭建项目结构,使用JPA进行数据持久化,并通过Thymeleaf模板展示页面。项目结构清晰,适合Java Web初学者学习与拓展。
138 1
|
16天前
|
算法 Java 测试技术
零基础学 Java: 从语法入门到企业级项目实战的详细学习路线解析
本文为零基础学习者提供完整的Java学习路线,涵盖语法基础、面向对象编程、数据结构与算法、多线程、JVM原理、Spring框架、Spring Boot及项目实战,助你从入门到进阶,系统掌握Java编程技能,提升实战开发能力。
58 0
|
2月前
|
存储 缓存 NoSQL
java 集合入门基础理论的核心概念与实用长尾知识
本文介绍了Java集合框架的基础理论知识,包括单列集合(List、Set、Queue)和双列集合(Map)的特点及常用实现类(如ArrayList、HashSet、HashMap等)。详细讲解了集合的遍历方式(迭代器、增强for循环、Lambda表达式)和典型应用场景(如数据去重、键值存储等)。通过具体代码示例,帮助初学者理解集合框架的核心概念和实际应用,为Java编程中的数据存储与管理提供基础指导。
69 0
|
2月前
|
缓存 NoSQL Java
Java Web 从入门到精通之苍穹外卖项目实战技巧
本项目为JavaWeb综合实战案例——苍穹外卖系统,涵盖Spring Boot 3、Spring Cloud Alibaba、Vue 3等主流技术栈,涉及用户认证、订单处理、Redis缓存、分布式事务、系统监控及Docker部署等核心功能,助你掌握企业级项目开发全流程。
228 0
|
2月前
|
存储 安全 Java
Java 学习路线 35 掌握 List 集合从入门到精通的 List 集合核心知识
本文详细解析Java中List集合的原理、常用实现类(如ArrayList、LinkedList)、核心方法及遍历方式,并结合数据去重、排序等实际应用场景,帮助开发者掌握List在不同业务场景下的高效使用,提升Java编程能力。
267 0
|
2月前
|
前端开发 Java API
基于 Spring Boot 3 与 React 的 Java 学生信息管理系统从入门到精通实操指南
本项目基于Spring Boot 3与React 18构建学生信息管理系统,涵盖前后端开发、容器化部署及测试监控,提供完整实操指南与源码,助你掌握Java全栈开发技能。
106 0
|
3月前
|
并行计算 Java API
Java 入门循环结构基础知识点详解
摘要:本文介绍了Java现代循环技术的进阶应用,包括Stream API、响应式编程和模式匹配,展示了如何用Stream API替代传统循环进行声明式集合处理(如过滤、映射和并行计算),以及响应式编程在异步非阻塞场景下的优势。文章还通过电商订单处理系统的案例演示了这些技术的综合应用,并提供了性能优化建议,如合理使用并行处理和避免循环内对象创建。这些现代特性使Java代码更简洁、高效,更适合高并发和I/O密集型场景。
46 1
|
3月前
|
Oracle Java 关系型数据库
java 入门学习视频_2025 最新 java 入门零基础学习视频教程
《Java 21 入门实操指南(2025年版)》提供了Java最新特性的开发指导。首先介绍了JDK 21和IntelliJ IDEA 2025.1的环境配置,包括环境变量设置和预览功能启用。重点讲解了Java 21三大核心特性:虚拟线程简化高并发编程,Record模式优化数据解构,字符串模板提升字符串拼接可读性。最后通过图书管理系统案例,展示如何运用Record定义实体类、使用Stream API进行数据操作,以及结合字符串模板实现控制台交互。该指南完整呈现了从环境搭建到实际项目开发的Java 21全流程实
102 1
|
2月前
|
存储 安全 Java
从基础语法到实战应用的 Java 入门必备知识全解析
本文介绍了Java入门必备知识,涵盖开发环境搭建、基础语法、面向对象编程、集合框架、异常处理、多线程和IO流等内容,结合实例帮助新手快速掌握Java核心概念与应用技巧。
58 0

热门文章

最新文章