Java 简明教程
Java - Functional Interfaces
Functional interfaces 在 Java 8 中引入,以及 lambda expression 和 method references 。这三个特性被添加来提升 Java 中函数式编程并编写干净、可读的代码。在 Java 8 之前,必须编写大量样板代码来涵盖基本功能。例如,为了调用函数,我们首先必须创建一个带有所需方法的类、创建一个类实例,而实例需要调用方法,或者另一种方法是使用具有相应方法的 anonymous class 。
Functional interfaces were introduced in Java 8 along with lambda expression and method references. These three features were added to boost functional programming in Java and to write clean, readable code. Before Java 8, a lot of boilerplate code had to be written to cover basic functionality. For example, in order to call a function, first we had to create a class with the required method, create a class instance, and the instance, needed to invoke the method or another way was to use an anonymous class with the corresponding method.
使用 Lambda 表达式,我们可以避免对具体和匿名类对象的需求。functional interface 协助向前迈进了一步,因为 Lambda 表达式可以轻松地实现函数式接口,只要实现一个方法。
With lambda expression, we can avoid the need for both concrete as well as anonymous class objects. A functional interface assists one step ahead, as a lambda expression can implement the functional interface easily as only one method is to be implemented.
Functional interfaces 有一个要展示的单一功能。例如,带有单个方法 compareTo() 的 Comparable 接口用于比较目的。但它可以拥有任意数量的默认和静态方法。
Functional interfaces have a single functionality to exhibit. For example, a Comparable interface with a single method compareTo() is used for comparison purposes. But it can have any number of default and static methods.
Java 8 定义了很多函数式接口,以便在 Lambda 表达式中广泛使用。以下是 java.util.Function 包中定义的函数式接口列表。
Java 8 has defined a lot of functional interfaces to be used extensively in lambda expressions. Following is the list of functional interfaces defined in java.util.Function package.
@FunctionalInterface Annotation
按功能,任何接口只要有一个单一抽象方法就是一个函数式接口。Java 提供了 @FunctionalInterface 注解来标记一个接口为函数式接口,这样编译器可以检查一个接口是否属于函数式接口。这个注解是可选的,它主要目的是添加编译器检查并提升代码的可读性和可维护性。
By functionality, any interface having a single abstract method is a functional interface. Java provides a @FunctionalInterface annotation to mark an interface as a functional interface so that the compiler can check if an interface is a functional interface or not. This annotation is optional and is primarily to add a compiler check and to increase the code readability and maintenance.
Types of Functional Interfaces in Java
在 Java 中主要有四种类型的函数式接口。
There are primarily four types of functional interfaces in Java.
Predicate Functional Interface
谓词式函数式接口是一个其方法接受一个自变量并返回 true 或 false 的接口。谓词式函数式接口主要用于比较元素或基于应用于传递给输入的特定条件(某些条件)对值进行过滤。Java 同时提供针对基本类型的谓词式函数式接口,如 IntPredicate、DoublePredicate 和 LongPredicate,它们分别只接受 Integer、Double 和 Long。
A predicate functional interface is the one whose method accepts one argument and will return either true or false. A predicate functional interface is mainly used in comparison to sort elements or to filter a value based on certain condition(s) applied on the input passed. Java provides predicate functional interfaces for primitives as well as IntPredicate, DoublePredicate, and LongPredicate, which accept only Integer, Double, and Long respectively.
Predicate predicate = (value) -> value != 0;
// or
Predicate predicate = (value) -> test(value);
在上面的片段中,谓词函数的作用是基于传递给它的值返回 true/false。
In above snippet predicate function is to return either true/false based on the value passed.
在这个示例中,我们正在使用一个谓词式函数式接口,借助一个 Lambda 表达式,从一个整数列表中过滤出奇数。
In this example, we’re using a predicate functional interface to filter odd numbers from a list of integers with the help of a lambda expression.
package com.tutorialspoint;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class Tester {
public static void main(String args[]) {
List<Integer> numbers = Arrays.asList(1,2,3,4,5,6,7,8);
Predicate<Integer> isEvenNumber = n -> n %2 == 0;
numbers = numbers.stream().filter(isEvenNumber).toList();
System.out.println(numbers);
}
}
让我们编译并运行上述程序,这将生成以下结果 −
Let us compile and run the above program, this will produce the following result −
[2, 4, 6, 8]
Consumer Functional Interface
消费式函数式接口是一个其方法接受一个自变量且不返回任何内容的接口。消费式函数式接口主要用于产生副作用的操作。例如,打印一个元素,添加一个敬语等。也存在如 BiConsumer 等 Consumer 的其他变体。BiConsumer 函数式接口可以接受两个参数。Java 同时提供针对基本类型的消费者式函数式接口,如 IntConsumer、DoubleConsumer 和 LongConsumer,它们分别只接受 Integer、Double 和 Long。
A consumer functional interface is one whose method accepts one argument and will not return anything. A consumer functional interface is mainly used for side-effect operations. For example, to print an element, to add a salutation, etc. There are other variants of Consumer as well like BiConsumer. A BiConsumer functional interface can accept two parameters. Java provides consumer functional interfaces for primitives as well as IntConsumer, DoubleConsumer, and LongConsumer, which accept only Integer, Double, and Long respectively.
Consumer consumer = (value) -> System.out.println(value);
// Or
Consumer consumer1 = System.out::println;
// Or
Consumer consumer2 = (value) -> accept(value);
在这个示例中,我们正在使用一个消费者式函数式接口,借助一个 Lambda 表达式和一个方法引用,从一个整数列表中打印所有数字。
In this example, we’re using consumer functional interface to print all numbers from a list of integers with the help of a lambda expression and a method reference.
package com.tutorialspoint;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
public class Tester {
public static void main(String args[]) {
List<Integer> numbers = Arrays.asList(1,2,3,4,5,6,7,8);
Consumer<Integer> consumer = (value) -> System.out.println(value);
Consumer consumer1 = System.out::println;
System.out.println("Printing using consumer functional interface as lambda expression");
numbers.forEach(consumer);
System.out.println("Printing using consumer functional interface as method reference");
numbers.forEach(consumer1);
}
}
让我们编译并运行上述程序,这将生成以下结果 −
Let us compile and run the above program, this will produce the following result −
Printing using consumer functional interface as lambda expression
1
2
3
4
5
6
7
8
Printing using consumer functional interface as method reference
1
2
3
4
5
6
7
8
Supplier Functional Interface
供应商式函数式接口是一个其方法没有要传递的任何自变量且将返回一个值的接口。供应商式函数式接口主要用于懒惰地生成值。例如,获取一个随机数,生成一个数字序列等。
The supplier functional interface is the one whose method does not have any arguments to pass and will return a value. A supplier functional interface is mainly used to generate values lazily. For example, to get a random number, to generate a sequence of numbers, etc.
Supplier supplier = () -> Math.random() * 10;
// or
Supplier supplier1 = () -> get();
在这个示例中,我们正在使用一个供应商式函数式接口,借助一个 Lambda 表达式,获取一个随机数。
In this example, we’re using supplier functional interface to get a random number with the help of a lambda expression.
package com.tutorialspoint;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
public class Tester {
public static void main(String args[]) {
Supplier<Integer> supplier = () -> (int)(Math.random() * 10);
List<Integer> randomNumbers = new ArrayList<>();
// generate 10 random numbers
for(int i = 0; i< 10; i++) {
randomNumbers.add(supplier.get());
}
System.out.println(randomNumbers);
}
}
让我们编译并运行上述程序,这将生成以下结果 −
Let us compile and run the above program, this will produce the following result −
[0, 8, 8, 8, 8, 5, 7, 5, 5, 9]
Function Functional Interface
Function 函数式接口是不接受一个参数并且会返回一个值的方法。函数式接口通常用于获取处理过后的值。比如,获取一个元素的平方,修整字符串值等。Function 还有其它变体,例如 BiFunction。BiFunction 函数式接口可以接受两个参数。Java 既提供了基本类型的函数式接口,也提供了只接受 Integer、Double 和 Long 的 IntFunction、DoubleFunction 和 LongFunction 等。还有两个效用接口,分别为扩展 Function 接口的 UnaryOperator 和扩展 BiFunction 接口的 BinaryOperator。
Function functional interface is one whose method accepts one argument and will return a value. A function functional interface is mainly used to get the processed value. For example, to get the square of an element, to trim string values, etc. There are other variants of Function as well like BiFunction. A BiFunction functional interface can accept two parameters. Java provides function functional interfaces for primitives as well as IntFunction, DoubleFunction, and LongFunction, which accept only Integer, Double, and Long respectively. There are two more utility interfaces, UnaryOperator which extend the Function interface, and BinaryOperator which extends the BiFunction interface.
Function function = (value) -> Math.random() * 10;
// or
Function function1 = (value) -> apply(value);
在这个示例中,我们使用函数式接口来借助一个 lambda 表达式获取一个数字的平方列表。
In this example, we’re using function functional interface to get a list of squares of numbers with the help of a lambda expression.
package com.tutorialspoint;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
public class Tester {
public static void main(String args[]) {
List<Integer> numbers = Arrays.asList(1,2,3,4,5,6,7,8);
Function<Integer, Integer> squared = (value) -> value * value;
List<Integer> squaredNumbers = numbers.stream().map(squared).toList();
System.out.println(squaredNumbers);
}
}
让我们编译并运行上述程序,这将生成以下结果 −
Let us compile and run the above program, this will produce the following result −
[1, 4, 9, 16, 25, 36, 49, 64]
Existing Functional Interfaces Prior to Java 8
在 Java 中,很多现存的接口被标记为函数式接口,并且可以在 lambda 表达式中使用。比如:
With Java, many existing interfaces are annotated as functional interfaces and can be used in lambda expressions. For example:
-
Runnable − provides run() method
-
Callable − provides call() method
-
Actionlistener − provides actionPerformed() method
-
Comparable − provides compareTo() method to compare two numbers
Example
在这个示例中,我们创建了两个线程。第一个使用匿名类创建,第二个使用 lambda 表达式创建。两者都使用可运行接口创建线程实例。
In this example, we’re creating two threads. First is created using anonymous class and second is using lambda expression. Both are using runnable interface to create the thread instance.
package com.tutorialspoint;
public class Tester {
public static void main(String args[]) {
// create anonymous inner class object
new Thread(new Runnable() {
@Override public void run() {
System.out.println("Thread 1 is running");
}
}).start();
// lambda expression to create the object
new Thread(() -> {
System.out.println("Thread 2 is running.");
}).start();
}
}
让我们编译并运行上述程序,这将生成以下结果 −
Let us compile and run the above program, this will produce the following result −
Thread 1 is running
Thread 2 is running.