不久前,我们将一些Eclipse插件项目升级到Java8。此后再也没有回头。 除其他事项外,使用lambda和streams API ,过滤,映射和查找集合中的元素变得更加容易和简洁。 我想到目前为止,对于大多数人来说,什么都没有。

但是许多现有的API在参数和/或返回数组中使用数组。 例如,请考虑以下虚构但通用的方法签名:

String[] filterStrings( String... input );

随之而来的是从数组中获取流的额外工作,以便能够优雅地过滤,映射,缩小等元素。 然后取回一个可以传递给老式API的数组。

向前…

要从数组中获取流,有很多选择。 例如,这行代码

Stream stream = Stream.of( "a", "b", "c" );

产生具有指定元素的流。 同样可以通过以下方式实现:

Stream stream = Arrays.stream( "a", "b", "c" );

实际上, Stream.of()使用Arrays.stream()完成任务。 通过列表绕行也会产生流:

Stream stream = Arrays.asList( "a", "b", "c" ).stream();

… 然后回来

一旦有了流,就可以使用所有流功能,例如,从字符串数组中过滤空字符串:

Stream.of( "a", "", "b", "", "c", "" ).filter( string -> !string.isEmpty() );

但是如何返回结果数组呢?

有用于集合和列表的收集器,但不包括用于简单数组的收集器。 此代码段

List<String> list
  = Stream.of( ... ).filter( ... ).collect( Collectors.toList() );
String[] array = list.toArray( new String[ list.size() ] );

使用toList()获得过滤后的输入的列表,然后在第二步中将该列表转换为数组。

我几乎要实现一个自定义数组收集器,以消除多余的步骤。 直到我发现有一个终端操作可以像这样简单地将流的结果捕获到数组中:

String[] array = Stream.of( ... ).toArray( size -> new String[ size ] );

toArray()需要generator ,它是对能够创建所请求大小的数组的方法的引用。 在这里创建一个String类型的数组。

但是,等等,还有一种更简单的方法。 如上所述,生成器是可以创建所需大小的数组的函数。 Java 8的开发者非常善于引入一些语法糖来直接引用数组构造函数。

通过在构造函数引用中添加一个左,右方括号,可以表示一个数组构造器引用 ,例如Type[]::new. 。 因此,上面的代码行可以这样重写:

String[] array = Stream.of( ... ).toArray( String[]::new );

编译器将String[]::new表达式扩展为size -> new String[ size ] 。 因此, 生成的字节码与前一种方法相同 ,但是我发现后者更为简洁。

而且,它消除了错误的生成的数组大小,这是不可能的,但仍然是可能的错误。 考虑一下:

String[] array = Stream.of( "a", "b", "c" ).toArray( size -> new String[ 1 ] );

创建的数组显然太小。 它的实际大小(一个)将永远无法容纳这三个结果元素。 因此将以IllegalStateException结尾。 使用数组构造函数引用时,编译器将确保创建适当大小的数组。

当然,还有一个通用的toArray()方法可返回一个Objects数组,如果结果数组的实际类型无关紧要,则可以使用该方法。

从数组到流再返回的结论

像我亲爱的同事Ralf一样 ,许多程序员更喜欢API接口中的集合而不是数组。 但是仍然有许多“老式” API要求您处理数组。 而且与API一样,这些不会很快消失。

但是,无论您喜欢哪种方式,或者无论哪种方式都必须使用现有代码,我都发现Java 8在两个世界之间提供了一个不错的桥梁,这是一个好消息。

如果您有任何疑问,建议或想分享您在该领域的经验,请发表评论。

翻译自: https://www.javacodegeeks.com/2015/11/from-arrays-to-streams-and-back-with-java-8.html