Java中的功能接口

时间:2020-01-09 10:35:13  来源:igfitidea点击:

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()的实现。