Java Function接口
最后修改时间:2025 年 4 月 16 日
java.util.function.Function接口代表一个接受一个参数并产生结果的函数。它是一个函数式接口,只有一个抽象方法apply。Function通常用于转换流操作中的数据和方法引用。
Function是Java 8中添加的Java函数式编程实用程序的一部分。它支持行为参数化,并有助于编写更简洁的代码。该接口提供了用于函数组合和链式调用的默认方法。
Function接口概述
Function接口包含一个抽象方法和几个默认方法。关键方法apply对输入执行操作。其他方法支持函数组合和转换链。
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before);
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after);
static <T> Function<T, T> identity();
}
上面的代码显示了Function接口的结构。它使用泛型,其中T是输入类型,R是结果类型。该接口使用@FunctionalInterface注解进行标注,以表明其单一抽象方法的性质。
Function的基本用法
使用Function的最简单方法是使用lambda表达式。我们在apply方法中定义如何将输入转换为输出。此示例将字符串转换为它们的长度。
package com.zetcode;
import java.util.function.Function;
public class Main {
public static void main(String[] args) {
// Define a function that takes String and returns its length
Function<String, Integer> lengthFunction = s -> s.length();
// Apply the function
System.out.println("Length of 'hello': " + lengthFunction.apply("hello"));
System.out.println("Length of 'functional': " + lengthFunction.apply("functional"));
// Function using method reference
Function<String, Integer> lengthMethodRef = String::length;
System.out.println("Length via method ref: " + lengthMethodRef.apply("method"));
}
}
此示例演示了lambda和方法引用的基本Function用法。lengthFunction接受String并返回Integer。我们将其应用于不同的字符串。方法引用为现有方法提供了更简洁的语法。
使用 andThen 进行函数组合
andThen方法允许链接函数,其中一个函数的输出成为下一个函数的输入。这使得可以从简单的函数创建复杂的转换。
package com.zetcode;
import java.util.function.Function;
public class Main {
public static void main(String[] args) {
// First function converts String to uppercase
Function<String, String> toUpper = s -> s.toUpperCase();
// Second function extracts first 3 characters
Function<String, String> firstThree = s -> s.substring(0, Math.min(s.length(), 3));
// Compose the functions
Function<String, String> upperThenTrim = toUpper.andThen(firstThree);
System.out.println("Result: " + upperThenTrim.apply("hello world"));
System.out.println("Result: " + upperThenTrim.apply("java"));
}
}
此示例展示了使用andThen的函数组合。输入字符串首先被转换为大写,然后被修剪为前3个字符。操作顺序在链中从左到右。
使用 compose 进行函数组合
compose方法类似于andThen,但以相反的顺序执行函数。参数函数首先运行,然后是原始函数。
package com.zetcode;
import java.util.function.Function;
public class Main {
public static void main(String[] args) {
// Function to double a number
Function<Integer, Integer> doubler = x -> x * 2;
// Function to increment by 1
Function<Integer, Integer> incrementer = x -> x + 1;
// Compose in different orders
Function<Integer, Integer> incrementThenDouble = doubler.compose(incrementer);
Function<Integer, Integer> doubleThenIncrement = doubler.andThen(incrementer);
System.out.println("Increment then double 5: " + incrementThenDouble.apply(5));
System.out.println("Double then increment 5: " + doubleThenIncrement.apply(5));
}
}
此示例演示了compose和andThen之间的区别。使用compose,增量发生在加倍之前。使用andThen,加倍发生在增量之前。结果有所不同。
将Function与Streams一起使用
Function通常与Java Streams一起用于数据转换。map操作接受一个Function来转换流元素。这使得可以创建干净的数据处理管道。
package com.zetcode;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
List<String> names = Arrays.asList("alice", "bob", "charlie", "dave");
// Function to capitalize first letter
Function<String, String> capitalize = s ->
s.substring(0, 1).toUpperCase() + s.substring(1);
// Apply function in stream
List<String> capitalizedNames = names.stream()
.map(capitalize)
.collect(Collectors.toList());
System.out.println("Original: " + names);
System.out.println("Transformed: " + capitalizedNames);
}
}
此示例显示了Streams中的Function用法。我们定义一个大写函数,并通过map将其应用于每个流元素。结果是一个新的列表,其中包含转换后的值。流操作变得非常具有表现力。
Function Identity
Function.identity方法返回一个始终返回其输入参数的函数。当操作需要一个函数,但您希望原样传递值时,它很有用。
package com.zetcode;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
// Identity function
Function<String, String> identity = Function.identity();
System.out.println("Identity applied: " + identity.apply("test"));
// Practical use in streams
Stream<String> words = Stream.of("a", "b", "c");
var result = words.collect(Collectors.toMap(
Function.identity(), // key mapper
String::length // value mapper
));
System.out.println("Resulting map: " + result);
}
}
此示例演示了Function.identity。identity函数返回其输入未更改。在流中,它通常用作占位符,当不需要转换但需要一个Function时使用。
BiFunction及其他
虽然Function接受一个参数,但Java提供了用于不同元数的相关接口。BiFunction接受两个参数,并且存在用于基本类型的专用接口以避免装箱。
package com.zetcode;
import java.util.function.BiFunction;
import java.util.function.DoubleFunction;
import java.util.function.ToIntFunction;
public class Main {
public static void main(String[] args) {
// BiFunction example
BiFunction<Integer, Integer, String> sumToString =
(a, b) -> String.valueOf(a + b);
System.out.println("Sum as string: " + sumToString.apply(5, 3));
// Primitive specialized functions
DoubleFunction<String> doubleFormatter = d -> String.format("$%.2f", d);
System.out.println("Formatted: " + doubleFormatter.apply(12.3456));
ToIntFunction<String> stringToLength = String::length;
System.out.println("Length as int: " + stringToLength.applyAsInt("hello"));
}
}
此示例显示了Function的变体。BiFunction处理两个输入,而诸如DoubleFunction之类的基本类型特化提高了性能。Java的函数式接口涵盖了许多常见用例。
来源
在本文中,我们介绍了Java Function接口的基本方法和特性。理解这些概念对于现代Java应用程序中的函数式编程和流处理至关重要。
作者
列出所有Java教程。