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教程。