Преобразование списка в список

У меня есть список целых чисел, List<Integer>и я хотел бы преобразовать все целочисленные объекты в строки, таким образом заканчивая новым List<String>.

Естественно, я мог бы создать новый List<String>и просмотреть список, вызывая String.valueOf()каждое целое число, но мне было интересно, есть ли лучший (читай: более автоматический ) способ сделать это?

20.08.2008 18:29:48
22 ОТВЕТА
РЕШЕНИЕ

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

List<Integer> oldList = ...
/* Specify the size of the list up front to prevent resizing. */
List<String> newList = new ArrayList<>(oldList.size());
for (Integer myInt : oldList) { 
  newList.add(String.valueOf(myInt)); 
}
76
15.04.2020 18:23:14
Когда это просто, это называется красотой.
Elbek 7.09.2012 16:11:02
Оригинальный плакат, казалось, указывал, что он думал об этом, но считал это решение слишком сложным или утомительным. Но мне трудно представить, что может быть проще. Да, иногда вам нужно написать 3 или 4 строки кода, чтобы выполнить работу.
Jay 7.09.2012 17:44:35
Но это связывает вас с ArrayList. Можно ли это сделать, используя ту же реализацию, что и исходный список?
alianos- 10.04.2013 10:23:40
@Andreas oldList.getClass (). NewInstance () сделает
Lluis Martinez 9.05.2013 16:56:18

@Jonathan: Я могу ошибаться, но я полагаю, что String.valueOf () в этом случае будет вызывать функцию String.valueOf (Object), а не помещаться в String.valueOf (int). String.valueOf (Object) просто возвращает значение «null», если оно равно null, или вызывает Object.toString (), если оно не равно NULL, что не должно включать в себя бокс (хотя, очевидно, речь идет о создании экземпляров новых строковых объектов).

2
20.08.2008 18:42:01

Вместо использования String.valueOf я бы использовал .toString (); он избегает некоторых из автоматического бокса, описанного @ johnathan.holland

Javadoc говорит, что valueOf возвращает то же самое, что и Integer.toString ().

List<Integer> oldList = ...
List<String> newList = new ArrayList<String>(oldList.size());

for (Integer myInt : oldList) { 
  newList.add(myInt.toString()); 
}
9
15.09.2008 18:24:58
как отметил Том Хоутин в «выигрышном» ответе, нельзя создать экземпляр List <String>, поскольку это всего лишь интерфейс.
Stu Thompson 14.09.2008 23:11:45
Хех, я знал это. Просто я написал код, не пытаясь его. Я исправлю это в своем ответе.
ScArcher2 15.09.2008 18:24:42

Я думаю, что использование Object.toString () для любых целей, кроме отладки, вероятно, является действительно плохой идеей, даже если в этом случае они функционально эквивалентны (при условии, что в списке нет нулей). Разработчики могут изменять поведение любого метода toString () без предупреждения, включая методы toString () любых классов в стандартной библиотеке.

Даже не беспокойтесь о проблемах производительности, вызванных процессом упаковки / распаковки. Если производительность критична, просто используйте массив. Если это действительно важно, не используйте Java. Попытка перехитрить JVM приведет только к душевной боли.

2
20.08.2008 18:53:35

Источник для String.valueOf показывает это:

public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}

Не то чтобы это имело большое значение, но я бы использовал toString.

9
20.08.2008 19:03:11

Вы не можете избежать "накладных расходов на бокс"; Стандартные контейнеры Java могут хранить только объекты, поэтому ваши целые должны быть упакованы в целые числа. В принципе, он мог бы избежать перехода от Object к Integer (поскольку это бессмысленно, поскольку Object достаточно хорош как для String.valueOf, так и для Object.toString), но я не знаю, достаточно ли умен для этого компилятор. Преобразование из String в Object должно быть более или менее запретным, поэтому я не буду беспокоиться об этом.

1
20.08.2008 20:25:49
компилятор не достаточно умен, чтобы сделать это. Когда javac запускается, он фактически удаляет всю информацию о типовых типах. Базовая реализация универсальной коллекции ALWAYS хранит ссылки на объекты. Вы можете фактически опустить параметризацию <T> и получить «сырой» тип. «Список l = новый список ()» против «Список <String> l = новый список <String> ()». конечно, это означает, что «List <String> l = (List <String>) new List <Integer> ()» будет фактически компилироваться и запускаться, но, очевидно, это очень опасно.
Dave Dopson 4.06.2011 20:20:45

Не базовая Java и не универсальная, но в популярной библиотеке коллекций общих ресурсов Джакарты есть несколько полезных абстракций для такого рода задач. В частности, посмотрите на методы сбора на

CollectionUtils

Что-то, чтобы рассмотреть, если вы уже используете коллекции общин в вашем проекте.

3
20.08.2008 20:26:04
Никогда не используйте Apache Collections. Они старые, устаревшие, небезопасные и плохо написанные.
KitsuneYMG 7.03.2010 12:51:58

То, что вы делаете, хорошо, но если вы чувствуете необходимость «Java-it-up», вы можете использовать Transformer и метод сбора от Apache Commons , например:

