java函数式编程
·
Java函数式编程:四大核心函数式接口超详细讲解
一、前言
Java 8 最重要的新特性之一就是函数式编程,而函数式编程的底层根基就是函数式接口。
只要吃透 4大核心函数式接口 + 2个高频扩展接口,就能彻底玩转 Lambda 表达式、Stream 流式编程、方法引用,日常开发和面试完全够用。
函数式接口定义:有且仅有一个抽象方法的接口,可使用
@FunctionalInterface注解标识,支持 Lambda 表达式简化实现。
二、Java 四大核心函数式接口总览
| 接口名 | 核心作用 | 抽象方法 | 记忆口诀 |
|---|---|---|---|
Supplier<T> |
生产者:无参,只返回结果 | T get() |
只产出、不接收 |
Consumer<T> |
消费者:有参,无返回值 | void accept(T t) |
只处理、不返回 |
Function<T, R> |
转换器:入参T,出参R | R apply(T t) |
进T出R、做转换 |
Predicate<T> |
断言判断:入参,返回布尔值 | boolean test(T t) |
做判断、返真假 |
三、四大核心接口逐类详解
3.1 Supplier<T> 生产者接口
3.1.1 核心特性
无入参、有返回值,只负责生产对象、生产数据。
3.1.2 常用场景
- 懒加载对象,延迟初始化
- 生成随机自定义对象
- 提供默认值
3.1.3 前置实体类
class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() { return name; }
public int getAge() { return age; }
@Override
public String toString() {
return name + "-" + age;
}
}
3.1.4 案例1:生成随机User对象
import java.util.function.Supplier;
public class SupplierDemo {
public static void main(String[] args) {
Supplier<User> userSupplier = () ->
new User("用户" + (int)(Math.random()*100), 18 + (int)(Math.random()*10));
System.out.println(userSupplier.get());
System.out.println(userSupplier.get());
}
}
3.1.5 案例2:懒加载集合对象
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
public class SupplierLazyDemo {
private static final Supplier<Map<String, Object>> mapSupplier = HashMap::new;
public static void main(String[] args) {
Map<String, Object> dataMap = mapSupplier.get();
dataMap.put("name", "张三");
dataMap.put("age", 22);
System.out.println(dataMap);
}
}
3.2 Consumer<T> 消费者接口
3.2.1 核心特性
- 有入参、无返回值,只负责消费、处理数据。
- 独有默认方法:
andThen(),支持链式拼接多个处理逻辑。
3.2.2 常用场景
- 集合遍历打印
- 批量修改对象属性
- 多段业务逻辑串行执行
3.2.3 案例1:基础用法
import java.util.function.Consumer;
public class ConsumerDemo {
public static void main(String[] args) {
Consumer<String> c = str -> System.out.println(str);
c.accept("我被消费了");
}
}
3.2.4 案例2:批量修改集合属性
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class ConsumerUpdateDemo {
public static void main(String[] args) {
List<User> userList = new ArrayList<>();
userList.add(new User("张三", 17));
userList.add(new User("李四", 20));
Consumer<User> updateAge = user -> {
if (user.getAge() < 18) {
System.out.println(user.getName() + " 未成年,年龄修正为18");
}
};
userList.forEach(updateAge);
}
}
3.2.5 案例3:andThen 链式执行
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class ConsumerAndThenDemo {
public static void main(String[] args) {
List<User> userList = new ArrayList<>();
userList.add(new User("张三", 17));
Consumer<User> printUser = System.out::println;
Consumer<User> renameUser = user -> System.out.println("已实名认证-" + user.getName());
userList.forEach(printUser.andThen(renameUser));
}
}
💡 关键点:
List.forEach()底层接收的参数就是Consumer,Lambda 只是简化了函数式接口的实现写法。
3.3 Function<T, R> 转换型接口
3.3.1 核心特性
输入类型 T,输出类型 R,专门用于类型转换、数据映射、数值计算。
独有默认方法:
andThen():先执行当前逻辑,再执行后续逻辑compose():先执行传入逻辑,再执行当前逻辑
3.3.2 常用场景
- 实体类与 DTO 互转
- Stream 流中
map映射 - 多级数据加工处理
3.3.3 案例1:基础转换
import java.util.function.Function;
public class FunctionDemo {
public static void main(String[] args) {
Function<String, Integer> f = str -> str.length();
Integer len = f.apply("hello");
System.out.println(len);
}
}
3.3.4 案例2:实体转DTO
class UserDTO {
private String userName;
private Integer userAge;
public UserDTO(String userName, Integer userAge) {
this.userName = userName;
this.userAge = userAge;
}
@Override
public String toString() {
return userName + "," + userAge;
}
}
import java.util.function.Function;
public class FunctionDtoDemo {
public static void main(String[] args) {
Function<User, UserDTO> userToDto = user -> new UserDTO(user.getName(), user.getAge());
User user = new User("王五", 25);
UserDTO dto = userToDto.apply(user);
System.out.println(dto);
}
}
3.3.5 案例3:链式多级转换
import java.util.function.Function;
public class FunctionChainDemo {
public static void main(String[] args) {
Function<String, Integer> strToInt = Integer::valueOf;
Function<Integer, Integer> addTen = num -> num + 10;
Function<String, Integer> totalFunc = strToInt.andThen(addTen);
System.out.println(totalFunc.apply("20"));
}
}
3.3.6 案例4:Stream 中 map 使用
import java.util.List;
public class FunctionStreamDemo {
public static void main(String[] args) {
List<String> list = List.of("a", "b", "c");
list.stream()
.map(String::toUpperCase)
.forEach(System.out::println);
}
}
3.4 Predicate<T> 判断型接口
3.4.1 核心特性
传入参数,返回 boolean 布尔值,用于条件判断、数据过滤。
独有默认方法:and()、or()、negate() 可自由组合多条件。
3.4.2 常用场景
- Stream 流
filter过滤 - 业务规则校验
- 多条件逻辑组合判断
3.4.3 案例1:基础判断
import java.util.function.Predicate;
public class PredicateDemo {
public static void main(String[] args) {
Predicate<Integer> p = num -> num > 0;
boolean b = p.test(10);
System.out.println(b);
}
}
3.4.4 案例2:多条件组合过滤
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
public class PredicateFilterDemo {
public static void main(String[] args) {
List<User> userList = new ArrayList<>();
userList.add(new User("张三", 17));
userList.add(new User("李四", 22));
userList.add(new User("张无忌", 28));
Predicate<User> agePredicate = user -> user.getAge() > 18;
Predicate<User> namePredicate = user -> user.getName().contains("张");
Predicate<User> finalPredicate = agePredicate.and(namePredicate);
userList.stream()
.filter(finalPredicate)
.forEach(System.out::println);
}
}
3.4.5 案例3:条件取反、或运算
Predicate<User> notAdult = agePredicate.negate();
Predicate<User> orCond = notAdult.or(user -> user.getName().contains("李"));
四、两大高频扩展函数式接口
4.1 扩展接口总览
| 接口名 | 作用 | 抽象方法 |
|---|---|---|
BiConsumer<T,U> |
双参数消费者 | void accept(T t, U u) |
BiFunction<T,U,R> |
双参数转换器 | R apply(T t, U u) |
4.2 BiConsumer<T, U> 双参数消费者
两个入参、无返回值,常用于 Map 遍历、双参数业务处理。
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
public class BiConsumerDemo {
public static void main(String[] args) {
Map<String, Integer> wordCount = new HashMap<>();
wordCount.put("java", 10);
wordCount.put("lambda", 8);
BiConsumer<String, Integer> printCount = (key, value) ->
System.out.println("单词:" + key + ",出现次数:" + value);
wordCount.forEach(printCount);
}
}
4.3 BiFunction<T, U, R> 双参数转换器
两个入参、一个返回值,常用于数值运算、对象信息合并。
4.3.1 数值平方和运算
import java.util.function.BiFunction;
public class BiFunctionCalcDemo {
public static void main(String[] args) {
BiFunction<Integer, Integer, Integer> calc = (a, b) -> a*a + b*b;
System.out.println(calc.apply(3,4));
}
}
4.3.2 合并两个用户信息
import java.util.function.BiFunction;
public class BiFunctionMergeDemo {
public static void main(String[] args) {
BiFunction<User, User, String> mergeName = (u1, u2) ->
"合并用户:" + u1.getName() + " & " + u2.getName();
User u1 = new User("张三", 20);
User u2 = new User("李四", 22);
System.out.println(mergeName.apply(u1, u2));
}
}
五、各接口专属默认方法汇总
| 接口类型 | 链式/组合方法 | 作用 |
|---|---|---|
Consumer / BiConsumer |
andThen() |
串行执行多个消费逻辑 |
Function / BiFunction |
andThen()、compose() |
实现多级数据转换 |
Predicate |
and()、or()、negate() |
多条件并且、或者、取反 |
Supplier |
无 | 无链式拼接方法 |
六、使用函数式接口的核心好处
- 把逻辑当成参数传递:传统开发需手写接口、匿名内部类;现在通过 Lambda 直接传递业务逻辑,代码极度简洁。
- 通用模板可复用:框架代码只编写一次,业务逻辑通过函数式接口传入,一套模板适配多种业务场景。
- 完美适配 Stream 流式编程:Stream 核心的
filter、map、forEach底层全部依赖函数式接口,代码优雅精简。 - 代码松耦合:业务逻辑与框架代码完全分离,修改业务逻辑只需替换 Lambda 表达式,无需改动底层框架。
七、全文总结
- 必背四大核心:
Supplier生产、Consumer消费、Function转换、Predicate判断 - 高频扩展接口:
BiConsumer双参消费、BiFunction双参转换 - 链式方法区分:
Consumer/Function用andThen,Predicate用and/or/negate - 核心本质:Lambda 表达式 函数式接口的匿名实现简写,Stream 流底层完全依托函数式接口驱动
更多推荐

所有评论(0)