我正在学习Java 8中的lambda表达式。有人可以向我解释如何将lambda表达式与只有一种方法的抽象类一起使用(如果可能的话)?
例如,这是抽象类:
public abstract class ClassA {
public abstract void action();
}
我有另一个类在其构造函数中使用ClassA
:
public ClassB {
public ClassB(String text, ClassA a){
//Do stuff
}
}
所以我想知道如何写这样的东西:
ClassB b = new ClassB("Example", new ClassA(() -> System.out.println("Hello")));
显然该语句不起作用,但有没有办法在这里使用lambda表达式?如果有的话,我做错了什么?
答案 0 :(得分:13)
不,您无法实现此目的,因为ClassA
必须是功能界面。功能接口是一个只包含一个抽象方法的接口。除抽象方法外,它可以包含零个或多个默认方法和/或静态方法。由于功能接口只包含一个抽象方法,因此在使用lambda表达式实现该方法时,可以省略该方法的名称。例如,请考虑以下界面:
interface Predicate<T> {
boolean test(T t);
}
此接口的目的是提供一个对类T
的对象进行操作并返回boolean
的方法。您可以使用一个方法来获取实现此接口的类实例,如下所示:
public void printImportantData(ArrayList<Data> dataList, Predicate<Data> p) {
for (Data d : dataList) {
if (p.test(d)) {
System.out.println(d);
}
}
}
其中Data
类可以简单如下:
public class Data {
public int value;
}
现在,您可以按如下方式调用上述方法:
printImportantData(al, (Data d) -> { return d.value > 1; });
请注意,此方法在此处没有名称。这是可能的,因为接口只有一个抽象方法,因此编译器可以找出名称。这可以缩短为:
printImportantData(al, (Data d) -> d.value > 1);
请注意,这里没有花括号,也没有return关键字。这是可能的,因为该方法返回一个布尔值,表达式d.value > 1
也返回一个布尔值。因此,编译器能够确定要从方法返回此表达式的值。这可以更加缩短为:
printImportantData(al, d -> d.value > 1);
请注意,d
没有类型声明!编译器可以找出它需要的所有信息,因为接口只有一个抽象方法,并且该方法只有一个参数。因此,您无需在代码中编写所有这些内容
使用内部类将上述方法与旧的Java 7样式进行比较,该内部类有效地执行相同的操作:
printImportantData(al, new Predicate<Data>() {
public boolean test(Data d) {
return d.value > 1;
}
});
答案 1 :(得分:4)
您只能使用lambda表达式实例化一个功能接口。
例如:
如果您将ClassA
更改为界面(您可能想要重命名):
public interface ClassA {
public abstract void action();
}
并按原样保留ClassB
:
public class ClassB {
public ClassB(String text, ClassA a){
//Do stuff
}
}
您可以将(接口)ClassA
的实例传递给ClassB
构造函数:
ClassB b = new ClassB("Example", () -> System.out.println("Hello"));
另一方面,你的
ClassB b = new ClassB("Example", new ClassA(() -> System.out.println("Hello")));
由于以下几个原因,尝试失败:
ClassA
(如果它不是抽象的),您的ClassA
也没有构造函数将某个函数接口作为参数,因此您不能这样做将() -> System.out.println("Hello")
作为参数传递给ClassA
的构造函数。 答案 2 :(得分:1)
好吧,你可以改变你的类,以便能够按照这些方式写一些东西:
public static void main(String[] args) {
ClassB b = new ClassB("Example", new ClassA(() -> System.out.println("Hello")) {
@Override
public void action() {
}
});
}
但为此,您需要更改ClassA
的构造函数以接受函数接口的某些实现,例如java.lang.Runnable
:
public abstract class ClassA {
public ClassA(Runnable runnable) {
runnable.run();
}
public abstract void action();
}
class ClassB {
public ClassB(String text, ClassA a) {
//Do stuff
}
}
当然,您仍然需要在ClassA
中实现抽象方法,请参阅上面的示例。