程序員的量化交易之路(11)--命令參數解析庫JCommonder學習

轉載須註明出處:http://blog.csdn.net/minimicall?viewmode=contentshttp://cloudtrade.top

在學習量化交易平臺的過程中,接觸到一個參數解析的庫,JCommander。今天把它記錄一下。

它的官網爲:http://www.jcommander.org/


1. 概述

Jcommander是一個非常小的框架,用於解析命令行參數。

可以通過註解來描述你的參數選項:

import com.beust.jcommander.Parameter;
 
public class JCommanderExample {
  @Parameter
  private List<String> parameters = new ArrayList<String>();
 
  @Parameter(names = { "-log", "-verbose" }, description = "Level of verbosity")
  private Integer verbose = 1;
 
  @Parameter(names = "-groups", description = "Comma-separated list of group names to be run")
  private String groups;
 
  @Parameter(names = "-debug", description = "Debug mode")
  private boolean debug = false;
}
然後你可以通過下面代碼來解析命令行參數:

JCommanderExample jct = new JCommanderExample();
String[] argv = { "-log", "2", "-groups", "unit" };
new JCommander(jct, argv);
 
Assert.assertEquals(jct.verbose.intValue(), 2);

2. 參數類型

你的參數可以是任何類型的。內置類型(Integer,Boolean,等),這些是默認就支持的,當然你可以寫一個類型轉換器來支持任意你想要支持的類型。

Boolean

@Parameter(names = "-debug", description = "Debug mode")
private boolean debug = false;

如果你想定義一個布爾參數,在默認情況下爲真,您可以聲明它的參數數量arity 爲1。用戶將需要顯式地指定他們想要的值。

下面程序就是命令行的一個解析案例:

program -debug true
program -debug false

String,Integer,Long

JCommander支持String,Integer,Long類型的解析。

例如:

@Parameter(names = "-log", description = "Level of verbosity")
private Integer verbose = 1;

java Main -log 3

上面的verbose 會接收到3.

當然,下面句子就會拋出異常:

java Main -log test

Lists

當Parameter註解放在一些列表List上時,那麼JCommander會理解爲該參數可以出現很多次。

@Parameter(names = "-host", description = "The host")
private List<String> hosts = new ArrayList<String>();

java Main -host host1 -verbose -host host2

Password

有時候你不想一個參數明文顯示和出現在歷史記錄裏面,比如輸入的密碼。這個時候你就可以將其配置爲密碼類型,只需要把password開關打開。

public class ArgsPassword {
  @Parameter(names = "-password", description = "Connection password", password = true)
  private String password;
}

當你執行程序時,就會有下面的提示:

Value for -password (Connection password):

當然,你也可以選擇顯示輸入的密碼,將echoInput設置爲true:

public class ArgsPassword {
  @Parameter(names = "-password", description = "Connection password", password = true, echoInput = true)
  private String password;
}

3. 自定義類型

通過註解(By annotation)

JCommander是支持內置類型的參數配置。但更多時候吧,你需要輸入一些更爲複雜的類型。比如說,文件、主機名、列表等。。。。爲了達到這個目的,你需要自己去實現下面這個轉換接口:

public interface IStringConverter<T> {
  T convert(String value);
}

例如,下面是一個將string轉換爲File(文件)的轉換器:

public class FileConverter implements IStringConverter<File> {
  @Override
  public File convert(String value) {
    return new File(value);
  }
}

然後呢,你就可以將該轉換器通過Parameter註解的converter參數進行配置:

@Parameter(names = "-file", converter = FileConverter.class)
File file;

JCommander支持一些常用的轉換器(例如都好分割的字符串轉成List<String>)


By factory(通過工廠)

上面的File file 用一次,就得使用一次converter=FileConverter.class。好麻煩不?如果要用多次,能不能省掉它呢。可以。

需要通過下面接口:

public interface IStringConverterFactory {
  <T> Class<? extends IStringConverter<T>> getConverter(Class<T> forType);
}

我們看下面這個例子,需要解析一個host:port參數:

java App -target example.com:8080

你需要定義下面holder類:

public class HostPort {
  private String host;
  private Integer port;
}

converter轉換器類:

class HostPortConverter implements IStringConverter<HostPort> {
  @Override
  public HostPort convert(String value) {
    HostPort result = new HostPort();
    String[] s = value.split(":");
    result.host = s[0];
    result.port = Integer.parseInt(s[1]);
 
    return result;
  }
}

工廠類:

