如何在Java 8中从流创建一个二维数组?

20 浏览
0 Comments

如何在Java 8中从流创建一个二维数组?

我有一个像这样的文本文件:

ids.txt

1000
999
745
123
...

我想读取这个文件并将其加载到一个二维数组中。我期望得到一个类似下面的数组:

Object[][] data = new Object[][] { //
     { new Integer(1000) }, //
     { new Integer(999) }, //
     { new Integer(745) }, //
     { new Integer(123) }, //
     ...
};

这是我写的代码:

File idsFile = ... ;
try (Stream idsStream = Files.lines(idsFile.toPath(), StandardCharsets.US_ASCII)) {
    Object[][] ids = idsStream
       .filter(s -> s.trim().length() > 0)
       .toArray(size -> new Object[size][]);
    // 在这里处理ids数组...
}

运行这段代码时,会引发异常:

java.lang.ArrayStoreException: null
at java.lang.System.arraycopy(Native Method) ~[na:1.8.0_45]
at java.util.stream.SpinedBuffer.copyInto(Unknown Source) ~[na:1.8.0_45]
at java.util.stream.Nodes$SpinedNodeBuilder.copyInto(Unknown Source) ~[na:1.8.0_45]
at java.util.stream.SpinedBuffer.asArray(Unknown Source) ~[na:1.8.0_45]
at java.util.stream.Nodes$SpinedNodeBuilder.asArray(Unknown Source) ~[na:1.8.0_45]
at java.util.stream.ReferencePipeline.toArray(Unknown Source) ~[na:1.8.0_45]
... 

如何解决这个异常呢?

0
0 Comments

在Java 8中,如果给定一个`Stream`,你可以将每个元素解析为一个`int`,并将其包装在一个`Object[]`中,如下所示:

strings
        .filter(s -> s.trim().length() > 0)
        .map(Integer::parseInt)
        .map(i -> new Object[]{i})

现在,要将这个结果转换为一个`Object[][]`,你可以简单地这样做:

Object[][] result = strings
        .filter(s -> s.trim().length() > 0)
        .map(Integer::parseInt)
        .map(i -> new Object[]{i})
        .toArray(Object[][]::new);

对于输入:

final Stream strings = Stream.of("1000", "999", "745", "123");

输出将是:

[[1000], [999], [745], [123]]

如果你怀疑字符串可能会偶尔在前后有空格,那么最好添加一个单独的`trim`步骤:`strings.map(String::trim).filter(s -> !s.isEmpty())`。此外,我建议使用`Integer::valueOf`而不是`Integer::parseInt`,因为它更符合所需的类型(`Integer`而不是`int`)。虽然这可能只是个人偏好的问题。

为什么"最好添加一个单独的trim步骤"呢?

这样你就可以解析带有数字后面的空格的文件(例如`"1 \n2\n3 \n"`)。目前,对于这样的文件,你将会得到`NumberFormatException`。

你认为这两个`map`操作比简单地使用`.map(s -> new Object[]{Integer.parseInt(s)})`有什么好处吗?

我不太清楚。我喜欢将每个逻辑转换拆分为单独的`map`步骤 - 我认为这样使代码更易读。我认为这只是个人喜好的问题 - 我怀疑这不会对性能产生太大影响。

0
0 Comments

问题:如何在Java 8中从流中创建一个二维数组?

原因:在Java 8中,我们可能遇到需要从流中创建一个二维数组的情况。我们可能有一个包含一系列数字的文件,我们想要将这些数字存储在一个二维数组中以便进一步处理。

解决方法:

我们可以使用Java 8中的流操作来解决这个问题。下面是一个示例代码片段,展示了如何从流中创建一个二维数组:

try (Stream idsStream = Files.lines(idsFile.toPath(), StandardCharsets.US_ASCII)) {
    Object[][] ids = idsStream
       .map(String::trim)
       .filter(s -> !s.isEmpty())
       .map(Integer::valueOf)
       .map(i -> new Integer[] { i })
       .toArray(Object[][]::new);
    // 在这里处理ids数组...
}

在上面的代码中,我们首先使用`Files.lines()`方法从文件中获取一个字符串流。然后,我们对流进行一系列的操作来处理和转换字符串。首先,我们使用`map()`方法来去除每个字符串的前后空格。接下来,我们使用`filter()`方法过滤掉空字符串。然后,我们使用`map()`方法将字符串转换为整数。最后,我们使用`map()`方法将整数转换为一个包含这个整数的单元素整数数组。最后,我们使用`toArray()`方法将所有这些单元素整数数组收集到一个二维数组中。在处理完二维数组后,我们可以在注释的位置继续处理它。

通过以上的解决方法,我们可以在Java 8中从流中创建一个二维数组。

0