Используйте Java Stream для разбора строки цифр в виде списка целочисленных объектов - PullRequest
0 голосов
/ 27 сентября 2018

Мой вопрос вдохновлен этим Вопросом , но нацелен на использование потоков Java для получения List<Integer>.

У меня есть этот код, который работает.Кажется, он возвращает ArrayList, предположительно ArrayList<Integer>.Но компилятор отказывается разрешить мне объявлять результат как таковой.

String input = "1 2 3 4 5";
Stream stream = Arrays.stream( input.split( " " ) );
var x = stream.map( s -> Integer.valueOf( ( String ) s ) ).collect( Collectors.toList() );

Это выполняется при использовании новой функции var в последних версиях Java.

System.out.println( x.getClass() );
System.out.println( x );

class java.util.ArrayList

[1, 2, 3, 4, 5]

У меня два вопроса:

  • Почему x отображается как ArrayList, но я не могу объявить x как ArrayList (ошибка: несовместимые типы), например:
    ArrayList<Integer> x = stream.map( s -> Integer.valueOf( ( String ) s ) ).collect( Collectors.toList() );
  • Есть ли лучший способ использовать потоки для преобразования этой строки цифр в List из Integer?

Ответы [ 4 ]

0 голосов
/ 27 сентября 2018

Почему x сообщается как ArrayList, но я не могу объявить x как ArrayList.

Поскольку

  1. collect(...) возвращает статически выведенныйтип, основанный на типе результата Collectors.toList().
  2. То есть (в данном случае) Collector<String,​?,​List<String>> ... в соответствии с Collectors javadoc .

Тот факт, что фактический объект являетсяArrayList - это деталь реализации, которая может измениться в будущих версиях Java.

Есть ли лучший способ использовать потоки для преобразования этой строки цифр в список целых чисел?

Я оставлю это другим.Тем не менее, я думаю, что более простой / чистый способ сделать это - не использовать потоки для этой задачи.

    String input = "1 2 3 4 5";
    var x = new ArrayList<>(Arrays.asList(input.split(" ")));

Приведенный выше код проще и, скорее всего, более эффективен, чем версии на основе потоков, которые я видел.

0 голосов
/ 27 сентября 2018

Во-первых, ваш Stream является необработанным.Использование необработанного типа означает, что все, что использует параметр типа, стирается до его верхней границы, здесь Object.Таким образом, map возвращает еще один необработанный Stream, а collect возвращает Object.Легкое исправление: Stream<String>.

Stream<String> stream = Arrays.stream( input.split( " " ) );

Секунда, Collectors.toList указано для возврата List<T> или List<String> здесь.

Нет никаких гарантий относительно типа, изменчивости, сериализуемости или безопасности потоков возвращаемого List;если требуется больший контроль над возвращаемым List, используйте toCollection(Supplier).

Если вы не удовлетворены List и вам абсолютно необходим ArrayList, укажите один:

.collect(Collectors.toCollection(ArrayList::new));

Кстати, вы можете заменить лямбда-выражение

s -> Integer.valueOf( ( String ) s )

ссылкой на метод

Integer::valueOf

После этих изменений ваш код может выглядеть следующим образом:

String input = "1 2 3 4 5";
Stream< String > stream = Arrays.stream( input.split( " " ) );
List< Integer > x = stream.map( Integer::valueOf ).collect( Collectors.toList() );

Или, если вы настаиваете на точном ArrayList, а не List, сделайте следующее:

String input = "1 2 3 4 5";
Stream< String > stream = Arrays.stream( input.split( " " ) );
ArrayList< Integer > x = stream.map( Integer::valueOf ).collect( Collectors.toCollection( ArrayList::new ) );

После внесения этих изменений это выглядит как достаточно хороший способ преобразованиястрока, содержащая целые числа через пробел в ArrayList<Integer>.Незначительным улучшением было бы изменение аргумента регулярного выражения split на "\\s+", чтобы представлять один или несколько пробельных символов.В случае поступления "1 2" с несколькими пробелами между числами это предотвратит пустые строки, которые будут совпадать между пробелами.

0 голосов
/ 27 сентября 2018

Вы можете создать ArrayList, но не следует:

ArrayList<Integer> x =
    stream.map(Integer::valueOf)
          .collect(Collectors.toCollection(ArrayList::new));

Рефакторинг:

List<Integer> x =
    Arrays.stream(input.split(" "))
          .map(Integer::valueOf)
          .collect(Collectors.toList());

Или с Pattern.splitAsStream:

List<Integer> x =
    Pattern.compile(" ").splitAsStream("1 2 3 4 5")
           .map(Integer::valueOf)
           .collect(Collectors.toList());
0 голосов
/ 27 сентября 2018
List<Integer> list = Arrays.stream("1 2 3 4 5".split(" ")).map(s -> Integer.valueOf(s)).collect(Collectors.toList());

Это компилируется.Согласно исходному коду сборщиков : «Нет никаких гарантий относительно типа, изменчивости, * сериализуемости или поточной безопасности возвращаемого {@code List};»

...