【问题标题】:What is best technique to pass big count of arguments to Java class?将大量参数传递给 Java 类的最佳技术是什么?
【发布时间】:2013-08-12 21:00:46
【问题描述】:

我有非标准问题。

假设我有类MyClass,我从命令行执行带有参数列表的类

[<key> <value>]

喜欢:

MyClass -key1 arg1 -key2 arg2 -key3 arg3 ... -keyN argN.

因此,我的班级遵循将输入数据传递给文件的方法:

public class MyClass{

private static String arg1;
private static String arg2;
private static String arg3;
...
private static String argN;

private static void getArgs(String[] args) {
    for(int k=0; k<args.length; k=k+2){
        if(args[k].equals("-key1")){ 
            arg1 = args[k+1];                 
        }
        else if(args[k].equals("-key2")){ 
            arg2 = args[k+1];                 
        }   
        else if(args[k].equals("-key3")){ 
            arg3 = args[k+1];                 
        }

                    ...

        else if(args[k].equals("-keyN")){ 
            argN = args[k+1];                 
        }
    }   
}

我编写自动化程序,大约有 30-40 个MyClass,其中每个都有 10-30 个参数。

所有类都有相同的字段和不同的字段 (50/50)。

我不喜欢private static void getArgs(String[] args)的方法实现,好像很浪费时间。

我虽然在 Notepad++ 中编写了一些基于 Reg-ex 的脚本并生成 java 代码,但在我想问是否有人知道其他技术/技术来处理输入参数之前。

[编辑]

我想使用反射,例如:

for(int k=0; k<args.length; k=k+2){
 Field field = classInstance.getClass().getDeclaredField(args[k].substring(1));
 field.setAccessible(true);
 field.set(classInstance, args[k]);
}

谢谢,

【问题讨论】:

  • 如果您只需要涵盖给定的示例,您可能希望创建一个通用的 parse 方法,该方法返回带有键/值的 Map&lt;String, String&gt;
  • 好吧,但是在我需要解析 Map 来提取值之后
  • 您可能需要一个 java getopt 替代方案。看here
  • 您的最后一次编辑更清楚地说明了这一点...您将使用反射为您的所有类节省编码时间,但是,您是否注意到您的字段是static?我宁愿在获取Field 实例后添加一个修饰符检查(以验证它是静态的),然后将该字段作为field.set(null, args[k]); 调用,因为在处理static 成员时没有类的实例。
  • 感谢您的评论,是的,我知道,我可以付出这个代价来切断开发。时间

标签: java


【解决方案1】:

Commons CLI 已经为这个问题提供了一个很好的解决方案。我建议使用它,因为它已经过很好的测试和使用。改造图书馆毫无意义。

【讨论】:

    【解决方案2】:

    老实说,我只是解析它们并将它们放入地图中。 并在需要时使用常量键从映射中获取值:private static final String KEY_FIRSTKEY = "firstkey";

    所以我会简单地编写一个函数parseArgs 将所有内容放在地图中。 (也许这属于实用程序类)。这是一个简单的例子(没有异常处理)

      private static Map<String, String> parseArgs(String... pArgs)
      {
        if (pArgs == null) return null;
    
        Map<String, String> map = new HashMap<String, String>();
        String arg;
        String key;
        String value;
        for (int i = 0, iLength = pArgs.length; i < iLength; i += 2)
        {
          arg = pArgs[i];
    
          // GET KEY
          if (!arg.startsWith("-")) continue;
          key = arg.substring(1);
    
          // GET VALUE
          if ((i + 1) >= pArgs.length) break;
          value = pArgs[i + 1];
    
          // PUT IT IN MAP
          map.put(key, value);
        }
        return (map.isEmpty()) ? null : map;
      }
    

    但是,如果您真的更喜欢将它们放在私有字段中。 然后我建议之后使用一些反射将地图转换为字段。 这是一个例子:

      private static void mapStaticFields(Map<String, String> pMap, Class pStaticFieldHolder)
              throws NoSuchFieldException
      {
        if (pMap == null) return;
        for (Map.Entry<String, String> entry : pMap.entrySet())
        {
          try
          {
            Field field = pStaticFieldHolder.getDeclaredField(entry.getKey());
            field.setAccessible(true);
            field.set(field, entry.getValue());
          }
          catch (IllegalAccessException iae)
          {
            // impossible
          }
        }
    }
    

    举个例子:

    import java.lang.reflect.Field;
    import java.util.HashMap;
    import java.util.Map;
    
    public class MainTest
    {
      private static String key1;
      private static String key2;
      private static String key3;
    
      public static void main(String... pArgs)
      {
        try
        {
          Map<String, String> argMap = parseArgs(pArgs);
          mapStaticFields(argMap, MainTest.class);
    
          System.out.println(key1);
          System.out.println(key2);
          System.out.println(key3);
        }
        catch (Exception e)
        {
          e.printStackTrace();
        }
      }
    }
    

    从命令行调用它为java MainTest -key1 val1 -key2 val2 -key3 val3 将产生以下输出:

    val1
    val2
    val3
    

    享受吧!

    【讨论】:

    • 谢谢,这实际上是我所做的,但你的例子表明我采取了正确的方式
    【解决方案3】:

    从参数列表构建 Map 应该很简单:

    Map<String, String> map = new HashMap<>();
    for (i=0; i < args.length-1; i+=2) {
         map.put(args[i], args[i+1];
    }
    

    然后你可以像这样初始化你的参数:

    String arg1 = map.get("-key1");
    ...
    

    【讨论】:

      【解决方案4】:

      当需要提供的参数很少时,将运行时参数传递给 java 程序很方便。但不是在有大量参数要传递给程序的情况下。我建议您不要使用命令行参数来提供您的信息,而应该使用属性文件。对您有利的是,Properties 文件还将数据保存在键值对中,这对您的要求更有意义。另外使用javaProperties类从文件中读取值也很方便。

      如果您需要,您可以将属性文件名(带有完整路径)作为参数传递给您的 java 类。

      【讨论】:

      • 当然我可以传递Properties 文件,但之后我需要使用ResourceBundle 并提取所有数据。这也是额外的任务。我想去反射方向。
      • @MaximShoustin 资源包不是以属性文件的形式保存的,我相信是的。此链接应该可以帮助您满足您的需求:docs.oracle.com/javase/tutorial/i18n/resbundle/propfile.html
      • 感谢链接,我有基于参数的自动化核心,我总共有大约 300-400 个 java 类,我无法更改基础设施来处理属性,无论如何谢谢
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-22
      • 1970-01-01
      • 2022-12-05
      • 1970-01-01
      • 2017-04-11
      • 1970-01-01
      相关资源
      最近更新 更多