在 Java 中,Function<T, R> 是函数式接口的核心代表,用于表明 “输入一个类型 T 的参数,返回一个类型 R 的结果” 的函数。除了基础的 apply() 方法,结合 Java 8+ 的 Stream、Optional、方法引用、复合函数等特性,Function 还有许多高级玩法,能极大简化代码、提升可读性。以下是 10 个实用的高级用法,附代码示例:

一、复合函数:andThen()与compose()链式调用
Function 提供了两个默认方法用于函数组合,实现 “链式执行”:
- andThen(Function<? super R, ? extends V> after):先执行当前函数,再将结果作为参数传给 after 函数(先当前后 after)。
- compose(Function<? super V, ? extends T> before):先执行 before 函数,再将结果作为参数传给当前函数(先 before 后当前)。
示例:数据转换链式处理
import java.util.function.Function;
public class FunctionDemo {
public static void main(String[] args) {
// 1. 字符串转整数
Function<String, Integer> strToInt = Integer::parseInt;
// 2. 整数翻倍
Function<Integer, Integer> doubleNum = n -> n * 2;
// 3. 整数转字符串(加前缀)
Function<Integer, String> intToStrWithPrefix = n -> "结果:" + n;
// 组合1:strToInt → doubleNum → intToStrWithPrefix(andThen链式)
Function<String, String> process1 = strToInt.andThen(doubleNum).andThen(intToStrWithPrefix);
System.out.println(process1.apply("10")); // 输出:结果:20
// 组合2:先执行doubleNum(需适配参数),再执行strToInt(compose)
// 注意:compose的参数函数输入类型需匹配最终输入,输出类型需匹配当前函数输入
Function<String, Integer> process2 = strToInt.compose(s -> Integer.parseInt(s) + 5); // 先s→int+5,再转int(此处仅演示逻辑)
System.out.println(process2.apply("10")); // 输出:15(先10+5=15,再转int)
}
}
二、与Stream结合:自定义映射逻辑
Stream.map(Function<? super T, ? extends R>) 是 Function 最常用的场景之一,但高级用法在于复杂映射逻辑的复用(将重复的 map 逻辑抽取为独立 Function)。
示例:抽取通用映射函数
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
class User {
private String name;
private int age;
// 构造器、getter省略
public User(String name, int age) { this.name = name; this.age = age; }
public String getName() { return name; }
public int getAge() { return age; }
}
public class StreamFunctionDemo {
// 抽取:User → 用户名(复用逻辑)
private static final Function<User, String> USER_TO_NAME = User::getName;
// 抽取:User → 年龄+10
private static final Function<User, Integer> USER_AGE_PLUS_10 = user -> user.getAge() + 10;
public static void main(String[] args) {
List<User> users = Arrays.asList(
new User("Alice", 20),
new User("Bob", 25)
);
// 复用Function进行map
List<String> names = users.stream().map(USER_TO_NAME).collect(Collectors.toList());
List<Integer> agesPlus10 = users.stream().map(USER_AGE_PLUS_10).collect(Collectors.toList());
System.out.println(names); // [Alice, Bob]
System.out.println(agesPlus10); // [30, 35]
}
}
三、与Optional结合:安全的链式转换
Optional.map(Function<? super T, ? extends U>) 可避免空指针,结合 Function 实现 “多步安全转换”(若中间步骤为 null,直接返回 Optional.empty())。
示例:多层对象安全取值
import java.util.Optional;
import java.util.function.Function;
class Address {
private String city;
public Address(String city) { this.city = city; }
public String getCity() { return city; }
}
class User {
private Address address;
public User(Address address) { this.address = address; }
public Address getAddress() { return address; }
}
public class OptionalFunctionDemo {
public static void main(String[] args) {
// 函数1:User → Address
Function<User, Address> userToAddress = User::getAddress;
// 函数2:Address → 城市(大写)
Function<Address, String> addressToCity = addr -> addr.getCity().toUpperCase();
// 安全链式转换:User → Address → 城市(避免NPE)
User userWithAddress = new User(new Address("Shanghai"));
User userWithoutAddress = new User(null);
String city1 = Optional.ofNullable(userWithAddress)
.map(userToAddress) // 第一步转换
.map(addressToCity) // 第二步转换
.orElse("未知城市");
System.out.println(city1); // SHANGHAI
String city2 = Optional.ofNullable(userWithoutAddress)
.map(userToAddress)
.map(addressToCity)
.orElse("未知城市");
System.out.println(city2); // 未知城市
}
}
四、方法引用简化Function定义
对于 “直接调用某个方法” 的简单逻辑,无需用 lambda 表达式,直接用方法引用(::)简化 Function 定义,代码更简洁。
示例:方法引用的 3 种场景
import java.util.function.Function;
public class MethodReferenceDemo {
public static void main(String[] args) {
// 1. 静态方法引用:String → Integer(Integer.parseInt(String))
Function<String, Integer> strToInt = Integer::parseInt;
// 2. 实例方法引用(对象实例):String → Integer("abc".length())
String prefix = "前缀_";
Function<String, String> addPrefix = prefix::concat; // 等价于 s -> prefix.concat(s)
// 3. 实例方法引用(类名):String → Character("abc".charAt(0))
Function<String, Character> firstChar = s -> s.charAt(0);
// 更简洁:类名::方法名(适用于方法参数为Function输入的场景)
Function<String, Integer> strLength = String::length;
System.out.println(strToInt.apply("20")); // 20
System.out.println(addPrefix.apply("test")); // 前缀_test
System.out.println(strLength.apply("hello")); // 5
}
}
五、Function作为方法参数:通用化逻辑
将 Function 作为方法参数,让方法支持 “自定义逻辑注入”,实现方法的通用性(类似 “策略模式” 的简化版)。
示例:通用数据处理器
import java.util.function.Function;
public class FunctionAsParameterDemo {
// 通用方法:接收数据和处理函数,返回处理结果
public static <T, R> R processData(T data, Function<T, R> processor) {
System.out.println("处理数据:" + data);
return processor.apply(data);
}
public static void main(String[] args) {
// 场景1:字符串转大写
String upperStr = processData("hello", String::toUpperCase);
System.out.println(upperStr); // HELLO
// 场景2:整数平方
Integer square = processData(10, n -> n * n);
System.out.println(square); // 100
// 场景3:字符串长度翻倍
Integer doubleLength = processData("java", s -> s.length() * 2);
System.out.println(doubleLength); // 8
}
}
六、BiFunction处理双参数场景
Function 仅支持单输入,若需处理两个输入参数,可使用 BiFunction<T, U, R>(输入 T 和 U,返回 R),配合 andThen() 可扩展为多步处理。
示例:双参数计算 + 链式转换
import java.util.function.BiFunction;
import java.util.function.Function;
public class BiFunctionDemo {
public static void main(String[] args) {
// 双参数函数:两个整数相加
BiFunction<Integer, Integer, Integer> add = (a, b) -> a + b;
// 单参数函数:整数转字符串(加描述)
Function<Integer, String> intToDesc = n -> "总和:" + n;
// 组合:先相加,再转描述
String result = add.andThen(intToDesc).apply(10, 20);
System.out.println(result); // 总和:30
// 复杂场景:拼接两个字符串并转为大写
BiFunction<String, String, String> concat = (s1, s2) -> s1 + "-" + s2;
Function<String, String> toUpper = String::toUpperCase;
String concatResult = concat.andThen(toUpper).apply("hello", "world");
System.out.println(concatResult); // HELLO-WORLD
}
}
七、UnaryOperator简化 “输入输出类型一样” 场景
若 Function 的输入类型 T 和输出类型 R 一样(如 “整数翻倍”“字符串截取”),可使用 UnaryOperator<T>(Function<T, T> 的子类),无需重复声明类型,代码更简洁。
示例:UnaryOperator 替代同类型 Function
import java.util.function.UnaryOperator;
public class UnaryOperatorDemo {
public static void main(String[] args) {
// 等价于 Function<Integer, Integer> doubleNum = n -> n * 2;
UnaryOperator<Integer> doubleNum = n -> n * 2;
// 等价于 Function<String, String> truncate = s -> s.substring(0, 3);
UnaryOperator<String> truncate = s -> s.substring(0, 3);
System.out.println(doubleNum.apply(5)); // 10
System.out.println(truncate.apply("Java8")); // Jav
// 组合使用(andThen同样适用)
UnaryOperator<Integer> add5 = n -> n + 5;
UnaryOperator<Integer> process = add5.andThen(doubleNum); // 先+5,再翻倍
System.out.println(process.apply(10)); // 30
}
}
八、Function与缓存结合:缓存计算结果
对于耗时的 Function 计算(如数据库查询、复杂运算),可包装 Function 实现结果缓存(避免重复计算),典型场景:数据字典翻译、ID→名称映射。
示例:带缓存的 Function 包装器
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
public class CachedFunctionDemo {
// 包装Function,添加缓存逻辑
public static <T, R> Function<T, R> cached(Function<T, R> function) {
Map<T, R> cache = new HashMap<>();
return t -> cache.computeIfAbsent(t, function); // 不存在则计算并缓存
}
public static void main(String[] args) {
// 模拟耗时计算:ID→用户名(假设查询数据库)
Function<Long, String> idToName = id -> {
System.out.println("查询数据库:ID=" + id); // 仅第一次执行
return id == 1L ? "Alice" : "Bob";
};
// 包装为带缓存的Function
Function<Long, String> cachedIdToName = cached(idToName);
// 第一次调用:查询数据库并缓存
System.out.println(cachedIdToName.apply(1L)); // 查询数据库:ID=1 → Alice
// 第二次调用:直接取缓存
System.out.println(cachedIdToName.apply(1L)); // Alice(无数据库查询)
System.out.println(cachedIdToName.apply(2L)); // 查询数据库:ID=2 → Bob
}
}

