Java 8 Lambdaexpression式 – 嵌套类中的多个方法

我正在阅读有关新function: http : //www.javaworld.com/article/2078836/java-se/love-and-hate-for-java-8.html

我看到下面的例子:

使用匿名类:

button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { System.out.println("Action Detected"); } }); 

随着Lambda:

 button.addActionListener(e -> { System.out.println("Action Detected"); }); 

如果他们想要在匿名类中实现多个方法,有人会用MouseListener做什么,例如:

 public void mousePressed(MouseEvent e) { saySomething("Mouse pressed; # of clicks: " + e.getClickCount(), e); } public void mouseReleased(MouseEvent e) { saySomething("Mouse released; # of clicks: " + e.getClickCount(), e); } 

… 等等?

来自JLS 9.8

function接口是一个只有一个抽象方法的接口,因此代表一个单一的function合同。

Lambda需要这些function接口,因此仅限于单一方法。 匿名接口仍然需要用于实现多方法接口。

 addMouseListener(new MouseAdapter() { @Override public void mouseReleased(MouseEvent e) { ... } @Override public void mousePressed(MouseEvent e) { ... } }); 

您可以使用帮助程序接口与lambdaexpression式一起使用多方法接口。 这适用于这样的监听器接口,其中不需要的方法的实现是微不足道的(即我们可以做什么MouseAdapter提供):

 // note the absence of mouseClicked… interface ClickedListener extends MouseListener { @Override public default void mouseEntered(MouseEvent e) {} @Override public default void mouseExited(MouseEvent e) {} @Override public default void mousePressed(MouseEvent e) {} @Override public default void mouseReleased(MouseEvent e) {} } 

你只需要定义一个这样的辅助接口一次。

现在,您可以为Component c添加一个监听器,如下所示:

 c.addMouseListener((ClickedListener)(e)->System.out.println("Clicked !")); 

Lambda EG确实考虑过这个问题。 许多库使用function接口,即使它们是在function接口成为事物之前几年devise的。 但是有时确实有一个类有多个抽象方法,你只想用lambda来定位其中的一个。

这里正式推荐的模式是定义工厂方法:

 static MouseListener clickHandler(Consumer<MouseEvent> c) { return ... } 

这些可以由API本身直接完成(这些可以是MouseListener静态方法),也可以是其他库中的外部辅助方法,如果维护者select不提供这种便利。 由于需要的情况很less,解决方法如此简单,因此似乎没有必要进一步扩展语言来解决这个问题。

ThreadLocal采用了类似的技巧; 请参阅withInitial(Supplier<S>)的新静态工厂方法。

(顺便说一下,当这个问题出现时,这个例子几乎总是MouseListener ,这是令人鼓舞的,因为它暗示了一组希望是lambda友好的类,但是不是,实际上非常小。

Java ActionListener必须只实现一个方法( actionPerformed(ActionEvent e) )。 这很适合Java 8的function,所以Java 8提供了一个简单的lambda来实现一个ActionListener

MouseAdapter至less需要两个方法,因此不适合作为function

Lambdaexpression式适合于函数接口必须包含一个抽象方法声明

缺省方法不能从lambdaexpression式中访问。 下面的代码不能编译:

 interface Formula { double calculate(int a); default double sqrt(int a) { return Math.sqrt(a); } } Formula formula = (a) -> sqrt( a * 100); 

只能使用function接口(仅限单一抽象方法+任意数量的默认方法),所以lambdaexpression式只能用抽象方法工作