Удалить последний символ StringBuilder?
Когда вам нужно перебрать коллекцию и сделать строку каждого из данных разделенной разделителем, вы всегда получите дополнительный разделитель в конце, например
for(String serverId : serverIds) {
sb.append(serverId);
sb.append(",");
}
Дает что-то вроде: serverId_1, serverId_2, serverId_3,
Я хотел бы удалить последний символ в StringBuilder (не преобразовывая его, потому что он мне все еще нужен после этого цикла).
20 ответов
Другие указали на deleteCharAt
метод, но вот еще один альтернативный подход:
String prefix = "";
for (String serverId : serverIds) {
sb.append(prefix);
prefix = ",";
sb.append(serverId);
}
В качестве альтернативы используйте Joiner
класс из гуавы:)
Начиная с Java 8, StringJoiner
является частью стандартного JRE.
Другое простое решение:
sb.setLength(sb.length() - 1);
Более сложное решение:
Приведенное выше решение предполагает, что sb.length() > 0
... т.е. есть "последний символ" для удаления. Если вы не можете сделать это предположение, и / или вы не можете справиться с исключением, которое возникнет, если это предположение неверно, то сначала проверьте длину StringBuilder; например
// Readable version
if (sb.length() > 0) {
sb.setLength(sb.length() - 1);
}
или же
// Concise but harder-to-read version of the above.
sb.setLength(Math.max(sb.length() - 1, 0));
Начиная с Java 8, класс String имеет статический метод join
, Первый аргумент представляет собой строку, которую вы хотите между каждой парой строк, а второй является Iterable<CharSequence>
(оба интерфейса, так что-то вроде List<String>
работает. Так что вы можете просто сделать это:
String.join(",", serverIds);
Также в Java 8 вы можете использовать новый StringJoiner
класс, для сценариев, где вы хотите начать конструирование строки, прежде чем у вас есть полный список элементов, чтобы вставить ее.
Просто получите позицию последнего появления персонажа.
for(String serverId : serverIds) {
sb.append(serverId);
sb.append(",");
}
sb.deleteCharAt(sb.lastIndexOf(","));
поскольку lastIndexOf
будет выполнять обратный поиск, и вы знаете, что он найдет с первой попытки, производительность здесь не будет проблемой.
В этом случае,
sb.setLength(sb.length() - 1);
предпочтительнее, так как он просто присваивает последнее значение '\0'
тогда как удаление последнего символа System.arraycopy
С Java-8
Вы можете использовать статический метод String
учебный класс,
String#join(CharSequence delimiter,Iterable<? extends CharSequence> elements)
,
public class Test {
public static void main(String[] args) {
List<String> names = new ArrayList<>();
names.add("James");
names.add("Harry");
names.add("Roy");
System.out.println(String.join(",", names));
}
}
ВЫХОД
James,Harry,Roy
Еще одна альтернатива
for(String serverId : serverIds) {
sb.append(",");
sb.append(serverId);
}
sb.deleteCharAt(0);
С другой стороны,
StringBuilder result = new StringBuilder();
for(String string : collection) {
result.append(string);
result.append(',');
}
return result.substring(0, result.length() - 1) ;
StringBuilder sb = new StringBuilder();
sb.append("abcdef");
sb.deleteCharAt(sb.length() - 1);
assertEquals("abcde",sb.toString());
// true
Еще одна альтернатива:
public String join(Collection<String> collection, String seperator) {
if (collection.isEmpty()) return "";
Iterator<String> iter = collection.iterator();
StringBuilder sb = new StringBuilder(iter.next());
while (iter.hasNext()) {
sb.append(seperator);
sb.append(iter.next());
}
return sb.toString();
}
Чтобы избежать повторного запуска (повлиять на производительность) prefix
использовать TextUtils.isEmpty:
String prefix = "";
for (String item : list) {
sb.append(prefix);
if (TextUtils.isEmpty(prefix))
prefix = ",";
sb.append(item);
}
Мне лично нравится добавлять символ возврата (или более для более длинного "разделителя") в конце:
for(String serverId : serverIds) {
sb.append(serverId);
sb.append(",");
}
sb.append('\b');
Обратите внимание, что у него есть проблемы:
- как
\b
отображается в зависимости от окружающей среды, length()
изString
содержимое может отличаться от длины видимых символов
когда \b
выглядит хорошо, и длина не имеет значения, например, для входа в консоль, это кажется мне достаточно хорошим.
Вы можете попытаться использовать класс Joiner вместо удаления последнего символа из вашего сгенерированного текста;
List<String> textList = new ArrayList<>();
textList.add("text1");
textList.add("text2");
textList.add("text3");
Joiner joiner = Joiner.on(",").useForNull("null");
String output = joiner.join(textList);
//output : "text1,text2,text3"
Я делаю что-то вроде ниже:
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < value.length; i++) {
stringBuilder.append(values[i]);
if (value.length-1) {
stringBuilder.append(", ");
}
}
Я обнаружил, что делаю это довольно много, поэтому я написал тест для 3 основных методов разделителей добавлений:
(тест с правильной разминкой и 100 раундов по 100000 итераций)
"Добавить после"
static void appendAfter()
{
sb.append('{');
for (int i = 0; i < 10; i++)
{
sb.append('"');
sb.append(i);
sb.append('"');
sb.append(':');
sb.append(i);
sb.append(',');
}
sb.setLength(sb.length() - 1);
sb.append('}');
}
"Добавить перед"
static void appendBefore()
{
sb.append('{');
String delimiter = "";
for (int i = 0; i < 10; i++)
{
sb.append(delimiter);
sb.append('"');
sb.append(i);
sb.append('"');
sb.append(':');
sb.append(i);
delimiter = ",";
}
sb.append('}');
}
"Может быть, добавить"
static void appendMaybe()
{
sb.append('{');
for (int i = 0; i < 10; i++)
{
sb.append('"');
sb.append(i);
sb.append('"');
sb.append(':');
sb.append(i);
if (i < 9)
{
sb.append(',');
}
}
sb.append('}');
}
Получил следующие результаты:
Помимо того, что она самая быстрая, я считаю, что реализация «Append Maybe» лучше всего показывает замысел кода. Обычно это более важно, чем доля наносекунд, получаемая за итерацию.
Я оставил тестовый код здесь на случай, если кто-то захочет попробовать его на своей платформе. Пожалуйста, поделитесь своими результатами выше, если вы это сделаете!
Поскольку вы знаете персонажа, которого хотите удалить, вы можете использовать это
sb.TrimEnd(",");
Вот еще одно решение:
for(String serverId : serverIds) {
sb.append(",");
sb.append(serverId);
}
String resultingString = "";
if ( sb.length() > 1 ) {
resultingString = sb.substring(1);
}
Гораздо более простое и компактное решение требует небольшой модификации вашего кода.
for (String serverId : serverIds) {
if (!sb.isEmpty()) sb.append(",")
sb.append(serverId);
}