九、Function实现类型转换工具类
利用 Function 的通用性,可封装通用类型转换工具,统一处理不同对象间的转换(替代繁琐的 setter 赋值)。
示例:对象转换工具类
import java.util.function.Function;
// DTO类
class UserDTO {
private String username;
private int userAge;
// 构造器、getter省略
public UserDTO(String username, int userAge) { this.username = username; this.userAge = userAge; }
public String getUsername() { return username; }
public int getUserAge() { return userAge; }
}
// 实体类
class UserEntity {
private String name;
private int age;
// 构造器、getter/setter省略
public UserEntity(String name, int age) { this.name = name; this.age = age; }
public String getName() { return name; }
public int getAge() { return age; }
}
public class ConverterDemo {
// 通用转换方法:接收源对象和转换函数,返回目标对象
public static <S, T> T convert(S source, Function<S, T> converter) {
return converter.apply(source);
}
public static void main(String[] args) {
// 定义DTO→Entity的转换规则
Function<UserDTO, UserEntity> dtoToEntity = dto ->
new UserEntity(dto.getUsername(), dto.getUserAge());
// 定义Entity→DTO的转换规则
Function<UserEntity, UserDTO> entityToDto = entity ->
new UserDTO(entity.getName(), entity.getAge());
// 转换示例
UserDTO dto = new UserDTO("Charlie", 30);
UserEntity entity = convert(dto, dtoToEntity);
System.out.println(entity.getName() + ":" + entity.getAge()); // Charlie:30
UserDTO dto2 = convert(entity, entityToDto);
System.out.println(dto2.getUsername() + ":" + dto2.getUserAge()); // Charlie:30
}
}
十、Function与枚举结合:实现策略枚举
枚举 +Function 可实现 “策略枚举”,将不同策略(逻辑)封装在枚举常量中,统一管理,避免大量 if-else。
示例:支付方式策略枚举
import java.util.function.Function;
// 支付金额计算策略枚举
enum PaymentStrategy {
// 枚举常量:策略名称 + 计算函数(Function<订单金额, 实际支付金额>)
NORMAL(amount -> amount), // 原价
DISCOUNT_90(amount -> amount * 0.9), // 9折
FULL_100_MINUS_20(amount -> amount >= 100 ? amount - 20 : amount); // 满100减20
// 持有Function作为策略逻辑
private final Function<Double, Double> calculator;
PaymentStrategy(Function<Double, Double> calculator) {
this.calculator = calculator;
}
// 执行计算
public double calculate(double amount) {
return calculator.apply(amount);
}
}
public class StrategyEnumDemo {
public static void main(String[] args) {
double orderAmount = 150.0;
// 不同策略计算
double normalPay = PaymentStrategy.NORMAL.calculate(orderAmount);
double discountPay = PaymentStrategy.DISCOUNT_90.calculate(orderAmount);
double fullReducePay = PaymentStrategy.FULL_100_MINUS_20.calculate(orderAmount);
System.out.println("原价支付:" + normalPay); // 150.0
System.out.println("9折支付:" + discountPay); // 135.0
System.out.println("满减支付:" + fullReducePay); // 130.0
}
}
核心总结
Function 及其相关接口(BiFunction、UnaryOperator 等)的核心价值是将 “逻辑” 抽象为可传递、可组合的对象,配合 Java 8+ 的流式 API、Optional 等特性,可实现:
- 简化重复逻辑(抽取为独立 Function);
- 避免空指针(与 Optional 结合);
- 减少 if-else(策略枚举);
- 提升代码通用性(作为方法参数)。
这些玩法覆盖了日常开发中的大部分场景,合理使用能让代码更简洁、更易维护。




















暂无评论内容