Skip to content

Instantly share code, notes, and snippets.

@Homyakin
Last active January 25, 2023 19:57
Show Gist options
  • Save Homyakin/812028a0ed7aef18af2fbd62fbeac0c1 to your computer and use it in GitHub Desktop.
Save Homyakin/812028a0ed7aef18af2fbd62fbeac0c1 to your computer and use it in GitHub Desktop.
Comparing implementation of java named string templates
package ru.homyakin;
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javafx.util.Pair;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.text.StringSubstitutor;
public class JavaNamedStringTemplates {
private static final String START_TOKEN = "${";
private static final String END_TOKEN = "}";
public static void main(String[] args) {
int count = 100;
long sumReplace = 0L;
long sumRegexp = 0L;
long sumApache = 0L;
long sumBuilder = 0L;
for (int i = 0; i < count; ++i) {
final var pair = generateData(10000);
var start = Instant.now();
System.out.println(formatReplace(pair.getKey(), pair.getValue()));
var end = Instant.now();
sumReplace += end.toEpochMilli() - start.toEpochMilli();
start = Instant.now();
System.out.println(formatRegexp(pair.getKey(), pair.getValue()));
end = Instant.now();
sumRegexp += end.toEpochMilli() - start.toEpochMilli();
start = Instant.now();
System.out.println(formatApache(pair.getKey(), pair.getValue()));
end = Instant.now();
sumApache += end.toEpochMilli() - start.toEpochMilli();
start = Instant.now();
System.out.println(formatBuilder(pair.getKey(), pair.getValue()));
end = Instant.now();
sumBuilder += end.toEpochMilli() - start.toEpochMilli();
}
System.out.printf("Replace: %d milis%n", sumReplace / count); // 5416 milis
System.out.printf("Regexp: %d milis%n", sumRegexp / count); // 151 milis
System.out.printf("Apache: %d milis%n", sumApache / count); // 291 milis
System.out.printf("Builder: %d milis%n", sumBuilder / count); // 21 milis
}
public static Pair<String, Map<String, Object>> generateData(int count) {
final var sb = new StringBuilder();
final var params = new HashMap<String, Object>();
for (int i = 0; i < count; ++i) {
final var key = RandomStringUtils.randomAlphabetic(100);
final var value = RandomStringUtils.randomAlphabetic(100);
// System.out.println(value);
sb.append(START_TOKEN).append(key).append(END_TOKEN).append(";");
params.put(key, value);
}
return new Pair<>(sb.toString(), params);
}
// https://www.baeldung.com/java-string-formatting-named-placeholders
public static String formatRegexp(String template, Map<String, Object> parameters) {
StringBuilder newTemplate = new StringBuilder(template);
List<Object> valueList = new ArrayList<>();
Matcher matcher = Pattern.compile("[$][{](\\w+)}").matcher(template);
while (matcher.find()) {
String key = matcher.group(1);
String paramName = START_TOKEN + key + END_TOKEN;
int index = newTemplate.indexOf(paramName);
if (index != -1) {
newTemplate.replace(index, index + paramName.length(), "%s");
valueList.add(parameters.get(key));
}
}
return String.format(newTemplate.toString(), valueList.toArray());
}
public static String formatApache(String template, Map<String, Object> parameters) {
return StringSubstitutor.replace(template, parameters);
}
// https://stackoverflow.com/a/74154810/11557872
public static String formatReplace(String template, Map<String, Object> parameters) {
String output = template;
for (Map.Entry<String, Object> entry : parameters.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
output = output.replace(START_TOKEN + key + END_TOKEN, String.valueOf(value));
}
return output;
}
// https://stackoverflow.com/a/58420165/11557872
public static String formatBuilder(String template, Map<String, Object> parameters) {
StringBuilder result = new StringBuilder();
int startIndex = 0;
while (startIndex < template.length()){
int openIndex = template.indexOf(START_TOKEN, startIndex);
if (openIndex < 0){
result.append(template.substring(startIndex));
break;
}
int closeIndex = template.indexOf(END_TOKEN, openIndex);
if(closeIndex < 0){
result.append(template.substring(startIndex));
break;
}
String key = template.substring(openIndex + START_TOKEN.length(), closeIndex);
if (!parameters.containsKey(key)) {
result.append(template, startIndex, closeIndex + END_TOKEN.length());
} else {
result.append(template, startIndex, openIndex);
result.append(parameters.get(key));
}
startIndex = closeIndex + END_TOKEN.length();
}
return result.toString();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment