Вы набросали два способа предлагая определенную функциональность
Первой явно предложить его как метод
public static String putInQ1(String s) {
return Q1.concat(s).concat(Q1);
}
, который, как предполагается, для использования с помощью ссылки на метод.
Второй, чтобы предложить его в качестве Function
объекта:.
Function<String, String> putInQ1 = n -> Q1.concat(n).concat(Q1);
(Здесь, вы не сказали, где эти случаи должны быть расположены, я предполагаю, что вы бы также создать класс, который содержал все эти Function
случаи как (возможно public static final
полей)
JBNizet упоминается третий вариант: могут использовать методы напрямую, а не через ссылки на методы. Действительно, цель функции transform
не совсем ясна. Единственным оправданием для этого было бы то, что вы захотите передать там произвольные ссылки на методы, но эти ссылки на методы будут всего лишь Function
объектов - как во втором подходе ...
Однако в техническом смысле разница не такая большая. Чтобы проиллюстрировать суть: оба подхода могут быть тривиально преобразованы друг в друга! Этот метод может быть реализован на основе функционального объекта
public static String putInQ1(String s) {
return putInQ1.apply(s);
}
И функциональный объект может быть создана из ссылки методы:
Function<String, String> putInQ1 = StringUtils::putInQ1;
Так что главный вопрос может быть: Как вы хотите предлагать эту функцию пользователю вашей библиотеки?
Для этого рассмотрит случай использования у вас есть входная строка, и хочет, чтобы положить его в (
скобки )
, и результат в '
одинарных кавычек '
:
String doItWithMethodReferences(String input) {
String result = input;
result = StrUtils.transform(result, StrUtils::putInParens);
result = StrUtils.transform(result, StrUtils::putInQ1);
return result;
}
String doItWithFunctionObjects(String input) {
String result = input;
result = StringFunctions.putInParens.apply(result);
result = StringFunctions.putInQ1.apply(result)
return result;
}
String doItWithMethods(String input) {
String result = input;
result = StrUtils.putInParens(result);
result = StrUtils.putInQ1(result);
return result;
}
Вы можете видеть, что есть вряд ли разница между подходами, которые могли бы квалифицировать один из них как «лучше» или «хуже», чем другой с точки зрения удобочитаемости, за исключением очевидного факта, что последний проще, чем первый, избегая ненужных вызовов transform
.
Конечно, каждый из этих методов можно было бы записать «более компактно» в одной строке. Но в зависимости от количества и структуры операций это могло бы строго уменьшить читаемость, и на самом деле это приводит к другому моменту: я мог представить себе, что расширяемость может что-то рассмотреть. Представьте себе, что вы хотели создать сингл, который помещал строку в '(
одинарные кавычки и круглые скобки )'
сразу.
С методами:
public static String putInPandQ1(String s) {
return putInQ1(putInParens(s));
}
С функциями:
Function<String, String> putInPandQ1 = putInParens.andThen(putInQ1);
Я думаю, что функция andThen
будет хорошая особенность, которая помогает создавать более сложные манипуляции строки.
(Но, принимая, что сколь угодно далеко, надо спросить, есть ли вы на самом деле не пытается реализовать шаблон двигатель или новый предметно-ориентированный язык программирования ...)
Короткая заметка: Все это кажется довольно несвязанным с производительностью. Будут ли вы делать return s0 + s1;
или return s0.concat(s1)
часто, и в тех немногих случаях, когда это имеет значение, вы можете изменить реализацию позже - поскольку, учитывая функциональность, очерченную в вопросе, решение об использовании +
или concat
или некоторых StringBuilder
обман - это точно: деталь реализации.
И еще одна записки, как указано в комментариях: Вместо определения своего собственного StringFunction
интерфейса, вы можете использовать UnaryOperator<String>
. Оба являются «структурно равными», но первая является частью стандартного API.Представьте, что там уже много библиотек, с методами, которые ожидают в качестве аргумента UnaryOperator<String>
. Если у вас есть только ваши собственные StringFunction
, вам, возможно, придется преобразовать эти экземпляры, чтобы ваш код мог взаимодействовать с другим кодом. Это, конечно, тривиально, но интерфейсы в пакете functional
тщательно подобраны для охвата большого числа приложений, и я думаю, что взаимодействие между библиотеками может быть значительно увеличено, когда программисты не напрасно создают новые интерфейсы, которые уже существуют в стандартном API. Один может утверждать, что введение StringFunction
упрощает код, поскольку для него не требуется общий параметр <String>
. Но если вы хотите это, тогда вы должны просто объявить iterface как interface StringFunction extends UnaryOperator<String> { }
, который просто является дополнительной специализацией и будет поддерживать совместимость с другим кодом. Кроме того, вы тогда удобно наследуете все методы default
от Function
, например, andThen
, которые я описал выше.
В чем смысл? Почему бы просто не использовать 'StrUtils.putInQ1 (« anSqlStr ») и' StrUtils.putInParens («sqlParams») '? И почему бы просто не использовать «return» («+ s +») «', что гораздо читаемо, а также более эффективно? –
Метод '.concat()' намного медленнее, чем использование '+', которое оптимизирует компилятор. – 4castle
Вам вообще не нужно определять 'StringFunction'. Вы можете просто использовать 'UnaryOperator'. (Не то, чтобы это было очень важно, потому что подход, предложенный JB Nizet, будет намного лучше в долгосрочной перспективе). –
4castle