public class IntegerToStringTransformer implements Transformer<Integer, String> {
   public String transform(final Integer i) {
      return (i == null ? null : i.toString());
   }
}

..а потом..

CollectionUtils.collect(
   collectionOfIntegers, 
   new IntegerToStringTransformer(), 
   newCollectionOfStrings);
40
12.01.2015 10:17:08
CollectionUtils.collect (collectionOfIntegers, новый org.apache.commons.collections.functors.StringValueTransformer ()); Но StringValueTransformer использует String.valueOf ...
Kannan Ekanath 17.02.2010 14:12:57
Если новая работа не была сделана над коллекциями Apache, они не делают дженерики.
KitsuneYMG 7.03.2010 12:50:48
Это действительно Java-ing-it down. Это не идиоматическая Java, а скорее функциональное программирование. Возможно, когда мы получим замыкания в Java 8, вы могли бы назвать это идиоматической Java.
Christoffer Hammarström 7.01.2012 22:44:38
Вы определенно хотите использовать Collections4 для этого (а не старые 3.x Collections) для поддержки обобщений: commons.apache.org/proper/commons-collections/apidocs/org/…
JRA_TLL 6.01.2016 10:17:47
Определение нового класса просто для того, чтобы он был «более ООП или идиоматическим» ... Я не понимаю, как это лучше, чем простой цикл for-each. Это требует больше кода и убирает функциональность (которая может быть уменьшена анонимными классами, но все же). Этот функциональный стиль начинает становиться полезным только тогда, когда существует приличный синтаксис (то есть лямбда-выражения, начиная с Java 8), как это делают функциональные языки десятилетиями.
TheOperator 31.01.2016 21:02:34

Людям, обеспокоенным «боксом» в ответе jsight: их нет. String.valueOf(Object)используется здесь, и никакой распаковки в intникогда не выполняется.

Используете ли вы Integer.toString()или String.valueOf(Object)зависит от того, как вы хотите обрабатывать возможные нули. Вы хотите выбросить исключение (возможно) или иметь «нулевые» строки в своем списке (возможно). Если первое, вы хотите бросить NullPointerExceptionили какой-то другой тип?

Кроме того, один маленький недостаток в ответе jsight: Listэто интерфейс, вы не можете использовать новый оператор на нем. Я бы, вероятно, использовал java.util.ArrayListв этом случае, тем более, что мы заранее знаем, как долго будет длиться список.

3
28.08.2008 18:35:49

Ответ только для экспертов:

    List<Integer> ints = ...;
    String all = new ArrayList<Integer>(ints).toString();
    String[] split = all.substring(1, all.length()-1).split(", ");
    List<String> strs = Arrays.asList(split);
2
11.09.2008 20:40:12
Это работает, но за счет неэффективности. Строки Java составляют два байта на символ, поэтому "," добавляет четырехбайтовую фиксированную стоимость на целое число, прежде чем считать само целое число ... среди прочего.
Robert Christian 13.10.2010 21:59:41
Я думаю, что регулярное выражение может быть больше проблемой с точки зрения эффективности сырого цикла процессора. С точки зрения памяти, я предполагаю, что разумная реализация (при условии, что реализация Sun не имеет смысла String) будет использовать один и тот же массив резервных копий (из all), так что на самом деле будет достаточно эффективно использовать память, что важно для долгосрочной производительности. Если только вы не хотите сохранить один из элементов, конечно ...
Tom Hawtin - tackline 13.10.2010 22:12:16

Просто для удовольствия, решение, использующее инфраструктуру fork-join jsr166y, как и в JDK7.

import java.util.concurrent.forkjoin.*;

private final ForkJoinExecutor executor = new ForkJoinPool();
...
List<Integer> ints = ...;
List<String> strs =
    ParallelArray.create(ints.size(), Integer.class, executor)
    .withMapping(new Ops.Op<Integer,String>() { public String op(Integer i) {
        return String.valueOf(i);
    }})
    .all()
    .asList();

(Отказ от ответственности: не скомпилировано. Спецификация не завершена. И т.д.)

