Конвертировать строку в SomeType в Java

1

Я решил написать свой собственный крошечный ArgumentParser в Java, ключевым моментом является его метод

public void addOption(String optionName, Class valueType, boolean required)

за что-то вроде

ArgumentParser parser = new ArgumentParser();
parser.addOption("--input_path", String.class, true);
Map<String, Object> options = parser.parse(args);  //args is String[]
String inputPath = (String)options.get("--input_path");  //hooray!

но я не могу понять, как попытаться автоматически преобразовать String в определенный пользователем класс? Очевидно, что код ниже не работает

options.put(currentOption, registeredOptions.get(currentOption).valueOf(arg));

Есть ли простой способ сделать это, чего я не могу понять? Или, может быть, вы говорите, что это плохая и порочная идея, я ценю любой совет! Спасибо!

  • 0
    Class.forName(fullyQualifiedClassName);
Теги:
command-line-arguments
string-conversion

3 ответа

1
Лучший ответ

Уже есть несколько библиотек, например JCommander, и почти все они используют шаблон стратегии. То есть, они позволяют клиентам регистрировать объекты конвертера, которые преобразуют входную строку в объект определенного класса. Разумеется, есть несколько встроенных преобразователей для самых очевидных классов, таких как Number, Boolean, File или lists.

Так что у вас будет что-то вроде этого.

public interface Converter<T> {
   public T convert( String arg );
}

public class IntegerConverter implements Converter<Integer> {
   public Integer convert( String arg ) {
       return Integer.parseInt( arg );
   }
}

И в вашем ArgumentParser вы сохраните карту своих зарегистрированных конвертеров и вызовите соответствующий.

Конечно, вы можете уточнить это, указав иерархию преобразователей, чтобы иметь более и менее конкретные стратегии, но общая идея одинаков.

  • 0
    Спасибо за советы по лучшим (распространенным) практикам Java, думаю, я буду придерживаться этого курса.
4

Вы в основном нацелены на создание функции, которая возвращает объект, класс которого был передан как параметр.

Я не знаю общего решения этой проблемы.

Но есть некоторые частичные решения, которые вместе, как я считаю, будут отвечать за то, что вы ищете:

A. Возвращаемый объект является числовым:

Для int и float решение очевидно:

int ival = Integer.parseInt(strParam);
float fval = Float.parseFloat(strParam);

B. Возвращенный класс объекта имеет конструктор строк, то есть конструктор, получающий один строковый параметр

То есть:

parser.addOption("--input_path", MySpecialClass.class, true);

где:

class MySpecialClass {
     public MySpecialClass(String param)  // <----------- string constructor
}

Здесь вы можете использовать отражение, чтобы создать экземпляр требуемого объекта, извлекая и активируя конструктор. Примечание: нашему коду не нужно знать идентификатор возвращаемого класса, но погода или нет, он имеет конструктор строк:

Constructor stringConstructor = classObject.getConstructor(new Class[]{String.class});
Object objectToReturn = stringConstructor.newInstance(stringParam);


Наконец, комбинируя приведенное выше, мы получаем функцию обработки аргументов, аналогичную этой:

Object processAnyParam(String strParam, Class returnClass, boolean mandatory) {

     if (returnClass.equals(int.class)) {
           return Integer.parseInt(strParam);
     }
     else if (returnClass.equals(float.class)) {
          return Float.parseFloat(strParam);
     }
     else if (maybe other numeric types here...) {
     }
     else {
          try { 
                Constructor stringConstructor = classObject.getConstructor(new Class[]{String.class});
          } catch (NoSuchMethodException  e) {
                // no string constructor; bail out..
                return  null;
          }
          return stringConstructor.newInstance(strParam);
     }


}
  • 0
    Спасибо за подробный ответ, есть много полезных идей, но ответ Бизиклопа показался мне самым простым и надежным. Я думаю, что я буду использовать какой-то комбинированный вариант
2

Невозможно преобразовать без передачи какого-либо метода для преобразования String в нужный тип объекта (если вы не требуете, чтобы все классы имели конструктор с параметром String как параметр, который вы хотите использовать для синтаксического анализа String). Одна из возможностей - передать Function<String,?> addOption, например:

public void addOption(String optionName, Function<String, ?> valueConverter, boolean required)


parser.addOption("--stringParameter", Function.identity(), true); // remains identical
parser.addOption("--integerParameter", Integer::parseInt, true); // use Integer.parseInt(String)
parser.addOption("--binaryIntParameter", s->Integer.parseInt(s, 2), true); // integer given in binary format
parser.addOption("--fileParameter", s -> new File(s), true); // use File(String) constructor

Ваша функция синтаксического анализа кода, преобразующая String в объект, будет содержать следующее:

Map<String, Object> result = //...
// ...
String key = //...
String stringValue = //...
Function<String, ?> converter = //... get the converter from where you stored it
result.put(key, converter.apply(stringValue));
//...
return result;
  • 0
    Я хотел бы использовать Java 8 со всеми его вкусными преимуществами, такими как лямбда-функции =) За исключением явного прохождения конвертеров в виде лямбд, ваша идея, насколько я понимаю, похожа на идею biziclop с регистрацией конвертера.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню