【问题标题】:Transform String args[] into an object [closed]将字符串 args [] 转换为对象 [关闭]
【发布时间】:2018-05-09 02:28:35
【问题描述】:

我需要解析命令行参数并将它们转换为 Java 对象。

我运行 Java .jar 的命令行:

java -cp "combo.jar" com.ascurra.Main --time=3 --limit=5000 --initDate=2017-01-01.13:00:00

我需要将参数--time=3 --limit=5000 --initDate=2017-01-01.13:00:00 转换为一个对象并将其保存到我的数据库中。

如何以优雅的方式做到这一点?

【问题讨论】:

  • 我会先努力自己解决这个问题。
  • 查看tutorial 并展示您的尝试

标签: java arguments main


【解决方案1】:

首先,创建一个具有相应字段的类

class Entry {

    private int time;
    private int limit;
    private Date initDate;

    public Entry() {
    }

    public Date getInitDate() {
        return initDate;
    }

    public void setInitDate(Date initDate) {
        this.initDate = initDate;
    }

    public int getLimit() {
        return limit;
    }

    public void setLimit(int limit) {
        this.limit = limit;
    }

    public int getTime() {
        return time;
    }

    public void setTime(int time) {
        this.time = time;
    }

}

然后创建这个类的一个对象并解析参数来设置值

