本文将介绍 Java 自定义Function接口示例。 Java 提供了 @FunctionalInterface
注解来创建Function接口。 @FunctionalInterface
从 Java 8 开始可用。函数式接口只有一个抽象方法。可以使用 lambda 表达式、方法引用或构造函数引用来初始化Function接口。Function接口可以有默认方法。也可以通过继承另一个Function接口来创建Function接口。 Java提供了Supplier
、Consumer
、Predicate
等内置Function接口。
在本文中,我们将使用 @FunctionalInterface
注释创建自定义Function接口。在我们的示例中,我们将使用泛型、默认方法和继承来创建Function接口。我们还将提供使用 lambda 表达式、方法引用或构造函数引用来初始化Function接口的示例。现在让我们逐步讨论创建自定义Function接口。
1.@FunctionalInterface
注解用于创建Function接口。
2. 一个函数式接口只有一个抽象方法。
3. 接口的默认方法不计为抽象,因为它们有实现。
4. 如果函数式接口声明了一个覆盖 Java Object
类的公共方法之一的抽象方法,那也不会被计算在内。
5. 函数式接口的实例可以使用 lambda 表达式、方法引用或构造函数引用来创建。
要创建我们的函数式接口,我们需要创建一个带有 @FunctionalInterface
注释的接口和一个抽象方法。接口中的抽象方法后跟分号,但没有大括号。
计算器.java
package com.concretepage;
@FunctionalInterface
public interface Calculator {
long calculate(long num1, long num2);
}
在这里,我们使用抽象方法 calculate
创建了 Calculator
接口。接口 Calculator
用 @FunctionalInterface
注释,这样我们就创建了一个Function接口,即 Calculator
。我们可以使用 lambda 表达式、方法引用或构造函数引用来实例化一个函数式接口。
在这里,我们将使用 lambda 表达式实例化一个函数式接口。查找 lambda 表达式语法。
(Argument part) -> Body part
现在我们将实例化我们的Function接口 Calculator
,如下所示。
Calculator calc = (n1, n2) -> n1 + n2;
在上面的 lambda 表达式中,参数的数量是两个,因为抽象方法 calculate
已经定义了两个参数。为了得到结果,我们将调用函数接口的方法。
System.out.println(calc.calculate(30, 50));
输出将是 80。
使用 Lambda 表达式将Function接口作为方法参数传递:
现在在一个类中创建一个方法,其参数将是我们的Function接口类型,如下所示。
public long process(Calculator calc) {
return calc.calculate(this.firstNum, this.secondNum);
}
该类将如下所示。
MyNumber.java
package com.concretepage;
public class MyNumber {
private long firstNum;
private long secondNum;
public MyNumber(long firstNum, long secondNum) {
this.firstNum = firstNum;
this.secondNum = secondNum;
}
public long process(Calculator calc) {
return calc.calculate(this.firstNum, this.secondNum);
}
//setters getters
}
我们可以直接将 lambda 表达式作为参数或函数接口的实例传递给上述类中的 process
方法。假设我们有一个如下的 MyNumber
列表。
List<MyNumber> list = new ArrayList<>();
list.add(new MyNumber(100, 40));
list.add(new MyNumber(300, 60));
list.add(new MyNumber(60, 20));
我们可以通过以下方式运行我们的Function接口。
示例 1:
在这里,我们正在创建函数接口的对象,然后将其作为求和的参数传递。
Calculator calc = (n1, n2) -> n1 + n2;
for(MyNumber myNumber: list) {
System.out.println(myNumber.process(calc));
}
输出。
140
360
80
示例 2:
在这里,我们直接将 lambda 表达式作为乘法参数传递。
for(MyNumber myNumber: list) {
System.out.println(myNumber.process((n1, n2) -> n1 * n2));
}
输出
4000
18000
1200
示例 3:
这里我们进行除法。
for(MyNumber myNumber: list) {
System.out.println(myNumber.process((n1, n2) -> n1 / n2));
}
输出。
2
5
3
方法引用使用 (::) 符号调用方法。假设我们有一个类 MyNumber
和一个静态方法 add
,那么我们可以使用类名来调用它。
MyNumber::add
如果 add
不是静态方法,那么我们可以使用类的实例调用此方法。假设 myNumber
是 MyNumber
类的实例并且 add
是非静态方法,那么我们使用下面给出的实例来调用它。
myNumber::add
要使用方法引用创建Function接口的实例,我们需要创建一个方法声明与抽象方法相同的方法。我们的Function接口 Calculator
中的方法如下。
long calculate(long num1, long num2);
现在我们在实用程序类中创建了两个静态方法 add
和 multiply
,其声明与Function接口的抽象方法相同。找到实用程序类。
实用程序.java
package com.concretepage;
public class Utility {
public static long add(long num1, long num2) {
return num1 + num2;
}
public static long multiply(long num1, long num2) {
return num1 * num2;
}
}
现在使用 Utility
类的静态方法实例化Function接口,如下所示。
Calculator calc = Utility::add;
System.out.println(calc.calculate(30, 50));
输出将是 80。
使用方法参考将Function接口作为方法参数传递:
现在让我们使用带有方法引用的 MyNumber
类。我们已经在上面创建了 MyNumber
类及其对象列表。现在找到使用方法参考。首先,我们使用实用程序 add
方法。
for(MyNumber myNumber: list) {
Calculator calc = Utility::add;
System.out.println(myNumber.process(calc));
}
我们也可以将引用方法直接传递给下面给出的方法。
System.out.println(myNumber.process(Utility::add));
输出
140
360
80
现在我们正在使用实用程序 multiply
方法。
for(MyNumber myNumber: list) {
System.out.println(myNumber.process(Utility::multiply));
}
输出
4000
18000
1200
现在让我们了解上述代码是如何工作的。要理解它,请查看 MyNumber
类的 process
方法的定义。
public long process(Calculator calc) {
return calc.calculate(this.firstNum, this.secondNum);
}
当我们调用 process(Utility::add)
和 process(Utility::multiply)
时,我们的Function接口 Calculator
分别使用 Utility
类的 add
和 multiply
方法的定义来实例化。当使用给定参数调用 calculate
方法时,我们会得到结果。
在这里,我们将使用构造函数引用实例化一个Function接口。我们需要使用 new
关键字作为构造函数引用。查找 Utility
类的构造函数参考。
Utility::new
我们知道构造函数没有返回类型。因此,我们将创建一个具有抽象方法的Function接口,该方法没有返回类型,但具有与构造函数相同数量的参数和类型。找到一个Function接口。
TaskHandler.java
package com.concretepage;
@FunctionalInterface
public interface TaskHandler {
void get(String tname);
}
我们在 Utility
类中创建了构造函数,如下所示。
实用程序.java
public class Utility {
public Utility(String taskName) {
System.out.println(taskName);
}
------
}
现在让我们实例化我们的Function接口并运行它。
TaskHandler taskHandler = Utility::new;
taskHandler.get("Task 1");
输出将是“任务 1”。
我们可以在Function接口中创建默认方法。找到Function接口Worship
。
崇拜.java
package com.concretepage;
import java.util.Objects;
@FunctionalInterface
public interface Worship {
void chant(String name);
default Worship again(Worship w) {
return (name) -> {
Objects.requireNonNull(w);
chant(name);
w.chant(name);
};
}
}
我们创建了一个名为 again
的默认方法。参数的类型是 Worship
本身。返回类型也是 Worship
。现在我们必须定义我们的默认方法。由于默认方法返回 Worship
,我们需要返回一个定义其抽象方法的函数,即 chant
。现在查看默认方法的定义。
default Worship again(Worship w) {
return (name) -> {
Objects.requireNonNull(w);
chant(name);
w.chant(name);
};
}
Objects.requireNonNull
检查指定的对象引用不为空。在上面的代码中,方法 chant(name)
是调用者 Worship
实例的方法。 w.chant(name)
属于参数 Worship
实例。如果我们多次调用 again
方法,结果将被链接。现在让我们运行这个例子。
Worship worship = (name) -> System.out.println(name);
worship.again(worship).again(worship).chant("Ram");
输出
Ram
Ram
Ram
现在让我们通过一些更改来实例化 Worship
,然后运行它。
Worship worship = (name) -> {
System.out.println(name);
System.out.println(name);
};
worship.again(worship).again(worship).chant("Ram");
输出
Ram
Ram
Ram
Ram
Ram
Ram
我们将在这里创建一些带有泛型的Function接口。我们还将添加默认方法来使用这些Function接口。
Function接口一:
DataCombiner.java
package com.concretepage;
@FunctionalInterface
public interface DataCombiner<T> {
String combine(T t);
}
Function接口二:
ExtraInfoProvider.java
package com.concretepage;
@FunctionalInterface
public interface ExtraInfoProvider<R> {
R provideMore(R r);
}
Function界面3:
现在找到将在其默认方法中使用 DataCombiner
和 ExtraInfoProvider
的 InfoProvider
Function接口。
InfoProvider.java
package com.concretepage;
import java.util.Objects;
@FunctionalInterface
public interface InfoProvider<T, R> {
R provide(T t);
default InfoProvider<T, R> addMore(ExtraInfoProvider<R> more) {
return (T t) -> {
Objects.requireNonNull(more);
R r = provide(t);
return more.provideMore(r);
};
}
default DataCombiner<T> addCombiner(DataCombiner<R> combiner) {
return (T t) -> {
Objects.requireNonNull(combiner);
return combiner.combine(provide(t));
};
}
}
在上面的代码中,我们创建了一个抽象方法 provide
和两个默认方法 addMore
和 addCombiner
。默认方法 addMore
是返回 InfoProvider
,所以在 addMore
中我们将返回 InfoProvider
函数接口的 provide
抽象方法的函数定义。 Objects.requireNonNull
检查指定的对象引用不为空。
在 addCombiner
方法中,我们返回的是 DataCombiner
,所以在这个方法中,我们将返回 DataCombiner
函数接口的抽象方法 combine
的函数定义。
假设我们有两个类 Employee
和 Project
,如下所示。
项目.java
public class Project {
private String pname;
private String teamLead;
private String location;
public Project(String pname, String teamLead) {
this.pname = pname;
this.teamLead = teamLead;
}
//getters and setters
}
员工.java
public class Employee {
private int id;
private String name;
public Employee(int id, String name) {
this.id = id;
this.name = name;
}
//getters and setters
}
现在我们将使用 lambda 表达式初始化我们的函数式接口。初始化 DataCombiner
、ExtraInfoProvider
、InfoProvider
并运行它。
DataCombiner<Project> dataCombiner = (Project p) -> {
if(p.getLocation() == null) {
return p.getPname()+" : " + p.getTeamLead();
} else {
return p.getPname()+" : " + p.getTeamLead() + " : " + p.getLocation();
}
};
InfoProvider<Employee, Project> infoProvider = (Employee emp) -> {
if(emp.getId() > 100) {
return new Project("ABCD", emp.getName());
} else {
return new Project("PQRS", emp.getName());
}
};
InfoProvider<Employee, Project> infoProvider = (Employee emp) -> {
if(emp.getId() > 100) {
return new Project("ABCD", emp.getName());
} else {
return new Project("PQRS", emp.getName());
}
};
String s = infoProvider.addMore(extraInfoProvider)
.addCombiner(dataCombiner).combine(new Employee(50, "Mahesh"));
System.out.println(s);
输出
PQRS : Mahesh : Noida
我们可以通过继承现有的接口来创建Function接口。假设我们有如下Function接口。
DataCombiner.java
package com.concretepage;
@FunctionalInterface
public interface DataCombiner<T> {
String combine(T t);
}
现在我们将通过扩展 DataCombiner
并添加一个默认方法来创建 DataReceiver
Function继承。
DataReceiver.java
package com.concretepage;
import java.util.Objects;
@FunctionalInterface
public interface DataReceiver<T> extends DataCombiner<T> {
default void receive(TaskHandler handler, T t) {
Objects.requireNonNull(handler);
handler.get(combine(t));
}
}
在默认方法 receive
中,我们传递了 TaskHandler
Function接口。 找到 TaskHandler
。
TaskHandler.java
package com.concretepage;
@FunctionalInterface
public interface TaskHandler {
void get(String tname);
}
实例化 DataReceiver
和 TaskHandler
然后运行它。
DataReceiver<Employee> dataReceiver = (Employee emp) -> emp.getId() + "-" + emp.getName();
TaskHandler tskHandler = (res) -> System.out.println(res);
dataReceiver.receive(tskHandler, new Employee(101, "Krishna"));
输出
101-Krishna
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://www.concretepage.com/java/java-8/java-functional-interface
内容来源于网络,如有侵权,请联系作者删除!