通用功能接口使用Consumer的简单示例

时间:2017-04-26 01:26:05

标签: java generics functional-interface

我正在尝试编写一个接受功能接口的泛型方法。见例子。任何帮助表示赞赏。

更新:编译并运行。对改进或澄清的意见或建议感兴趣。

我不会创建一个Typed Abstract Base Class。在repeat方法中添加一个额外的参数,指定执行命令的机器人似乎与其他类似的示例更加一致。

思想?

import java.util.function.Consumer;

/**
 * The intent is to create a generic function repeat() in the Robot base class
 * that will repeat actions for all subclasses of robots
 */
public class GenericFunctionalInterface
{
    public static void main(String[] args)
    {
        // Consumer<Robot> actionTurn = Robot::turnLeft;
        // Consumer<EnhancedRobot> anyAction = EnhancedRobot::anyAction;

        Robot r = new Robot();
        r.repeat(3, a->a.turnLeft() );

        EnhancedRobot e = new EnhancedRobot();
        e.repeat(3, a->a.anyAction() ); // cannot find symbol - method anyAction()
        // if ((EnhancedRobot)a).anyAction() is used this works
    }
}

class Robot 
{
    public void move() { System.out.println("MOVE"); }

    public void turnLeft() { System.out.println("TURNLEFT"); }

    public <T extends Robot> void repeat(int n, Consumer<T> cmd )
    {
        for(int i=0; i<n; i++) cmd.accept( (T) this); // UPDATED: casting this to T removed -> incompatible types: Robot cannot be converted to T
        // this will be whatever type repeat is called on
    } 

    // added this override - specifying what robot to send the command to
    public <T extends Robot> void repeat(int n, Consumer<T> cmd, T robot )
    {
        for(int i=0; i<n; i++) cmd.accept( robot );
    } 

}

class EnhancedRobot extends Robot
{
    public void turnRight() { System.out.println("TURNRIGHT"); }

    public void move() {  System.out.println("MOVEOVERIDE"); }

    public void anyAction() { System.out.println("ANYACTION"); }
}    

3 个答案:

答案 0 :(得分:1)

对于e.repeat()问题:假设您有以下代码:

class SuperRobot extends Robot {}

EnhancedRobot e = new EnhancedRobot();
e.repeat(3, new Consumer<SuperRobot>() {
  @Override
  public void accept(SuperRobot t) {
    // ...
  }
});

然后在想要调用的重复方法内:

Consumer<T> cmd;
cmd.accept(this);

这会失败,因为this属于EnhancedRobot类型,但cmd期望得到SuperRobot。这就是你不能在那里打电话的原因。

存在a.anyAction()问题,因为a类型为Robot,但没有anyAction()方法。从声明(T extends Robot),关于其类型的唯一安全假设是Robot或扩展它的东西。因此,您无法从EnhancedRobot上调用方法。

答案 1 :(得分:1)

您需要以Robot的方式将Consumer的{​​{1}}类型参数化Enum,并添加返回适当类型{{1}的方法(这要求this是抽象的,因为任何默认实现都必须错误地返回Robot)。

null

稍微更一般地说,我认为你可以将abstract class Robot<THIS extends Robot<THIS>> { ... public void repeat(int n, Consumer<THIS> cmd) { for (int i=0; i<n; i++) { cmd.accept(getThis()); } } protected abstract THIS getThis(); } class EnhancedRobot extends Robot<EnhancedRobot> { @Override protected abstract EnhancedRobot getThis() { return this; } ... } 声明为

repeat

答案 2 :(得分:0)

在更新的代码中,repeat方法不使用您正在调用方法的Robot实例。所以方法可以是static

// added this override - specifying what robot to send the command to
public static <T extends Robot> void repeat(int n, Consumer<T> cmd, T robot )
{
    for(int i=0; i<n; i++) cmd.accept( robot );
} 

一样被调用
EnhancedRobot e = new EnhancedRobot();
Robot.repeat(3, a->a.anyAction(), e );

但是robot方法不需要repeat参数。您可以将其声明为

public static void repeat(int n, Runnable cmd)
{
    for(int i=0; i<n; i++) cmd.run();
}

一样被调用
EnhancedRobot e = new EnhancedRobot();
Robot.repeat(3, () -> e.anyAction());

显示了设计的实际问题。重复操作是否与Robot实例相关,与repeat方法的逻辑无关。试图通过通用签名来强制执行这种关系会产生问题而没有任何好处。

事实上,已经存在允许重复的通用工具。例如,你可以写

EnhancedRobot e = new EnhancedRobot();
Collections.nCopies(3, e).forEach(EnhancedRobot::anyAction);

EnhancedRobot e = new EnhancedRobot();
IntStream.range(0, 3).forEach(i -> e.anyAction());