从数组流传输时,为什么不能将整数映射到字符串?


92

这段代码有效(取自Javadoc):

List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
String commaSeparatedNumbers = numbers.stream()
    .map(i -> i.toString())
    .collect(Collectors.joining(", "));

这是无法编译的:

int[] numbers = {1, 2, 3, 4};
String commaSeparatedNumbers = Arrays.stream(numbers)
    .map((Integer i) -> i.toString())
    .collect(Collectors.joining(", "));

IDEA告诉我,“ lambda表达式中的返回类型字符串不兼容”。

为什么呢 以及如何解决?

Answers:


114

Arrays.stream(int[])创建一个IntStream,而不是一个Stream<Integer>。因此,在将映射到对象时,您需要调用mapToObj而不是。mapint

这应该按预期工作:

String commaSeparatedNumbers = Arrays.stream(numbers)
    .mapToObj(i -> ((Integer) i).toString()) //i is an int, not an Integer
    .collect(Collectors.joining(", "));

您也可以这样写:

String commaSeparatedNumbers = Arrays.stream(numbers)
    .mapToObj(Integer::toString)
    .collect(Collectors.joining(", "));

3
IntStream和之间有什么区别Stream<Integer>
Florian Margaine 2015年

8
@FlorianMargaine An IntStream是原始int值的流专业化。A Stream<Integer>只是一个持有Integer对象的流。
Alexis C.

2
@FlorianMargaine IntStream是一个流或图元(int),Steram<Integer>而是一个对象流。出于性能原因,原始流具有专门的方法。
assylias 2015年

7
IntStream.mapToObj期望使用IntFunction消耗int值的函数,因此  .mapToObj((Integer i) -> i.toString())不起作用。无论如何,我们不建议您这样做,因为它包含从int到的不必要的转换Integer。相反,.mapToObj(Integer::toString)由于将调用staticmethod ,因此效果很好Integer.toString(int)。请注意,这与调用.map(Integer::toString)a  不同,Stream<Integer>因为后者不明确,因此后者不会编译。
Holger 2015年

1
@cic:不,调用.map(Integer::toString)a Stream<Integer>确实是模棱两可的,.map(i->i.toString())并且.map(i->Integer.toString(i))是有效的。但是,使用可以轻松解决.map(Object::toString)
Holger

19

Arrays.stream(numbers)IntStream在幕后创建一个,而对的地图操作则IntStream需要一个IntUnaryOperator(即function int -> int)。您要应用的映射函数不遵守该约定,因此会产生编译错误。

您需要先致电boxed()才能获得Stream<Integer>(这是Arrays.asList(...).stream()返回的内容)。然后map像在第一个代码段中那样打电话。

请注意,如果需要boxed()紧随其后,则map可能要mapToObj直接使用。

优点是mapToObj不需要将每个int值都装箱到一个Integer对象中。当然取决于您应用的映射功能;所以我会选择这个更短的选项。


5

您可以使用Arrays.stream(int [])创建一个Integer流,可以调用mapToObjlike mapToObj(Integer::toString)

String csn = Arrays.stream(numbers) // your numbers array
.mapToObj(Integer::toString)
.collect(Collectors.joining(", "));

希望这可以帮助..


2

没有拳击,AFAIK,也没有爆炸的小串添加到堆中:

public static void main(String[] args) {
    IntStream stream = IntStream.of(1, 2, 3, 4, 5, 6);
    String s = stream.collect(StringBuilder::new, (builder, n) -> builder.append(',').append(n), (x, y) -> x.append(',').append(y)).substring(1);
    System.out.println(s);
}

1

如果此示例和问题的目的是弄清楚如何将字符串映射到整数流(例如,使用整数流访问字符串数组中的索引),则还可以使用装箱,然后强制转换为一个int(然后将允许访问数组的索引)。

int[] numbers = {0, 1, 2, 3}; 
String commaSeparatedNumbers = Arrays.stream(numbers)
    .boxed()
    .map((Integer i) -> Integer.toString((int)i))
    .collect(Collectors.joining(", "));

.boxed()调用将您的IntStream(原始int流)转换为Stream(对象流,即Integer对象),然后该Stream将接受来自以下对象的对象(在这种情况下为String对象)的返回你的lambda。在这里,它只是数字的字符串表示形式,用于演示目的,但是它也可以很容易(并且实际上)是任何字符串对象-就像前面提到的字符串数组的元素一样。

只是以为我会提供另一种可能性。在编程中,总是有多种完成任务的方法。尽可能多地了解,然后选择最适合手头任务的一种,同时牢记性能问题,直观性,代码的清晰度,您对编码样式的偏好以及最易于记录的文档。

编码愉快!


1
您正在做不必要的工作。将每个int包装盒包装为其包装类型,Integer然后将其取消包装。
Alexis C.
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.