Лучший способ объединить список строковых объектов? [дубликат]
этот вопрос уже есть ответ здесь:
Java: преобразование списка в строку
22 ответов
каков наилучший способ объединения списка строковых объектов? Я думаю сделать так:
List<String> sList = new ArrayList<String>();
// add elements
if (sList != null)
{
String listString = sList.toString();
listString = listString.subString(1, listString.length() - 1);
}
Я как-то нашел это более аккуратным, чем использование StringBuilder / StringBuffer подход.
любые мысли/комментарии?
19 ответов:
ваш подход зависит от реализации Java ArrayList#toString ().
хотя реализация задокументирована в Java API и вряд ли изменится, есть шанс, что это может произойти. Это гораздо надежнее, чтобы реализовать это самостоятельно (петли, StringBuilders, рекурсии, что вам нравится лучше).
используйте один из the StringUtils.присоединяйтесь методы в Apache Commons Lang.
import org.apache.commons.lang3.StringUtils; String result = StringUtils.join(list, ", ");Если вам посчастливилось использовать Java 8, то это еще проще...просто используйте строку.присоединяйтесь
String result = String.join(", ", list);
Использование Java 8+
String str = list.stream().collect(Collectors.joining())или даже
String str = String.join("", list);
вариация ответа codefin
public static String concatStringsWSep(Iterable<String> strings, String separator) { StringBuilder sb = new StringBuilder(); String sep = ""; for(String s: strings) { sb.append(sep).append(s); sep = separator; } return sb.toString(); }
Если вы разрабатываете для Android, есть
TextUtils.joinпредоставлено SDK.
гуавы Это довольно аккуратная библиотека от Google:
Joiner joiner = Joiner.on(", "); joiner.join(sList);
Это самый элегантный и чистый способ я нашел до сих пор:
list.stream().collect(Collectors.joining(delimiter));
вы видели эту запись в блоге ужасов кодирования?
печальная трагедия театра микро-оптимизации
Я не уверен, что это "аккуратнее", но с точки зрения производительности это, вероятно, не будет иметь большого значения.
вместо
ArrayList.toString()реализация, вы можете написать однострочный, если вы используете java 8:String result = sList.stream() .reduce("", String::concat);если вы предпочитаете использовать
StringBufferвместо строки сString::concatимеет время выполненияO(n^2), вы можете конвертировать каждыйStringдоStringBufferпервый.StringBuffer result = sList.stream() .map(StringBuffer::new) .reduce(new StringBuffer(""), StringBuffer::append);
Я как-то нашел это более аккуратным, чем использование StringBuilder/StringBuffer подход.
Я думаю, это зависит от того, какой подход вы взяли.
метод AbstractCollection#toString () просто выполняет итерацию по всем элементам и добавляет их в StringBuilder. Таким образом, ваш метод может сэкономить несколько строк кода, но за счет дополнительных манипуляций со строками. Является ли этот компромисс хорошим, зависит от вас.
мне кажется, что StringBuilder будет быстрым и эффективным.
базовая форма будет выглядеть примерно так:
public static String concatStrings(List<String> strings) { StringBuilder sb = new StringBuilder(); for(String s: strings) { sb.append(s); } return sb.toString(); }Если это слишком упрощенно (и это вероятно), вы можете использовать аналогичный подход и добавить разделитель такой:
public static String concatStringsWSep(List<String> strings, String separator) { StringBuilder sb = new StringBuilder(); for(int i = 0; i < strings.size(); i++) { sb.append(strings.get(i)); if(i < strings.size() - 1) sb.append(separator); } return sb.toString(); }Я согласен с другими, кто ответил на этот вопрос, когда они говорят, что вы не должны полагаться на метод toString() ArrayList Java.
предполагая, что быстрее просто переместить указатель / установить байт в null (или, Однако, Java реализует StringBuilder#setLength), а не проверять условие каждый раз через цикл, чтобы увидеть, когда добавить разделитель, вы можете использовать этот метод:
public static String Intersperse (Collection<?> collection, String delimiter) { StringBuilder sb = new StringBuilder (); for (Object item : collection) { if (item == null) continue; sb.append (item).append (delimiter); } sb.setLength (sb.length () - delimiter.length ()); return sb.toString (); }
следующая вариация на ответ Питера Лоури без инициализации новой строки каждый поворот цикла
String concatList(List<String> sList, String separator) { Iterator<String> iter = sList.iterator(); StringBuilder sb = new StringBuilder(); while (iter.hasNext()) { sb.append(iter.next()).append( iter.hasNext() ? separator : ""); } return sb.toString(); }
ArrayListнаследуетtoString()-способ отAbstractCollection, например:public String toString() { Iterator<E> i = iterator(); if (! i.hasNext()) return "[]"; StringBuilder sb = new StringBuilder(); sb.append('['); for (;;) { E e = i.next(); sb.append(e == this ? "(this Collection)" : e); if (! i.hasNext()) return sb.append(']').toString(); sb.append(", "); } }создание строки самостоятельно будет гораздо более эффективным.
если вы действительно хотите объединить строки заранее в какой-то список, вы должны предоставить свой собственный метод, чтобы эффективно объединить их, например, так:
static String join(Collection<?> items, String sep) { if(items.size() == 0) return ""; String[] strings = new String[items.size()]; int length = sep.length() * (items.size() - 1); int idx = 0; for(Object item : items) { String str = item.toString(); strings[idx++] = str; length += str.length(); } char[] chars = new char[length]; int pos = 0; for(String str : strings) { str.getChars(0, str.length(), chars, pos); pos += str.length(); if(pos < length) { sep.getChars(0, sep.length(), chars, pos); pos += sep.length(); } } return new String(chars); }
в Java 8 вы можете использовать редуктор, что-то вроде:
public static String join(List<String> strings, String joinStr) { return strings.stream().reduce("", (prev, cur) -> prev += (cur + joinStr)); }
в зависимости от потребности в производительности и количества элементов, которые будут добавлены, это может быть решение ОК. Если количество элементов велико, то
Arraylists перераспределение памяти может быть немного медленнее, чемStringBuilder.
С помощью Функциональная Java библиотека, импортируйте их:
import static fj.pre.Monoid.stringMonoid; import static fj.data.List.list; import fj.data.List;... тогда вы можете сделать это:
List<String> ss = list("foo", "bar", "baz"); String s = stringMonoid.join(ss, ", ");или, общий способ, если у вас нет списка строк:
public static <A> String showList(List<A> l, Show<A> s) { return stringMonoid.join(l.map(s.showS_()), ", "); }
Comments