Маловероятно, что в JDK7 есть что-то вроде вывода типа и синтаксического сахара, чтобы сделать этот вызов withMapping менее многословным:

    .withMapping(#(Integer i) String.valueOf(i))
0
14.09.2008 21:25:13

Это такая базовая вещь, которую я бы не делал, я бы не использовал внешнюю библиотеку (это приведет к зависимости в вашем проекте, которая вам, вероятно, не нужна).

У нас есть класс статических методов, специально созданных для выполнения подобных задач. Поскольку код для этого очень прост, мы позволяем Hotspot выполнить оптимизацию за нас. Это, кажется, тема в моем коде в последнее время: написать очень простой (простой) код и позволить Hotspot сделать свое волшебство. У нас редко возникают проблемы с производительностью в отношении такого кода - когда появляется новая версия виртуальной машины, вы получаете все дополнительные преимущества в скорости и т. Д.

Как бы я ни любил коллекции Джакарты, они не поддерживают Generics и используют 1.4 в качестве ЖК-дисплея. Я опасаюсь коллекций Google, потому что они указаны в качестве уровня поддержки Alpha!

0
24.09.2008 07:27:48

Используя Google Collections из Guava-Project , вы можете использовать transformметод в классе Lists.

import com.google.common.collect.Lists;
import com.google.common.base.Functions

List<Integer> integers = Arrays.asList(1, 2, 3, 4);

List<String> strings = Lists.transform(integers, Functions.toStringFunction());

ListВозвращаемый transformэто вид в списке основы - преобразование будет применяться при каждом доступе к преобразованному списку.

Имейте в виду , что Functions.toStringFunction()будет бросать NullPointerExceptionпри нанесении на нуль, поэтому используйте его только если вы уверены , что ваш список не будет содержать нуль.

95
22.12.2017 10:27:57
Было бы хорошо, если бы помимо функций Functions.toStringFunction () было больше готовых функций
ThiamTeck 7.09.2010 06:58:21
чисто, но, возможно, не так быстро .. 1 дополнительный вызов функции на значение?
h3xStream 9.12.2010 15:35:27
HotSpot может выполнять встроенные вызовы функций - поэтому, если он вызывается достаточно, это не должно иметь значения.
Ben Lings 9.12.2010 20:45:53
Я не понижаю это, потому что это действительно решение. Но побуждение людей добавлять библиотечную зависимость для решения такой простой задачи для меня не годится.
estani 28.02.2014 19:09:08
Хорошее решение, если вы уже используете Guava в нашем решении.
dudinha-dedalus 28.04.2015 12:46:16

Lambdaj позволяет сделать это очень простым и понятным способом. Например, предположим, что у вас есть список Integer, и вы хотите преобразовать их в соответствующее представление String, вы можете написать что-то подобное;

List<Integer> ints = asList(1, 2, 3, 4);
Iterator<String> stringIterator = convertIterator(ints, new Converter<Integer, String> {
    public String convert(Integer i) { return Integer.toString(i); }
}

Lambdaj применяет функцию преобразования только во время итерации по результату.

2
7.03.2010 12:40:04

Вот однострочное решение без мошенничества с не-JDK библиотекой.

List<String> strings = Arrays.asList(list.toString().replaceAll("\\[(.*)\\]", "$1").split(", "));
9
25.04.2011 18:42:07

Я просто хотел присоединиться к объектно-ориентированному решению проблемы.

Если вы моделируете доменные объекты, то решение находится в доменных объектах. Домен здесь представляет собой список целых чисел, для которых нам нужны строковые значения.

Самый простой способ - не преобразовывать список вообще.

При этом для преобразования без преобразования измените исходный список Integer на List of Value, где Value выглядит примерно так ...

class Value {
    Integer value;
    public Integer getInt()
    {
       return value;
    }
    public String getString()
    {
       return String.valueOf(value);
    }
}

Это будет быстрее и займет меньше памяти, чем копирование списка.

Удачи!

-1
25.09.2012 06:24:32

Решение для Java 8. Немного длиннее, чем Guava, но, по крайней мере, вам не нужно устанавливать библиотеку.

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

//...

List<Integer> integers = Arrays.asList(1, 2, 3, 4);
List<String> strings = integers.stream().map(Object::toString)
                                        .collect(Collectors.toList());
78
11.04.2014 23:52:19
Хотя это немного длиннее для toStringпримера, в итоге оно становится короче для преобразований, не поддерживаемых библиотекой функций Guava. Пользовательские функции по-прежнему просты, но они значительно больше кода, чем этот поток Java 8
lightswitch05 24.10.2017 20:17:53

Другое решение с использованием Guava и Java 8

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<String> strings = Lists.transform(numbers, number -> String.valueOf(number));
7
25.04.2014 12:38:10

Я не видел ни одного решения, которое бы соответствовало принципу сложности космоса. Если список целых чисел имеет большое количество элементов, то это большая проблема.

It will be really good to remove the integer from the List<Integer> and free
the space, once it's added to List<String>.

Мы можем использовать итератор для достижения того же.

    List<Integer> oldList = new ArrayList<>();
    oldList.add(12);
    oldList.add(14);
    .......
    .......

    List<String> newList = new ArrayList<String>(oldList.size());
    Iterator<Integer> itr = oldList.iterator();
    while(itr.hasNext()){
        newList.add(itr.next().toString());
        itr.remove();
    }
0
29.08.2017 16:27:48
List<String> stringList = integerList.stream().map((Object s)->String.valueOf(s)).collect(Collectors.toList())
2
19.06.2019 11:11:06

Использование потоков: Если, скажем, результат - список целых чисел ( List<Integer> result), то:

List<String> ids = (List<String>) result.stream().map(intNumber -> Integer.toString(intNumber)).collect(Collectors.toList());

Один из способов решить это. Надеюсь это поможет.

0
3.10.2019 05:39:01

Несколько более краткое решение с использованием метода forEach из первоначального списка:

    List<Integer> oldList = Arrays.asList(1, 2, 3, 4, 5);
    List<String> newList = new ArrayList<>(oldList.size());
    oldList.forEach(e -> newList.add(String.valueOf(e)));
0
15.04.2020 18:56:27