Java中的功能接口
Java中的功能接口是具有单个抽象方法的接口。这是Java中的功能接口示例。
interface MyFunctionalInterface{ void calculateInterest(int i); }
由于该接口中只有一个未实现的方法,因此可以将该接口视为功能接口。
什么是功能界面
Java 8及更高版本的接口可以具有默认方法,静态方法,而Java 9及更高版本甚至私有方法,因此功能接口也可以具有这些方法,但是只有一个未实现的方法才可以用作功能接口。
如果接口声明的抽象方法覆盖了java.lang.Object的公共方法之一,则该方法也不会计入接口的抽象方法。
后续接口即使包含默认方法和私有方法,也具有功能接口,因为它具有单个抽象方法。
@FunctionalInterface interface MyFunctionalInterface{ void calculateInterest(int i); default void defMethod(){ commonCode(); System.out.println("In default method 2"); } private void commonCode(){ System.out.println("Executing common code..."); } }
功能接口和Lambda表达式
尽管Java中已经有使用单一抽象方法的接口,例如具有单个run()方法的Runnable,具有call()方法的Callable或者具有compare()方法的Comparator,但是术语"功能接口"在Java 8中Lambda表达式的介绍
Lambda表达式本身只是一个函数,需要执行目标类型上下文。由于Java是一种面向对象的语言,因此Lambda表达式必须包装在功能接口所提供的对象中。 Lambda表达式指定了由函数接口定义的抽象方法的实现,这就是函数接口为Lambda表达式提供目标类型的方式。
让我们看一个示例,其中将lambda表达式分配给功能接口引用。
//Functional interface interface MyFunctionalInterface{ void calculateSimpleInterest(int p, int r, int t); } public class LambdaExample { public static void main(String[] args) { // lambda assigned to functional interface reference MyFunctionalInterface ref = (int p, int r, int t) -> System.out.println("Simple Interest is " + (p*r*t)/100); ref.calculateSimpleInterest(10000, 5, 3); } }
输出:
Simple Interest is 1500
在示例中,我们可以看到Lambda表达式已分配给MyFunctionalInterface引用。由于此处的lambda表达式的目标类型是MyFunctionalInterface,因此将自动创建一个类的实例,该实例实现功能接口,而lambda表达式提供功能接口声明的抽象方法的实现。
这是另一个示例,其中lambda表达式作为方法参数传递。在那种情况下,功能接口提供目标类型作为方法参数。
public class LambdaExample { public static void main(String[] args) { new Thread(()->System.out.println("Method argument to Runnable")).start(); } }
输出:
Method argument to Runnable
上面的示例是Runnable as Lambda表达式的实现。如我们在此处看到的那样,使用了Runnable作为方法参数传递的线程构造函数,而实现了Runnable功能接口的run()方法的Lambda表达式作为方法参数传递了。 Java运行时能够根据使用的上下文推断目标类型。
Java中的@FunctionalInterface注释
Java 8中还添加了@FunctionalInterface批注,以与Java中的功能接口一起使用。通过使用@FunctionalInterface批注对接口进行批注,可以确保该接口不会使用多个抽象方法。最好将其与功能接口一起使用,这样就不会偶然将其他抽象方法添加到接口中。
这是一个尝试向使用@FunctionalInterface注释注释的功能接口添加另一个抽象方法的示例。
@FunctionalInterface interface MyFunctionalInterface{ int calculateSimpleInterest(int p, int r, int t); void test(int i); }
该功能接口给出了编译时错误"无效的'@FunctionalInterface'注释; MyFunctionalInterface不是功能接口",因为不止一种抽象方法。
Java中的预打包功能接口
在上面显示的示例中,我们创建了自己的功能接口,但是Java预包装了许多功能接口,涵盖了大多数场景。 Java 8中添加了一个全新的软件包java.util.function,其中包含许多现成可用的功能接口。
一些内置的功能接口如下:
BiConsumer <T,U> –表示一个接受两个输入参数且不返回结果的操作。
BiFunction <T,U,R> –表示一个接受两个参数并产生结果的函数。
BinaryOperator <T> –表示对两个相同类型的操作数的运算,产生与该操作数相同类型的结果。
Function <T,R> –表示一个接受一个参数并产生结果的函数。
Predicate <T> –表示一个参数的谓词(布尔值函数)。
Supplier <T>代表结果的供应商。
UnaryOperator <T> –表示对单个操作数的操作,该操作产生与其操作数相同类型的结果。
在此处检查整个列表https://docs.oracle.com/javase/10/docs/api/java/util/function/package-summary.html
使用BiFunction功能接口的示例
由于BiFunction功能接口接受两个参数并返回结果,因此可以在需要使用两个参数进行计算的地方使用它。
public class LambdaExample { public static void main(String[] args) { BiFunction<String, String, String> ref = (str1, str2) -> str1+ " " +str2; System.out.println("Concatenating Strings- " + ref.apply("Hello", "Lambda")); } }
输出:
Concatenating Strings- Hello Lambda
使用谓词功能接口的示例
Java中的谓词功能接口有一个抽象方法test(),它对给定参数评估此谓词,如果输入参数与谓词匹配,则返回true,否则返回false。
假设我们有一个整数列表,并且只想获取列表中大于10的那些元素,则可以使用谓词功能接口来测试元素是否大于10,并且仅在大于10时才返回true。 。
public class LambdaExample { public static void main(String[] args) { List<Integer> myList = Arrays.asList(25, 5, 17, 1, 7, 14, 9, 11); LambdaExample obj = new LambdaExample(); // Lambda expression as method arg List<Integer> filterdList = obj.filter(myList, (i) -> i>10); System.out.println("Filtered elements- " + filterdList); } public <T> List<T> filter(Collection<T> myList, Predicate<T> predicate) { List<T> filterdList = new ArrayList<T>(); for(T element: myList) { if(predicate.test(element)) { filterdList.add(element); } } return filterdList; } }
输出:
Filtered elements- [25, 17, 14, 11]
在示例中,lambda表达式(i)-> i> 10提供了谓词功能接口的抽象方法test()的实现。