使用 Java Stream 将一串数字解析为 Integer 对象的 List

Use Java Stream to parse a string of digits as a List of Integer objects

我的问题受到 的启发,但旨在使用 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() );

这在使用最新 Java 版本的新 var 功能时运行。

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

class java.util.ArrayList

[1, 2, 3, 4, 5]

我有两个问题:

List<Integer> list = Arrays.stream("1 2 3 4 5".split(" ")).map(s -> Integer.valueOf(s)).collect(Collectors.toList());

编译通过。根据 collectors source code:“类型、可变性无法保证, * 返回的 {@code List} 的可序列化性或线程安全性;“

首先,您的 Stream 是原始的。使用原始类型意味着任何使用类型参数的内容都将被擦除到其上限,此处 Object。所以 map return 是另一个原始 Streamcollect return 是 Object。轻松修复:Stream<String>.

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

其次,Collectors.toList指定为returnList<T>,或者List<String>这里

There are no guarantees on the type, mutability, serializability, or thread-safety of the List returned; if more control over the returned List is required, use toCollection(Supplier).

如果您对 List 不满意并且您绝对需要一个 ArrayList,请提供一个:

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

顺便说一句,您可以替换 lambda 表达式

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 ) );

完成这些更改后,这似乎是将包含 space 分隔的整数的字符串转换为 ArrayList<Integer> 的一种相当好的方法。一个小的改进是将 split 正则表达式参数更改为 "\s+",以表示一个或多个白色 space 字符。如果 "1 2" 到达,数字之间有多个 space,这将防止在 space 个字符之间匹配的空字符串。

您可以创建 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());

Why is x reported as an ArrayList yet I cannot declare x to be an ArrayList.

因为

  1. collect(...) 返回静态推断类型,基于 Collectors.toList() 结果的类型。
  2. 即(在这种情况下)Collector<String,​?,​List<String>> ... 根据 Collectors javadoc

实际对象是 ArrayList 这一事实是一个实现细节,可以想象在 Java 的未来版本中会发生变化。

Is there a better way to use streams to convert this string of digits to a List of Integer?

我会留给其他人说。但是,我认为更简单/更清晰的方法是不使用流来完成此任务。

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

上面的代码比我见过的基于流的版本更简单,而且很可能更高效。