尝试在Java中使用lambdas做一个小型重构

时间:2016-02-24 04:16:21

标签: java lambda java-8 anonymous-function anonymous-methods

我正在研究程序的一部分(关于语音识别和遥控车),其中代码transmit(XXXXX); disableAutoMode();重复多次。出于好奇心的缘故,我想将其转换为类似于var f = p -> transmit(p); disableAutoMode();的lambda函数(原谅var;我不知道表达式的类型是什么)然后在一个函数中调用它类似于此的方式:f("s");f("a");f("f");或与f.call("s");f.call("a");f.call("f");类似的内容。

在Java中使用简单的lambda函数的正确语法是什么,类似于我上面描述的? (我应该把它放在什么类型而不是说var?)

以下是代码块,如果你很好奇:

@Override
public void onResult(Hypothesis hypothesis) {
    if (hypothesis != null) {
        String text = hypothesis.getHypstr();
        Log.i("onresult",text);
        ToastMaster(text);

        switch (text) {
            case "forward":
            case "go forward":
                transmit("f");
                disableAutoMode();
                break;
            case "go back":
            case "go backward":
            case "back":
            case "backward":
            case "reverse":
                transmit("b");
                disableAutoMode();
                break;
            case "skid left":
            case "go left":
                transmit("l");
                disableAutoMode();
                break;
            case "skid right":
            case "go right":
                transmit("r");
                disableAutoMode();
                break;
            case "turn left":
                transmit("q");
                disableAutoMode();
                break;
            case "turn right":
                transmit("e");
                disableAutoMode();
                break;
            case "reverse left":
                transmit("z");
                disableAutoMode();
                break;
            case "reverse right":
                transmit("x");
                disableAutoMode();
                break;
            case "stop":
                disableAutoMode();
                break;
            case "automatic":
                toggleAutoMode(null);
                break;
            case "enable automatic mode":
                enableAutoMode();
                break;
            case "disable automatic mode":
                disableAutoMode();
                break;
        }
    }
}

4 个答案:

答案 0 :(得分:8)

更加雄心勃勃的重构将建立在将代码转换为数据的基础之上。 lambdas的所有原则,将switch语句从代码转换为数据。怎么样:

// One-time setup of the machine
Map<String, Consumer<String>> actions = new HashMap<>();
actions.put("go forward", x -> { transmit(x); disableAutoMode(); });
actions.put(...)
...

public void onResult(Hypothesis hypothesis) {
    if (hypothesis != null) {
        String text = hypothesis.getHypstr();
        Log.i("onresult",text);
        ToastMaster(text);

        Consumer<String> action = actions.get(text);
        if (action != null)
            action.accept(text);
    }
}

答案 1 :(得分:3)

在这种情况下,您需要Consumer

Consumer<String> function = (x) -> { transmit(x); disableAutoMode(); };
function.accept("hello!");

但是我不确定你为什么要在这里使用lambda表达式,你可以创建一个普通的旧方法并调用它。

如果您使用的是更有意义的重构,则可以选择切换到StringAction/Runnable的地图。虽然你最终会得到更多的代码,但重构的目标不是使它变得更小&#34;但要使其更具可读性/可维护性。通过将每个动作分成它自己的小型自包含类,每个动作都可以通过最少的设置进行单独测试。每个动作都可以重复使用(因为它只是一个类)。通过良好的命名策略,读者可以清楚地知道发生了什么,而无需深入了解大型switch语句。

答案 2 :(得分:2)

调用lambda比使用简单的辅助方法更乏味:

private void m(String x) {
    transmit(x);
    disableAutoMode();
}

(更详细)替代方案是使用lambdas:

Consumer<String> consumer = (x) -> {
    transmit(x);
    disableAutoMode();
};

然后将其称为

consumer.accept("f");

答案 3 :(得分:0)

你想做什么,确实可以使用lambda表达式,但保存不会那么大:

@Override
public void onResult(Hypothesis hypothesis) {
    if (hypothesis != null) {
        String text = hypothesis.getHypstr();
        Log.i("onresult",text);
        ToastMaster(text);

        Consumer<String> transmitDisable=s->{ transmit(s); disableAutoMode(); };
        switch (text) {
            case "forward": case "go forward":
                transmitDisable.accept("f");
                break;
            case "go back":  case "go backward": case "back":
            case "backward": case "reverse":
                transmitDisable.accept("b");
                break;
            case "skid left": case "go left":
                transmitDisable.accept("l");
                break;
            case "skid right": case "go right":
                transmitDisable.accept("r");
                break;
            case "turn left":     transmitDisable.accept("q"); break;
            case "turn right":    transmitDisable.accept("e"); break;
            case "reverse left":  transmitDisable.accept("z"); break;
            case "reverse right": transmitDisable.accept("x"); break;
            case "stop": disableAutoMode(); break;
            case "automatic": toggleAutoMode(null); break;
            case "enable automatic mode": enableAutoMode(); break;
            case "disable automatic mode": disableAutoMode(); break;
        }
    }
}

但是,如果你考虑Java不常用的代码流控制结构,你也可以删除没有lambda表达式的代码重复:

@Override
public void onResult(Hypothesis hypothesis) {
    if (hypothesis != null) {
        String text = hypothesis.getHypstr();
        Log.i("onresult",text);
        ToastMaster(text);

        transmitAndDisable: {
            final String toTransmit;
            switch (text) {
                case "forward":    case "go forward": toTransmit="f"; break;
                case "go back":    case "go backward": case "back":
                case "backward":   case "reverse":  toTransmit="b"; break;
                case "skid left":  case "go left":  toTransmit="l"; break;
                case "skid right": case "go right": toTransmit="r"; break;
                case "turn left":     toTransmit="q"; break;
                case "turn right":    toTransmit="e"; break;
                case "reverse left":  toTransmit="z"; break;
                case "reverse right": toTransmit="x"; break;

                case "stop": disableAutoMode(); break transmitAndDisable;
                case "automatic": toggleAutoMode(null); break transmitAndDisable;
                case "enable automatic mode": enableAutoMode(); break transmitAndDisable;
                case "disable automatic mode": disableAutoMode(); break transmitAndDisable;
                default: break transmitAndDisable;
            }
            transmit(toTransmit);
            disableAutoMode();
        }
    }
}

结构可能不那么容易理解,但请注意如何将toTransmit声明为final有很大帮助。因为它是final,所以无法使用回退值进行初始化,这意味着获取共享transmit(…); disableAutoMode();代码的每个备选方案都必须将变量初始化一次。

换句话说,

  • 如果您忘记在不打算调用共享代码的情况下transmitAndDisable指定break标签,编译器将立即大喊,因为toTransmit尚未初始化
  • 如果您忘记了其中一个用于调用共享代码的替代方法之间的中断,编译器将立即拒绝该代码,因为它分配toTransmit两次
  • 如果您在用于调用共享代码的案例的transmitAndDisable错误地指定break标签,那么优秀的编译器将发出有关未使用的作业的警告