public class Factory implements IStringConverterFactory {
  public Class<? extends IStringConverter<?>> getConverter(Class forType) {
    if (forType.equals(HostPort.class)) return HostPortConverter.class;
    else return null;
  }

使用:

public class ArgsConverterFactory {
  @Parameter(names = "-hostport")
  private HostPort hostPort;
}

看到了吧,沒有再用converter參數了。

當然,你需要將工廠繳入到JCommander對象中:

ArgsConverterFactory a = new ArgsConverterFactory();
JCommander jc = new JCommander(a);
jc.addConverterFactory(new Factory());
jc.parse("-hostport", "example.com:8080");
 
Assert.assertEquals(a.hostPort.host, "example.com");
Assert.assertEquals(a.hostPort.port.intValue(), 8080);

4. 參數驗證

你可以通過下面的接口來做一些早期的參數驗證工作:

public interface IParameterValidator {
 /**
   * Validate the parameter.
   *
   * @param name The name of the parameter (e.g. "-host").
   * @param value The value of the parameter that we need to validate
   *
   * @throws ParameterException Thrown if the value of the parameter is invalid.
   */
  void validate(String name, String value) throws ParameterException;
}

下面這例子就能夠保證輸入的數字一定大於等於0,即正數:

public class PositiveInteger implements IParameterValidator {
 public void validate(String name, String value)
      throws ParameterException {
    int n = Integer.parseInt(value);
    if (n < 0) {
      throw new ParameterException("Parameter " + name + " should be positive (found " + value +")");
    }
  }
}
使用例子:

@Parameter(names = "-age", validateWith = PositiveInteger.class)
private Integer age;



5 主參數(Main parameter)

到目前爲止,你會發現每個參數都有一個names參數。JCommander允許且只允許你配置一個沒有名字的參數,它會接受所有沒有名字的參數。

例如:

@Parameter(description = "Files")
private List<String> files = new ArrayList<String>();
 
@Parameter(names = "-debug", description = "Debugging level")
private Integer debug = 1;

解析:

java Main -debug file1 file2

那麼 files域會接收到"file1","file2"。

6. 私有參數(Private parameters)

參數可以是私有的:

public class ArgsPrivate {
  @Parameter(names = "-verbose")
  private Integer verbose = 1;
 
  public Integer getVerbose() {
    return verbose;
  }
}
ArgsPrivate args = new ArgsPrivate();
new JCommander(args, "-verbose", "3");
Assert.assertEquals(args.getVerbose().intValue(), 3);


7. 參數分隔符(Parameter separators)

默認情況下,參數是通過空白符分割的。但你可以改變爲:

java Main -log:3

或者:

java Main -level=42

你可以定義分隔符:

@Parameters(separators = "=")
public class SeparatorEqual {
  @Parameter(names = "-level")
  private Integer level = 2;
}

8. 多描述(Multiple description)

直接上例子吧:

public class ArgsMaster {
  @Parameter(names = "-master")
  private String master;
}

public class ArgsSlave {
  @Parameter(names = "-slave")
  private String slave;
}

ArgsMaster m = new ArgsMaster();
ArgsSlave s = new ArgsSlave();
String[] argv = { "-master", "master", "-slave", "slave" };
new JCommander(new Object[] { m , s }, argv);
 
Assert.assertEquals(m.master, "master");
Assert.assertEquals(s.slave, "slave");

9. @語法

JCommander支持@語法,允許你將參數寫到文件裏面,然後通過@符加載。例如:


-verbose
file1
file2
file3

java Main @/tmp/parameters

10. Arities(參數的多個值)

一個參數會接收多個值,例如:

java Main -pairs slave master foo.xml

這個-pairs需要接收2個值,(也就是不需要foo.xml),那麼需要定義arity=2,如下:
@Parameter(names = "-pairs", arity = 2, description = "Pairs")
private List<String> pairs;

當然,內置類型都不需要定義這個參數。

你可以定義參數接收無限個值,例如:

program -foo a1 a2 a3 -bar
program -foo a1 -bar

即,變長的,他需要設定variableArity參數:

@Parameter(names = "-foo", variableArity = true)
public List<String> foo = new ArrayList<String>();

11. 爲參數取多個名字

你可以爲一個參數取多個名字:

@Parameter(names = { "-d", "--outputDirectory" }, description = "Directory")
private String outputDirectory;

下面都是可以的:

java Main -d /tmp
java Main --outputDirectory /tmp


好了,還有更多的細節,讀者可以自行到其官網學習了。今天就到這裏。。。。。。











發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章