news 2026/3/27 16:54:34

函数式编程学习(Java)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
函数式编程学习(Java)

一、函数式接口

函数式接口是 Lambda 表达式和方法引用的容器,是整个 Java 函数式编程的基础,所有 Lambda 最终都要绑定到某个函数式接口的抽象方法上。

1. 核心定义

仅包含一个抽象方法的接口(可包含多个默认方法、静态方法、私有方法),推荐用@FunctionalInterface注解标记(编译器会强制校验是否符合规范)。

2. 核心价值

将「行为(方法逻辑)」抽象为接口类型,让行为可以像变量一样被传递、赋值、作为方法参数/返回值。

3. 常用内置函数式接口(java.util.function 包)

接口类型核心方法入参/返回值典型用途
消费型 Consumervoid accept(T t)入参 T,无返回遍历集合、打印数据
供给型 SupplierT get()无入参,返回 T生成随机数、创建对象
函数型 Function<T,R>R apply(T t)入参 T,返回 R数据转换(如字符串转数字)
断言型 Predicateboolean test(T t)入参 T,返回布尔过滤集合、条件判断
二元函数 BiFunction<T,U,R>R apply(T t, U u)入参 T+U,返回 R双参数转换(如两数运算)

4. 基础示例(自定义+使用)

// 自定义函数式接口(单一抽象方法)@FunctionalInterfaceinterfaceMyFunction{Stringprocess(Strings);// 唯一抽象方法}publicclassFunctionalInterfaceDemo{publicstaticvoidmain(String[]args){// 给函数式接口赋值(后续用Lambda实现)MyFunctionupperCase=s->s.toUpperCase();MyFunctionaddSuffix=s->s+"_suffix";// 调用抽象方法执行逻辑System.out.println(upperCase.process("hello"));// HELLOSystem.out.println(addSuffix.process("test"));// test_suffix}}

二、Lambda 表达式

Lambda 是函数式接口的简洁实例化方式,替代冗长的匿名内部类,本质是「一段可传递的代码块」。

1. 核心语法

(参数列表)->{方法体}
简化规则(核心!减少冗余)
场景简化写法原始写法
单参数s -> s.toUpperCase()(String s) -> { return s.toUpperCase(); }
无参数() -> Math.random()() -> { return Math.random(); }
单语句方法体(a, b) -> a + b(int a, int b) -> { return a + b; }
多语句方法体(a, b) -> { int c = a*2; return c + b; }必须带大括号和return

2. 使用场景:绑定函数式接口

Lambda 不能单独存在,必须绑定到「函数式接口的抽象方法」,常见场景:

场景1:赋值给函数式接口变量
// 绑定Consumer接口Consumer<String>print=s->System.out.println(s);print.accept("Lambda赋值示例");// 输出:Lambda赋值示例// 绑定Predicate接口Predicate<Integer>isOdd=num->num%2!=0;System.out.println(isOdd.test(5));// 输出:true
场景2:作为方法参数(行为参数化)
// 自定义方法:接收函数式接口参数publicstatic<T>List<T>filter(List<T>list,Predicate<T>condition){List<T>result=newArrayList<>();for(Tt:list){if(condition.test(t)){result.add(t);}}returnresult;}// 调用:传入Lambda作为过滤条件publicstaticvoidmain(String[]args){List<Integer>nums=Arrays.asList(1,2,3,4,5);// 过滤偶数List<Integer>evens=filter(nums,num->num%2==0);System.out.println(evens);// 输出:[2,4]}

3. 关键注意点

  • Lambda 可捕获外部变量,但变量必须是final或「有效 final」(未显式声明 final,但从未重新赋值);
  • Lambda 没有自己的thisthis指向外部类的对象;
  • 编译期会将 Lambda 转换为函数式接口的匿名实现类(运行期优化为 invokedynamic 指令)。

三、方法引用

方法引用是 Lambda 的简化写法,当 Lambda 体仅调用一个已有方法时,可用「方法引用」替代,让代码更简洁。

1. 语法格式

方法引用类型语法等效 Lambda 示例
静态方法引用类名::静态方法名Integer::sum(a,b) -> Integer.sum(a,b)
实例方法引用(对象)对象名::实例方法名str::toUpperCase() -> str.toUpperCase()
实例方法引用(类)类名::实例方法名String::lengths -> s.length()
构造器引用类名::newArrayList::new() -> new ArrayList<>()

