Java 8流和简单类型

3

有人可以解释一下为什么以下内容不起作用吗:

long la[] = new long[] {1,2,3};
Arrays.stream(la).map(Long::valueOf).collect(Collectors.toSet());

当这样做时:
String la[] = new String[] {"1","2","3"};
Arrays.stream(la).map(Long::valueOf).collect(Collectors.toSet());

前者会产生编译错误,而后者不会。编译错误(在Eclipse中)非常晦涩难懂,我无法理解。

3个回答

2
Arrays.stream(la) 执行 public static LongStream stream(long[] array) 方法,生成一个 LongStreamLongStreammap 方法返回一个 LongStream(即将源 LongStream 中的每个 long 元素映射到目标 LongStream 中的一个 long 元素)。LongStream 没有接受单个参数的 collect 方法,这就是为什么 collect(Collectors.toSet()) 无法通过编译的原因。

如果使用 mapToObj,它应该可以正常工作:

Set<Long> set = Arrays.stream(la).mapToObj(Long::valueOf).collect(Collectors.toSet());

您的第二个代码片段有效,因为这里的Arrays.stream生成了一个引用类型(Stream<String>)的流,其map方法在您的情况下生成了另一个引用类型(Stream<Long>)的流。在这里,Stream有一个collect方法,接受一个参数 - collect(Collector<? super T, A, R> collector) - 所以collect(Collectors.toSet())有效。

这会解决问题,但并没有解释为什么第一个片段无法编译。 - Tunaki
1
更短的写法:Arrays.stream(la).boxed().collect(Collectors.toSet()); - tobias_k
由于自动装箱(autoboxing)的存在,提供一个期望 long -> long 函数时的 long -> Long 函数并不是问题(你只需要进行不必要的转换)。问题出在 collect 调用上。 - Alexis C.
@user1283068 请注意,尽管有解释,但是它是不正确的。请看上面我的评论和Alexis C.的评论。 - Tunaki
@user1283068 Alexis是对的。上周我没有时间测试这段代码(大部分时间离开了电脑),所以现在才有时间验证它。我已经相应地更新了答案。 - Eran
显示剩余3条评论

2
代码看起来只是相同的。被调用的方法Arrays.stream实际上在两种情况下是不同的: 在一个`Stream`上,您可以调用map并返回基于映射器的返回类型的`Stream`。但是在一个`LongStream`上,map将始终返回一个`LongStream`,即基本类型特化。发生的情况是,Long::valueOf会将您的`long`元素转换为`Long`对象,然后它将自动取消装箱为`long`;实际上,该调用除了执行装箱/取消装箱操作之外什么也没有做。
然后问题出现在`collect`调用中。
  • LongStream.collect 需要3个参数。
  • Stream.collect 有一个3个参数的方法,但也有一个1个参数的方法,你可以使用 .collect(Collectors.toSet()); 调用这个方法。

所以你不能在 LongStream 上调用 .collect(Collectors.toSet());,因为这会导致编译错误:它需要3个参数。

你可以在LongStream上调用mapToObj方法,而不是map方法,该方法声明从映射器的返回类型返回Stream<R>(而不是LongStream)。 在这种情况下,映射器是Long::valueOf,它返回一个Long对象,因此将返回一个Stream<Long>
总之:
  long la[] = new long[] {1,2,3};
  Arrays.stream(la).map(Long::valueOf).collect(Collectors.toSet());
//^--LongStream----^^---LongStream----^^     error

  String la[] = new String[] {"1","2","3"};
  Arrays.stream(la).map(Long::valueOf).collect(Collectors.toSet());
//^-Stream<String>-^^--Stream<Long>--^^---- successful call -----^

  long la[] = new long[] {1,2,3};
  Arrays.stream(la).mapToObj(Long::valueOf).collect(Collectors.toSet());
//^--LongStream----^^-----Stream<Long>-----^^---- successful call -----^

谢谢你的回答! - user1283068

0
回答第一个代码为什么无法编译,是因为它创建了一个LongStream
Arrays.stream(la)

这个操作会将每个long都创建成一个Long包装器,然后再将其拆箱回long。流仍然是一个LongStream

.map(Long::valueOf)

这个代码向 LongStream.collect 传递了一个参数,但是因为 LongStream.collect 需要三个参数,所以会失败:

.collect(Collectors.toSet())

如果你想将LongStream转换为Stream<Long>(或调用LongStream.boxed()),你需要将map更改为mapToObj


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