public static void main(String[] args) {

    ArrayList<String> options = new ArrayList<>();
    for (String arg : args) {  // get the options from the arguments
        if (arg.startsWith("--")) {
            options.add(arg.replace("--", ""));
        }
    }
    Entry entry = new Entry();

    for (String option : options) {
        String[] pair = option.split("=");
        if (pair.length == 2) {
            if (pair[0].equals("time")) { // parse time option
                entry.setTime(Integer.parseInt(pair[1])); 
            } else if (pair[0].equals("limit")) { // parse limit option
                entry.setLimit(Integer.parseInt(pair[1]));
            } else if (pair[0].equals("initDate")) { // parse initDate option
                SimpleDateFormat sdf = new SimpleDateFormat(
                        "yyyy-MM-dd.HH:mm:ss");
                try {
                    entry.setInitDate(sdf.parse(pair[1]));
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    System.out.println(entry.getLimit() + " , " + entry.getTime() + " , "
            + entry.getInitDate());
}

【讨论】:

    【解决方案2】:

    我会创建 args 数组的流 map 以保留所需的字符串部分,即:

    String[] resultArray = Arrays.stream(args)
                                 .map(s -> s.substring(s.indexOf("=") + 1))
                                 .toArray(String[]::new);
    

    数组现在应该包含:

    [3, 5000, 2017-01-01.13:00:00]
    

    在这种情况下,您可以对该数组进行索引,然后转换为所需的任何其他类型并填充您的自定义对象。


    或者,由于只有 3 个参数,您可以完全跳过创建流,只需使用 substring 对数组进行索引以保留所需的部分。但是,上面的方法更具适应性,就好像您要输入更多参数一样,就检索参数而言,您无需更改代码中的任何内容。

    【讨论】:

    • 我需要将属性保存在一个对象中才能在另一个时间进入。
    • @MisterB 查看编辑。我已经稍微简化了解决方案,但这是我所能做到的,因为我不知道您在帖子中谈论的 Java 对象的类型。
    【解决方案3】:

    如何以优雅的方式做到这一点?

    这三个信息(--time=3 --limit=5000 --initDate=2017-01-01.13:00:00)在主类的String[] args中作为特定元素传递。
    解析它们确实不是一项复杂的任务(String.substring() 或正则表达式就可以完成这项工作)。
    但是一个好的解析器也应该能够不被参数的顺序所困扰,并且还应该考虑在数据映射到特定类型(如日期或数字类型)期间产生相关的调试信息。
    最后,添加或删除受支持的参数应该既简单又安全,并且还可能需要获得命令帮助。

    因此,首先建议,如果您可以使用库,请不要重新发明轮子并使用 Apache Commons CLI 或更好地使用 arg4j,它使用起来非常简单,避免了样板代码。

    如果你不能,至少从他们那里激励你。

    Apache Commons CLI 示例

    例如创建Options(参数):

    public static final String TIME_ARG = "time";
    public static final String LIMIT_ARG = "limit";
    ...
    
    Options options = new Options();   
    options.addOption("t", TIME_ARG, true, "current time");
    options.addOption("l", LIMIT_ARG, true, "limit of ...");
    ...
    

    然后解析Options 并检索它的值:

    public static void main(String[] args) {
    
      ...
      try{
        CommandLineParser parser = new DefaultParser();
        CommandLine cmd = parser.parse(options, args);
        ...
        // then retrieve arguments
        Integer time = null;
        Integer limit = null;
        LocalDateTime localDateTime = null;
    
        String timeRaw = cmd.getOptionValue(TIME_ARG);
        if (timeRaw.matches("\\d*")) { 
           time = Integer.valueOf(timeRaw); 
        }
        ...and so for until you create your object to save 
        MyObj obj = new MyObj(time, limit, localDateTime);
        ...
       }
       catch(ParseException exp ) {
          System.out.println( "Unexpected exception:" + exp.getMessage() );
       }
    }
    

    args4j 示例

    args4j 使用起来非常直接。
    此外,它提供了一些转换器(从String 到特定类型),但不提供开箱即用的日期转换。
    因此,您应该创建自己的处理程序来执行此操作。示例。

    在示例中,LocalDateTimeOptionHandler 必须如此实现 [OptionHandler][3]

    import org.kohsuke.args4j.CmdLineException;
    import org.kohsuke.args4j.CmdLineParser;
    import org.kohsuke.args4j.Option;
    import org.kohsuke.args4j.OptionHandlerFilter;
    
    public class SampleMain {
    
        @Option(name = "--time", usage = "...")
        private Integer time;
    
        @Option(name = "--limit", usage = "..")
        private Integer limit;
    
        @Option(name="--initDate", handler=LocalDateTimeOptionHandler.class, usage="...")
        private LocalDateTime initDate;
    
        public static void main(String[] args) throws IOException {
           new SampleMain().doMain(args);
        }
    
        public void doMain(String[] args) throws IOException {
          CmdLineParser parser = new CmdLineParser(this);
    
          try {
            // parse the arguments.
            parser.parseArgument(args);        
           } catch (CmdLineException e) {
             System.err.println(e.getMessage());
             System.err.println("java SampleMain [options...] arguments...");
             parser.printUsage(System.err);
             System.err.println("  Example: java SampleMain" + parser.printExample(OptionHandlerFilter.ALL));
             return;
           }
    
          if (time != null)
            System.out.println("-time is set");
    
          if (limit != null)
            System.out.println("-limit is set");
    
          if (initDate != null)
            System.out.println("-initDate is set");
    
        }
     }
    

    【讨论】:

    • 当我的 args 在线程“main”java.lang.IllegalArgumentException 中出现“--”异常时收到此错误:选项“--time”包含非法字符:“-”在 org .apache.commons.cli.OptionValidator.validateOption(OptionValidator.java:71) 在 org.apache.commons.cli.Option.(Option.java:146)
    • 啊,是的。我忘了。为了能够使用- 传递参数,您必须使用将 longOpt String 指定为参数的 Option 构造函数。我更新了
    • 我不喜欢 Commons CLI。像JCommanderArgs4J 这样的东西要优雅得多。
    • @Boris the Spider 感谢您的反馈。我注意到它。我很久以前使用过 Commons CL。它给出了一个很好的结果,但 API 确实不是很好用。
    • 是的,这就是我发现的——它是一个有点神秘的 API。多年来,它并没有减少任何弧度。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-21
    • 1970-01-01
    • 1970-01-01
    • 2020-03-30
    • 2013-02-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多