Вопрос-ответ

Best way to convert an ArrayList to a string

Лучший способ преобразовать ArrayList в строку

У меня есть ArrayList который я хочу вывести полностью в виде строки. По сути, я хочу выводить его по порядку, используя toString каждого элемента, разделенного табуляциями. Есть ли какой-нибудь быстрый способ сделать это? Вы могли бы выполнить цикл (или удалить каждый элемент) и объединить его в строку, но я думаю, что это будет очень медленно.

Переведено автоматически
Ответ 1

В Java 8 или более поздней версии:

String listString = String.join(", ", list);

В случае, если list не имеет типа String, можно использовать объединяющий коллектор:

String listString = list.stream().map(Object::toString)
.collect(Collectors.joining(", "));
Ответ 2

Если вы делаете это на Android, для этого есть хорошая утилита под названием TextUtils, у которой есть .join(String delimiter, Iterable) метод.

List<String> list = new ArrayList<String>();
list.add("Item 1");
list.add("Item 2");
String joined = TextUtils.join(", ", list);

Очевидно, что вне Android от него мало пользы, но я решил добавить его в эту тему...

Ответ 3

В Java 8 представлен String.join(separator, list) метод; см. Ответ Виталия Федеренко.

До появления Java 8 единственным вариантом было использование цикла для перебора ArrayList:

НЕ используйте этот код, продолжайте читать до конца этого ответа, чтобы понять, почему это нежелательно и какой код следует использовать вместо него:

ArrayList<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");

String listString = "";

for (String s : list)
{
listString += s + "\t";
}

System.out.println(listString);

На самом деле, конкатенация строк будет просто отличной, поскольку javac компилятор в любом случае оптимизирует конкатенацию строк как серию append операций над StringBuilder. Вот часть дизассемблирования байт-кода из for цикла из вышеупомянутой программы:

   61:  new #13; //class java/lang/StringBuilder
64: dup
65: invokespecial #14; //Method java/lang/StringBuilder."<init>":()V
68: aload_2
69: invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
72: aload 4
74: invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
77: ldc #16; //String \t
79: invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
82: invokevirtual #17; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;

Как можно видеть, компилятор оптимизирует этот цикл с помощью StringBuilder, поэтому производительность не должна вызывать большой озабоченности.

(Хорошо, на второй взгляд, StringBuilder создается экземпляр на каждой итерации цикла, поэтому это может быть не самый эффективный байт-код. Создание экземпляра и использование явного StringBuilder, вероятно, повысило бы производительность.)

На самом деле, я думаю, что вывод любого типа (будь то на диск или на экран) будет как минимум на порядок медленнее, чем беспокоиться о производительности конкатенаций строк.

Редактировать: Как указано в комментариях, приведенная выше оптимизация компилятора действительно создает новый экземпляр StringBuilder на каждой итерации. (Что я отмечал ранее.)

Наиболее оптимизированным методом для использования будет ответ Пола Томблина, поскольку он создает экземпляр только одного StringBuilder объекта вне for цикла.

Переписываем приведенный выше код, чтобы:

ArrayList<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");

StringBuilder sb = new StringBuilder();
for (String s : list)
{
sb.append(s);
sb.append("\t");
}

System.out.println(sb.toString());

Будет создан экземпляр StringBuilder только один раз вне цикла и только два вызова append метода внутри цикла, как показано в этом байт-коде (который показывает создание экземпляра StringBuilder и цикла):

   // Instantiation of the StringBuilder outside loop:
33: new #8; //class java/lang/StringBuilder
36: dup
37: invokespecial #9; //Method java/lang/StringBuilder."<init>":()V
40: astore_2

// [snip a few lines for initializing the loop]
// Loading the StringBuilder inside the loop, then append:
66: aload_2
67: aload 4
69: invokevirtual #14; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
72: pop
73: aload_2
74: ldc #15; //String \t
76: invokevirtual #14; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
79: pop

Итак, действительно, ручная оптимизация должна быть более эффективной, поскольку внутренняя часть for цикла короче, и нет необходимости создавать экземпляр StringBuilder на каждой итерации.

Ответ 4

Загрузите язык Apache Commons Lang и используйте метод

 StringUtils.join(list)

StringUtils.join(list, ", ") // 2nd param is the separator.

Вы, конечно, можете реализовать это самостоятельно, но их код полностью протестирован и, вероятно, является наилучшей возможной реализацией.

Я большой поклонник библиотеки Apache Commons, и я также считаю, что это отличное дополнение к стандартной библиотеке Java.

java string arraylist