如何将Java中的开关替换为每个情况引用一个变量的列表?

How can I replace a switch in Java with a list that references a variable for each case?

本文关键字:引用 变量 一个 情况 列表 Java 开关 替换      更新时间:2023-10-16

我在这里找不到这样的问题(这让我很惊讶),所以…

我有一个工作的Java程序,其中一部分分析键入的输入。一些输入'选项'是以下情况下的字符串。

switch (varName.toLowerCase())  {
    case "steps":
        common.steps = true;
        break;
    case "scale":
        common.scale = true;
        break;
    case "float":
        common.fracts = false;
        break;
    case "fraction":
        common.fracts = true;
        break;
    case "spaces":
        common.spaces = false;
        break;
    ... etc.
}

在C或c++中,我可以通过创建一个列表(这是一个包含字符串名称和变量指针的结构)来缩短代码,例如

LIST varAction[] = { { "steps", &common.steps },
                     { "scale", &common.scale },
                     .. etc.
                   };

,然后在I = 0的循环中检查列表

的大小。
if ( strcmp(varAction[i].name, input) == 0)  {
    *varAction[i].pointer = condition;
}

Java切换不止一次,这是一个维护问题,这就是为什么我想要一个更好的方法。

我可以使用字符串的哈希值对数组使用哈希索引,但这会阻止我根据需要在代码中使用特定的变量名,使代码不太清楚……例如,我不想做(伪代码)

hashTable[varName] instead of (for example)  
if ( common.fracts )
     { do something }

一定有更好的办法吧?是吗?

从你的问题中,很明显你知道你不能做你说过你在C/c++中会做的事情,但只是为了其他人来问这个问题:Java没有对变量的引用。

很容易把这个问题推到一个层次:首先看看为什么你有varName,看看你是否可以避免它。

Java切换不止一次,这是一个维护问题,这就是为什么我想要一个更好的方法。

这表明common应该有这个信息的访问函数,所以开关只存在于一个地方(getter)或两个地方(getter和setter)。

void setThingy(String name, boolean value) {
    switch (name.toLowerCase())  {
        case "steps":
            this.steps = value;
            break;
        case "scale":
            this.scale = value;
            break;
        case "float":
            this.fracts = value;
            break;
        case "fraction":
            this.fracts = value;
            break;
        case "spaces":
            this.spaces = value;
            break;
        // ... etc.
    }
}
boolean getThingy(String name) {
    switch (name.toLowerCase())  {
        case "steps":
            return common.steps;
        case "scale":
            return common.scale;
        case "float":
            return this.fracts;
        case "fraction":
            return this.fracts;
        case "spaces":
            return this.spaces;
        // ... etc.
    }
}

如果common的类不是你可以改变的东西,一个静态的实用函数也会在某个地方工作,但如果可能的话,如果它在类中更好。

对于Java 8+,您可以使用如下命令:

Map<String, Runnable> actions = new HashMap<> ();
actions.put("steps", () -> common.steps = true);
actions.put("scale", () -> common.scales = true);
//etc.

然后在你的代码中:

actions.get(varName.toLowerCase()).run(); //need null check

你也可以在Java 7中使用匿名类,但是会更冗长。

这是一个选项,从评论中发展我的想法只是一点点。我不确定你是否会喜欢,但我想提供给你,以防万一。

public class Common {
    private Map<String, Boolean> options = new HashMap<>();
    public void setOption(String varName, boolean condition) {
        options.put(varName.toLowerCase(), condition);
    }
    public boolean isSteps() { return options.get("steps"); }
    public boolean isFracts() { return options.get("fractions"); }
    public boolean isScale() { return options.get("scale"); }
}

您可能需要添加一些防御,例如避免设置不存在的选项。

编辑:根据David Foerster对枚举的评论,这里有一个使用枚举的解决方案:

public enum Option {
    steps, scale, fraction;
    private boolean option = false;
    public static void setOption(String varName, boolean condition) {
        valueOf(varName.toLowerCase()).option = condition;
    }
    public boolean isSet() {
        return option;
    }
}

现在查找发生在setter中,而不是getter中。防止设置不存在的选项是内置的:如果你尝试,你会得到一个异常,当然,如果你愿意,这种行为可以被修改。该解决方案具有很强的可扩展性,如果需要,可以很容易地添加更多的enum常量。

警告:距离我上次编写Java已经有一段时间了,这可能违反了最佳实践,所以请继续小心!这只是一个简单的例子,我在一个(不是最新的)手机上写的…

你可以尝试使用反射:

class Common {
  public boolean a;
  public boolean b;
  public boolean tryToSet(String field, boolean value) throws java.lang.Exception {
    Class<?> cl = this.getClass();
    try {
      Field f = cl.getDeclaredField(field);
      f.setBoolean(this, value);
      return true;
    } catch(NoSuchFieldException e) {
      return false;
    }
  }
}

返回一个布尔值让你有可能实现一个"默认情况":

if (! c.tryToSet("x", false)) {
  System.out.println("some default case");
}

试试这个:

import java.util.Scanner;
public class TestCases 
{
    static boolean steps = false;
    static boolean fracts;
    static boolean scale;
    public static void  main( String[] args ) 
    {
        Scanner input = new Scanner( System.in );
        System.out.println( "Type the input" );
        String typedInput = input.nextLine();
        Object[][] tests = { { "steps", steps }, { "float", fracts }, { "scale", scale } };
        for( int i = 0; i < tests.length; i++ )
        {
            if( typedInput.equals( tests[ i ][ 0 ] ) )
            {
                tests[ i ][ 1 ] = true;
                break;
            }
        }
        for( int i = 0; i < tests.length; i++ )
        {
            for( int j = 0; j < tests[ i ].length; j++ )
            {
                    System.out.print( tests[ i ][ j ] + " " );
            }
            System.out.println();
        }

    }
}

所有必要的转换都自动完成。