功能接口与 Lambda 表达式是在 Java 8 中引入的特性,这些功能旨在增强 Java 中的函数式编程,并帮助编写更清晰、可读性更高的代码。在 Java 8 之前,为了实现基本功能,通常需要编写大量的样板代码。例如,为了调用一个方法,我们需要首先创建一个包含所需方法的类,然后创建一个类实例,并通过该实例来调用方法或使用相应的匿名类。
通过 Lambda 表达式,我们可以避免创建具体类以及匿名类对象的需求。功能接口进一步简化了这一过程,因为一个 Lambda 表达式可以很容易地实现功能接口,而只需要实现单一抽象方法。
功能接口展示了一种单一的功能。例如,Comparable
接口只有一个 compareTo()
方法,主要用于比较目的。但是它也可以有任意数量的默认和静态方法。
Java 8 定义了许多功能接口以方便在 Lambda 表达式中使用。以下是 java.util.Function
包中定义的一些功能接口列表。
@FunctionalInterface
注解
任何具有单个抽象方法的接口都是功能接口。Java 提供了一个 @FunctionalInterface
注解来标记一个接口作为功能接口,以便编译器可以检查一个接口是否是功能接口。此注解是可选的,主要是为了增加编译检查以及提高代码的可读性和维护性。
Java 中的功能接口类型
Predicate 功能接口
一个 Predicate
功能接口是其方法接受一个参数并且会返回 true
或 false
的接口。Predicate
功能接口主要用在比较操作中,如排序元素或基于对输入应用的某些条件过滤一个值。Java 提供了适用于基本类型的 Predicate
功能接口,如 IntPredicate
、DoublePredicate
和 LongPredicate
,它们分别只接受 Integer
、Double
和 Long
类型。
用法
Predicate predicate = (value) -> value != 0;
Predicate predicate = (value) -> test(value);
示例
在这个例子中,我们使用 Predicate
功能接口来过滤出整数列表中的偶数,通过 Lambda 表达式实现。
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);
}
}
编译并运行上述程序,将会产生以下结果:
[2, 4, 6, 8]
Consumer 功能接口
一个 Consumer
功能接口是其方法接受一个参数并且不会返回任何值的接口。Consumer
功能接口主要用于副作用操作,比如打印一个元素、添加称呼等。还有其他变体如 BiConsumer
。BiConsumer
功能接口可以接受两个参数。Java 提供了适用于基本类型的 Consumer
功能接口,如 IntConsumer
、DoubleConsumer
和 LongConsumer
,它们分别只接受 Integer
、Double
和 Long
类型。
用法
Consumer consumer = (value) -> System.out.println(value);
Consumer consumer1 = System.out::println;
Consumer consumer2 = (value) -> accept(value);
示例
在这个例子中,我们使用 Consumer
功能接口来打印所有整数列表中的数字,通过 Lambda 表达式和方法引用实现。
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);
}
}
编译并运行上述程序,将会产生以下结果:
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 功能接口
Supplier
功能接口是一个没有参数传递并且返回一个值的方法的接口。Supplier
功能接口主要用于懒加载生成值。例如,获取随机数、生成一系列数字等。
用法
Supplier supplier = () -> Math.random() * 10;
Supplier supplier1 = () -> get();
示例
在这个例子中,我们使用 Supplier
功能接口通过 Lambda 表达式获取一个随机数。
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<>();
for(int i = 0; i< 10; i++) {
randomNumbers.add(supplier.get());
}
System.out.println(randomNumbers);
}
}
编译并运行上述程序,将会产生以下结果:
[0, 8, 8, 8, 8, 5, 7, 5, 5, 9]
Function 功能接口
Function
功能接口是一个其方法接受一个参数并且会返回一个值的接口。Function
功能接口主要用于获取处理后的值。例如,获取元素的平方、修剪字符串值等。还有其他变体如 BiFunction
。BiFunction
功能接口可以接受两个参数。Java 提供了适用于基本类型的 Function
功能接口,如 IntFunction
、DoubleFunction
和 LongFunction
,它们分别只接受 Integer
、Double
和 Long
类型。还有两个实用接口,UnaryOperator
扩展了 Function
接口,而 BinaryOperator
扩展了 BiFunction
接口。
用法
Function function = (value) -> Math.random() * 10;
Function function1 = (value) -> apply(value);
示例
在这个例子中,我们使用 Function
功能接口通过 Lambda 表达式获取一个数字列表的平方。
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);
}
}
编译并运行上述程序,将会产生以下结果:
[1, 4, 9, 16, 25, 36, 49, 64]
Java 8 之前的现有功能接口
Java 8 之前已存在的许多接口现在被标注为功能接口,可以用于 Lambda 表达式。例如:
-
-
-
ActionListener
—— 提供 actionPerformed()
方法
-
Comparable
—— 提供 compareTo()
方法用于比较两个数字
示例
在这个例子中,我们创建了两个线程。第一个是使用匿名类创建的,第二个是使用 Lambda 表达式创建的。两者都使用 Runnable
接口来创建线程实例。
package com.tutorialspoint;
public class Tester {
public static void main(String args[]) {
new Thread(new Runnable() {
@Override public void run() {
System.out.println("Thread 1 is running");
}
}).start();
new Thread(() -> {
System.out.println("Thread 2 is running.");
}).start();
}
}
编译并运行上述程序,将会产生以下结果:
Thread 1 is running
Thread 2 is running.