Мы реализуем адаптер для Jaxen (библиотека XPath для Java), который позволяет нам использовать XPath для доступа к модели данных нашего приложения.
Это делается путем реализации классов, которые отображают строки (переданные нам из Jaxen) в элементы нашей модели данных. По нашим оценкам, нам потребуется около 100 классов с более чем 1000 сравнений строк.
Я думаю, что лучший способ сделать это - простые операторы if / else со строками, записанными непосредственно в код, а не определение каждой строки как константы. Например:
public Object getNode(String name) {
if ("name".equals(name)) {
return contact.getFullName();
} else if ("title".equals(name)) {
return contact.getTitle();
} else if ("first_name".equals(name)) {
return contact.getFirstName();
} else if ("last_name".equals(name)) {
return contact.getLastName();
...
Однако меня всегда учили, что мы не должны вставлять строковые значения непосредственно в код, а вместо этого создавать строковые константы. Это будет выглядеть примерно так:
private static final String NAME = "name";
private static final String TITLE = "title";
private static final String FIRST_NAME = "first_name";
private static final String LAST_NAME = "last_name";
public Object getNode(String name) {
if (NAME.equals(name)) {
return contact.getFullName();
} else if (TITLE.equals(name)) {
return contact.getTitle();
} else if (FIRST_NAME.equals(name)) {
return contact.getFirstName();
} else if (LAST_NAME.equals(name)) {
return contact.getLastName();
...
В этом случае я думаю, что это плохая идея. Константа будет использоваться только один раз, вgetNode()
методе . Использование строк напрямую так же легко понять и понять, как и использование констант, и это экономит нам на написании как минимум тысячи строк кода.
Так есть ли причина определять строковые константы для одного использования? Или допустимо использовать строки напрямую?
PS. Прежде чем кто-либо предложит использовать перечисления вместо этого, мы прототипировали это, но преобразование перечисления в 15 раз медленнее, чем простое сравнение строк, поэтому оно не рассматривается.
Вывод: ответы ниже расширили сферу этого вопроса за пределы строковых констант, поэтому у меня есть два вывода:
- Возможно, в этом сценарии можно использовать строки напрямую, а не строковые константы, но
- Есть способы вообще избежать использования строк, которые могут быть лучше.
Итак, я собираюсь попробовать технику обертки, которая полностью избегает строк. К сожалению, мы не можем использовать оператор переключения строк, потому что мы еще не на Java 7. В конечном счете, я думаю, что лучший ответ для нас - попробовать каждую технику и оценить ее эффективность. Реальность такова, что если один метод явно быстрее, то мы, вероятно, выберем его независимо от его красоты или приверженности условностям.
источник
switch
меток. Используйте переключатель вместоif
каскадов.Ответы:
Попробуй это. Первоначальное размышление, безусловно, дорого, но если вы собираетесь использовать его много раз, что, я думаю, вам понадобится, это, безусловно, лучшее решение того, что вы предлагаете. Я не люблю использовать рефлексию, но я использую ее, когда мне не нравится альтернатива рефлексии. Я думаю, что это избавит вашу команду от головной боли, но вы должны передать имя метода (строчными буквами).
Другими словами, вместо того, чтобы передавать «имя», вы должны передать «полное имя», потому что имя метода get - «getFullName ()».
Если вам нужен доступ к данным, содержащимся в членах контакта, вы можете рассмотреть возможность создания класса-обертки для контакта, который имеет все методы для доступа к любой необходимой информации. Это также было бы полезно для гарантии того, что имена полей доступа всегда будут оставаться одинаковыми (т. Е. Если класс-оболочка имеет getFullName () и вы вызываете с полным именем, он всегда будет работать, даже если метод getFullName () контакта был переименован - он приведет к ошибке компиляции, прежде чем это позволит вам сделать это).
Это решение спасло меня несколько раз, а именно, когда я хотел иметь единственное представление данных для использования в jsf datatables и когда эти данные нужно было экспортировать в отчет с помощью jasper (который по моему опыту плохо обрабатывает сложные средства доступа к объектам) ,
источник
.invoke()
, потому что он полностью исключает строковые константы. Я не очень заинтересован в отражении во время выполнения для настройки карты, хотя, возможно, выполнениеgetMethodMapping()
вstatic
блоке будет в порядке, так что это происходит при запуске, а не после запуска системы.Если это вообще возможно, используйте Java 7, который позволяет использовать строки в
switch
выражениях.От http://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html
Я не измерял, но я считаю, что операторы switch компилируются в таблицу переходов вместо длинного списка сравнений. Это должно быть еще быстрее.
Относительно вашего фактического вопроса: если вы используете его только один раз, вам не нужно превращать его в константу. Однако учтите, что константа может быть задокументирована и отображена в Javadoc. Это может быть важно для нетривиальных строковых значений.
источник
Если вы собираетесь поддерживать это (вносить какие-либо нетривиальные изменения когда-либо), я мог бы на самом деле подумать об использовании какого-либо рода генерации кода на основе аннотаций (возможно, через CGLib ) или даже просто сценария, который пишет весь код для вас. Представьте себе количество опечаток и ошибок, которые могут возникнуть с подходом, который вы рассматриваете ...
источник
object.getAddress().getCountry()
), которые трудно представить с помощью аннотаций. Сравнение строк if / else не очень красиво, но они быстрые, гибкие, простые для понимания и удобные для модульного тестирования.Я бы все еще использовал константы, определенные в начале ваших классов. Это делает ваш код более понятным, так как легче увидеть, что можно изменить позже (при необходимости). Например,
"first_name"
может стать"firstName"
в более позднее время.источник
Если ваше именование непротиворечиво (иначе
"some_whatever"
всегда отображается наgetSomeWhatever()
), вы можете использовать отражение, чтобы определить и выполнить метод get.источник
Я думаю, обработка аннотаций может быть решением, даже без аннотаций. Это то, что может генерировать весь скучный код для вас. Недостатком является то, что вы получите N сгенерированных классов для N модельных классов. Вы также не можете ничего добавить к существующему классу, но пишете что-то вроде
Один раз в класс не должно быть проблемой. Кроме того, вы могли бы написать что-то вроде
в общем суперклассе.
Вы можете использовать отражение вместо обработки аннотаций для генерации кода. Недостатком является то, что вам нужно, чтобы ваш код компилировался, прежде чем вы сможете использовать рефлексию. Это означает, что вы не можете полагаться на сгенерированный код в классах модели, если вы не сгенерируете некоторые заглушки.
Я также рассмотрел бы прямое использование отражения. Конечно, размышление медленное, но почему оно медленное? Это потому, что он должен делать все, что вам нужно, например, включать имя поля.
источник