从ArrayNode创建Java 8 Stream

37

com.fasterxml.jackson.databind.node.ArrayNode创建流是否可能?
我尝试过:

ArrayNode files = (ArrayNode) json.get("files");
Stream<JsonNode> stream = Stream.of(files);

但实际上它会返回一个元素构成的流,即初始的ArrayNode对象。
正确的结果应该是Stream<JsonNode>,我能做到吗?


正确的结果应该是Stream<JsonNode>,我能做到吗?

1
这里的整个数组会被加载到内存中吗?我相信答案是“是”。那么在这里使用流的意义是什么? - Andrii Karaivanskyi
@AndreyKarayvansky,这不是关于性能,而是关于能否使用Java 8 Stream API方法以“函数式方式”处理ArrayNode集合(使用诸如mapfiltercollect等方法)。 - icl7126
Lists.newArrayList(arrayNode.elements()).stream() //由Guava提供 - Anderson
3个回答

50

我尝试了你的解决方案,它可以工作,但是我不理解为什么 Stream.of(files) 不行而 spliterator 却可以。 - progonkpa
2
因为Stream.of()期望一个数组作为参数,而ArrayNode不是一个数组。 - JB Nizet

20

ArrayNode类提供随机访问:您可以使用size()和索引(使用get(index))获取元素。这就是创建良好流所需的全部内容。

Stream<JsonNode> nodes = IntStream.range(0, files.size()).mapToObj(files::get);
请注意,与其他答案建议使用默认分割器相比,此解决方案更好,因为它可以很好地拆分并正确报告大小。即使您不关心并行处理,一些操作(如toArray())也会更有效地工作,因为提前知道大小将有助于分配正确大小的数组。

1
我同意你所说的一切,这在很多方面都是更好的解决方案。但我希望能够直接在ArrayNode类中看到这样的解决方案,或者作为某些Utils方法。流应该使代码更易于阅读和理解。对于简单的过滤-映射-收集操作使用此解决方案会稍微增加代码的复杂性。无论如何,非常好的思考,你得到了我的+1。 - icl7126
@klerik,同时保持与Java 8之前版本的兼容性并提供流API方法并不是一件容易的事情。 - Tagir Valeev
我喜欢这个,因为这意味着我不必将我的 JsonNode 强制转换为 ArrayNode - Bernie

5

ArrayNode#elements返回一个迭代器,可以用它来创建一个Stream(通过利用StreamSupport)。StreamSupport需要一个Spliterator,要从Iterator创建一个Spliterator,可以使用Spliterators类。

  ArrayNode files = (ArrayNode) json.get("files");
  Stream<JsonNode>  elementStream = StreamSupport.stream(Spliterators
                  .spliteratorUnknownSize(files.elements(),
                        Spliterator.ORDERED),false);

cyclops-streams 包含一个 StreamUtils 类,其中有一个静态方法可以使代码更简洁(我是作者)。

 ArrayNode files = (ArrayNode) json.get("files");
 Stream<JsonNode>  elementStream = StreamUtils.stream(files.elements());

考虑到@JB Nizet的回答,ArrayNode是一个可迭代对象,可以使用StreamUtils将其传递并直接获取Stream。
Stream<JsonNode>  elementStream = StreamUtils.stream((ArrayNode) json.get("files"));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接