2. 实战示例

publicclassMethodReferenceDemo{publicstaticvoidmain(String[]args){// 1. 静态方法引用:Integer::sumBinaryOperator<Integer>sum=Integer::sum;System.out.println(sum.apply(10,20));// 30// 2. 实例方法引用(对象):自定义字符串对象的toUpperCaseStringstr="hello";Supplier<String>upperCase=str::toUpperCase;System.out.println(upperCase.get());// HELLO// 3. 实例方法引用(类):String::lengthFunction<String,Integer>strLength=String::length;System.out.println(strLength.apply("test"));// 4// 4. 构造器引用:ArrayList::newSupplier<List<String>>listSupplier=ArrayList::new;List<String>list=listSupplier.get();list.add("a");System.out.println(list);// [a]}}

3. 使用技巧

  • 方法引用的参数列表、返回值必须和绑定的函数式接口抽象方法完全匹配
  • 优先使用方法引用替代简单 Lambda,提升代码可读性(如 Stream 操作中)。

四、Stream 流(函数式集合操作)

Stream 是 Java 提供的「函数式集合处理工具」,基于 Lambda 和函数式接口实现,支持「管道式」数据处理,替代传统的 for 循环,核心是「声明式编程」(关注做什么,而非怎么做)。

1. Stream 核心特性

  • 不存储数据:仅处理数据源(集合、数组等),不修改原数据;
  • 惰性求值:中间操作(如 filter、map)仅记录逻辑,终端操作(如 forEach、collect)才触发计算;
  • 可并行:通过parallelStream()实现并行处理,简化多线程编程;
  • 一次性:流只能被消费一次,再次使用需重新创建。

2. 核心操作分类

操作类型常用方法特点
中间操作filter、map、distinct、sorted、limit返回 Stream,可链式调用,惰性执行
终端操作forEach、collect、reduce、count、anyMatch返回非 Stream 结果,触发计算

3. 实战示例(核心场景)

importjava.util.Arrays;importjava.util.List;importjava.util.Map;importjava.util.stream.Collectors;publicclassStreamDemo{// 定义测试实体类staticclassUser{privateStringname;privateintage;privateStringcity;publicUser(Stringname,intage,Stringcity){this.name=name;this.age=age;this.city=city;}// 省略getter/setterpublicStringgetName(){returnname;}publicintgetAge(){returnage;}publicStringgetCity(){returncity;}}publicstaticvoidmain(String[]args){List<User>users=Arrays.asList(newUser("Alice",22,"Beijing"),newUser("Bob",28,"Shanghai"),newUser("Charlie",22,"Beijing"),newUser("David",30,"Shanghai"));// 场景1:过滤+映射 → 获取北京22岁用户的姓名List<String>names=users.stream().filter(u->u.getAge()==22&&"Beijing".equals(u.getCity()))// 中间操作.map(User::getName)// 方法引用简化Lambda.collect(Collectors.toList());// 终端操作System.out.println(names);// [Alice, Charlie]// 场景2:分组 → 按城市分组用户Map<String,List<User>>groupByCity=users.stream().collect(Collectors.groupingBy(User::getCity));System.out.println(groupByCity);// {Beijing=[Alice, Charlie], Shanghai=[Bob, David]}// 场景3:归约 → 计算所有用户的年龄总和inttotalAge=users.stream().mapToInt(User::getAge)// 避免装箱,提升性能.sum();// 终端操作System.out.println(totalAge);// 102// 场景4:并行流 → 大数据量处理(自动多线程)longcount=users.parallelStream().filter(u->u.getAge()>25).count();System.out.println(count);// 2}}

4. 高频技巧

  • 基本类型流(IntStream/LongStream/DoubleStream):避免自动装箱/拆箱,提升性能;
  • Optional结合 Stream:处理可能为空的结果(如findFirst()返回Optional<User>);
  • collect()是最灵活的终端操作:支持转集合、分组、拼接字符串(Collectors.joining())等。

五、核心总结

  1. 函数式接口是基础:定义了「行为的类型」,是 Lambda 和方法引用的「载体」;
  2. Lambda 表达式是函数式接口的「简洁实现」:替代匿名内部类,直接表达行为逻辑;
  3. 方法引用简化Lambda :进一步简化仅调用单个方法的 Lambda;
  4. Stream 流是函数式接口+Lambda 的「实战场景」:通过接收函数式接口参数(如 filter 接收 Predicate),实现声明式集合处理。

六、避坑

  1. Stream 不要滥用:小数据量场景下,传统 for 循环可能比 Stream 更快(无线程开销);
  2. Lambda 不要写太复杂:复杂逻辑拆分为方法,用方法引用替代,提升可读性;
  3. 并行流注意线程安全:数据源若为线程不安全的集合(如 ArrayList),并行流处理时需注意;
  4. 函数式接口必须满足单一抽象方法:用@FunctionalInterface注解强制校验,避免后续误加抽象方法。

实战练习

需求:从员工列表中筛选出「部门为研发、年龄>30岁」的员工,按薪资降序排序,最终获取他们的姓名和薪资(格式:姓名-薪资),拼接成字符串。

// 自行实现以下逻辑,检验掌握程度List<Employee>employees=// 初始化员工列表Stringresult=employees.stream().filter(/* 研发部门+年龄>30 */).sorted(/* 薪资降序 */).map(/* 转换为 姓名-薪资 字符串 */).collect(/* 拼接为逗号分隔的字符串 */);

(参考答案:

Stringresult=employees.stream().filter(e->"研发".equals(e.getDept())&&e.getAge()>30).sorted((e1,e2)->Double.compare(e2.getSalary(),e1.getSalary())).map(e->e.getName()+"-"+e.getSalary()).collect(Collectors.joining(","));

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/25 11:37:32

openi启智社区提供大模型在线体验功能

openi启智社区提供大模型在线体验功能&#xff0c;可以根据自己的任务场景选择合适的模型和计算资源&#xff0c;创建模型在线体验任务&#xff0c;从而在线检验模型的反应效果。 网址&#xff1a;OpenI - 启智AI开源社区提供普惠算力&#xff01; 有很多模型可以选 每个账户…

作者头像 李华
网站建设 2026/3/25 7:10:38

xcode也有了自己独有的Ai本地大语言模型支持了

开启这个功能&#xff0c;就会提示需要下载一个2G的本地大语言模型&#xff0c;下载完成后重启xcode&#xff0c;写代码就会有提示。比如下面的示例&#xff1a;测试下来虽然没有 GitHub Copilot for Xcode 聪明&#xff0c;也没有 GitHub Copilot for Xcode响应块&#xff0c;…

作者头像 李华
网站建设 2026/3/25 6:46:41

ConcurrentHashMap从分段锁到CAS+synchronized

&#x1f942;(❁◡❁)您的点赞&#x1f44d;➕评论&#x1f4dd;➕收藏⭐➕关注&#x1f440;是作者创作的最大动力&#x1f91e; &#x1f496;&#x1f4d5;&#x1f389;&#x1f525; 支持我&#xff1a;点赞&#x1f44d;收藏⭐️留言&#x1f4dd;关注&#x1f440;欢迎…

作者头像 李华
网站建设 2026/3/26 11:37:02

“AI写的论文,参考文献靠谱吗?”-虎贲等考AI:所有参考文献都来自知网/维普可查

一、引言&#xff1a;AI 论文参考文献的信任危机与破局点随着人工智能写作工具在学术领域的普及&#xff0c;“AI 生成论文的参考文献是否靠谱” 成为科研工作者、学生群体关注的核心议题。部分早期 AI 工具因缺乏权威数据源支撑&#xff0c;曾出现参考文献虚假标注、链接失效、…

作者头像 李华
网站建设 2026/3/26 14:01:23

AI在软件测试中的理想与现实:一场尚未到来的革命

75%的企业将AI驱动测试视为2025年战略重点&#xff0c;但实际采用率仅为16% 引言&#xff1a;高期望与低落的现实 在人工智能席卷各行各业的今天&#xff0c;抛开软件开发&#xff0c;软件测试领域似乎也站在变革的风口浪尖。行业调查显示&#xff0c;超过75%的企业将AI驱动测…

作者头像 李华
网站建设 2026/3/26 18:06:45

项目实战04——机器学习赋能餐饮业(含代码、数据)

机器学习在餐饮企业中的应用方向 机器学习技术可帮助餐饮企业优化运营、提升顾客体验并增加利润。常见应用包括需求预测、菜品推荐、动态定价、库存管理、顾客细分等。通过分析历史销售数据、天气、节假日等因素,预测未来需求,减少浪费并提高备货效率。 1. 餐饮企业现状与需…

作者头像 李华