Java 8中的方法参考
介绍
到目前为止,添加到Java中最甜的语法糖肯定是Lambda Expressions。
Java是一种冗长的语言,会妨碍生产率和可读性。减少样板代码和重复性代码一直是Java开发人员的热门任务,并且通常追求简洁,可读,简洁的代码。
对于一些常见任务,Lambda Expressions消除了键入繁琐的样板代码的需要,它允许开发人员在不属于类的情况下调用它们并将它们像对象一样传递。
这些表达式在Java Streams API和Spring的WebFlux框架中主要用于创建反应性,动态应用程序。
Java 8中另一个真正有用的功能是方法引用,它使Lambda Expressions更加简洁明了,方法是:在使用Lambda Expression仅用于调用a时,使用方法名称调用(引用)方法。方法。
方法参考
方法引用实质上是缩短的Lambda表达式,用于调用方法。
它们包括两个部分:
Class::method;
常见的示例是打印出说结果,例如订阅发布者服务或Java Stream:
someCodeChain.subscribe(System.out::println);
让我们看一下命令式代码的示例,然后我们将通过Lambda表达式转向功能代码,最后通过方法引用进行缩短。
我们将做一个简单的类:
public class Employee {
private int id;
private String name;
private int wage;
private String position;
// Constructor, getters and setters
@Override
public String toString() {
return "Name: " + name + ", Wage: " + wage + ", Position: " + position;
}
public int compareTo(Employee employee) {
if (this.wage <= employee.wage) {
return 1;
} else {
return -1;
}
}
}
如果我们将该类形成一个集合,例如ArrayList
,我们将无法使用实用程序方法对其进行排序,.sort()
因为它没有实现Comparable
接口。
我们可以做的是new Comparator
在调用.sort()
方法时为这些对象定义一个:
Employee emp1 = new Employee(1, "David", 1200, "Developer");
Employee emp2 = new Employee(2, "Tim", 1500, "Developer");
Employee emp3 = new Employee(3, "Martha", 1300, "Developer");
ArrayList<Employee> employeeList = new ArrayList<>();
employeeList.add(emp1);
employeeList.add(emp2);
employeeList.add(emp3);
Collections.sort(employeeList, new Comparator<Employee>() {
public int compare(Employee emp1, Employee emp2) {
return emp1.compareTo(emp2);
}
});
System.out.println(employeeList);
运行此代码将产生:
[Name: Tim, Wage: 1500, Position: Developer, Name: Martha, Wage: 1300, Position: Developer, Name: David, Wage: 1200, Position: Developer]
在此,匿名类(Comparator
)正在定义比较条件。通过使用Lambda表达式,我们可以使其更简单,更短:
Collections.sort(employeeList, (e1, e2) -> e1.compareTo(e2));
运行这段代码将产生:
[Name: Tim, Wage: 1500, Position: Developer, Name: Martha, Wage: 1300, Position: Developer, Name: David, Wage: 1200, Position: Developer]
再说一次,由于我们对Lambda表达式所做的全部工作都称为一个方法,因此我们只能引用该方法:
Collections.sort(employeeList, Employee::compareTo);
这还将产生:
[Name: Tim, Wage: 1500, Position: Developer, Name: Martha, Wage: 1300, Position: Developer, Name: David, Wage: 1200, Position: Developer]
方法参考类型
方法引用可以在两种不同的情况下使用:
- 静态方法:
Class::staticMethodName
- 特定对象的实例方法:
object::instanceMethodName
- 仲裁对象的实例方法:
Class::methodName
- 构造函数参考:
Class::new
让我们通过一些简单的示例来研究所有这些类型。
静态方法参考
您可以static
通过简单地用方法名称调用其包含类来引用类的任何方法。
让我们用static
方法定义一个类,然后从另一个类中引用它:
public class ClassA {
public static void raiseToThePowerOfTwo(double num) {
double result = Math.pow(num, 2);
System.out.println(result);
}
}
现在,从另一个类中,让我们使用static
实用程序方法:
public class ClassB {
public static void main(String[] args) {
List<Double> integerList = new ArrayList<>();
integerList.add(new Double(5));
integerList.add(new Double(2));
integerList.add(new Double(6));
integerList.add(new Double(1));
integerList.add(new Double(8));
integerList.add(new Double(9));
integerList.forEach(ClassA::raiseToThePowerOfTwo);
}
}
运行这段代码将产生:
25.0
4.0
36.0
1.0
64.0
81.0
有许多Java类提供static
可以在此处使用的实用程序方法。在我们的示例中,我们使用了一种自定义方法,尽管在这种情况下不是一个非常有用的方法。
特定对象的实例方法
通过使用对象的引用变量引用该方法,可以从特定的实例化对象调用方法。
订阅我们的新闻
在收件箱中获取临时教程,指南和作业。从来没有垃圾邮件。随时退订。
订阅电子报
订阅
这通常通过自定义比较器进行说明。我们将使用Employee
之前的相同类和相同的列表来突出显示两者之间的区别:
public class Employee {
private int id;
private String name;
private int wage;
private String position;
// Constructor, getters and setters
@Override
public String toString() {
return "Name: " + name + ", Wage: " + wage + ", Position: " + position;
}
public int compareTo(Employee employee) {
if (this.wage <= employee.wage) {
return 1;
} else {
return -1;
}
}
}
现在,让我们定义一个CustomComparator
:
public class CustomComparator {
public int compareEntities(Employee emp1, Employee emp2) {
return emp1.compareTo(emp2);
}
}
最后,让我们填充一个列表并对其进行排序:
Employee emp1 = new Employee(1, "David", 1200, "Developer");
Employee emp2 = new Employee(2, "Tim", 1500, "Developer");
Employee emp3 = new Employee(3, "Martha", 1300, "Developer");
ArrayList<Employee> employeeList = new ArrayList<>();
employeeList.add(emp1);
employeeList.add(emp2);
employeeList.add(emp3);
// Initializing our CustomComparator
CustomComparator customComparator = new CustomComparator();
// Instead of making a call to an arbitrary Employee
// we're now providing an instance and its method
Collections.sort(employeeList, customComparator::compareEntities);
System.out.println(employeeList);
运行此代码还将产生:
[Name: Tim, Wage: 1500, Position: Developer, Name: Martha, Wage: 1300, Position: Developer, Name: David, Wage: 1200, Position: Developer]
主要区别在于,通过添加了另一层,CustomComparator
我们可以添加更多功能进行比较并将其从类本身中删除。诸如此类的类Employee
不应承受复杂的比较逻辑的负担,这将导致更清晰,更易读的代码。
另一方面,有时我们不希望定义自定义比较器,而引入一个比较器简直太麻烦了。在这种情况下,我们将从特定类型的任意对象中调用方法,如下一节所示。
任意对象的实例方法
当我们将命令式方法通过Lambda Expressions分解为功能性方法时,该示例已在本文开头显示。
不过,从良好的角度来看,由于这种方法的使用频率很高,因此让我们来看另一个示例:
List<Integer> integerList = new ArrayList<>();
integerList.add(new Integer(5));
integerList.add(new Integer(2));
integerList.add(new Integer(6));
integerList.add(new Integer(1));
integerList.add(new Integer(8));
integerList.add(new Integer(9));
// Referencing the non-static compareTo method from the Integer class
Collections.sort(integerList, Integer::compareTo);
// Referencing static method
integerList.forEach(System.out::print);
运行这段代码将产生:
125689
虽然这可能看起来像它一样的静态方法的调用,它不是。这等效于调用Lambda表达式:
Collections.sort(integerList, (Integer a, Integer b) -> a.compareTo(b));
在这里,区别更加明显。如果我们要调用一个static
方法,它将看起来像:
Collections.sort(integerList, (Integer a, Integer b) -> SomeClass.compare(a, b));
引用构造函数
您可以像引用static
方法一样引用类的构造函数。
您可以使用对构造函数的引用,而不是经典的类实例化:
// Classic instantiation
Employee employee = new Employee();
// Constructor reference
Employee employee2 = Employe::new;
根据上下文,如果存在多个构造函数,则在引用时将使用足够的构造函数:
Stream<Employee> stream = names.stream().map(Employee::new);
由于名称流,如果存在Employee(String name)
构造函数,则将使用它。
可以使用构造函数引用的另一种方式是,当您想要将流映射到数组中时,同时保留特定的类型。如果要简单地映射它,然后调用toArray()
,则会得到Object
s数组,而不是您的特定类型。
如果我们尝试过,请说:
Employee[] employeeArray = employeeList.toArray();
当然,由于.toArray()
返回Object
s数组,因此会遇到编译器错误。投射它也无济于事:
Employee[] employeeArray = (Employee[]) employeeList.toArray();
但是这次,它将是运行时异常- ClassCastException
。
我们可以通过以下方法避免这种情况:
// Making a list of employees
List<String> employeeList = Arrays.asList("David", "Scott");
// Mapping a list to Employee objects and returning them as an array
Employee[] employeeArray = employeeList.stream().map(Employee::new).toArray(Employee[]::new);
// Iterating through the array and printing information
for (int i = 0; i < employeeArray.length; i++) {
System.out.println(employeeArray[i].toString());
}
这样,我们得到输出:
Name: David, Wage: 0, Position: null
Name: Scott, Wage: 0, Position: null
结论
方法引用是Lambda表达式的一种,用于在调用中简单地引用方法。使用它们,编写代码可以更加简洁和可读。
Lambda Expressions向Java开发人员介绍了一种更具功能性的编程方法,该方法允许他们避免为简单操作编写冗长的代码。
发布于 2021-01-09 16:16