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

Why can't I map integers to strings when streaming from an array?

此代码有效(取自 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 告诉我我有一个 "incompatible return type String in lambda expression".

为什么?以及如何解决这个问题?

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

这应该按预期工作:

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(", "));

Arrays.stream(numbers) 在幕后创建了一个 IntStreamIntStream 上的映射操作需要一个 IntUnaryOperator(即函数 int -> int)。您要应用的映射函数不遵守此合同,因此会出现编译错误。

您需要先调用 boxed() 才能获得 Stream<Integer>(这就是 Arrays.asList(...).stream() returns)。然后像在第一个片段中那样调用 map

请注意,如果您需要 boxed() 后跟 map,您可能想直接使用 mapToObj

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

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

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

希望这对您有所帮助..

如果此示例和问题的目的是弄清楚如何将字符串映射到整数流(例如,使用整数流访问字符串数组中的索引),您还可以使用装箱,然后转换为 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(原始整数流)转换为 Stream(对象流——即 Integer 对象),后者将接受对象的 return(在这种情况下,一个 String 对象)来自你的 lambda。这里它只是用于演示目的的数字的字符串表示形式,但它可以很容易地(并且更实际地)是任何字符串对象——就像前面提到的字符串数组的元素一样。

只是想我会提供另一种可能性。在编程中,总是有多种方法来完成一项任务。尽可能多地了解,然后选择最适合手头任务的那个,同时牢记性能问题、直观性、代码清晰度、您对编码风格的偏好以及最多的自我记录。

编码愉快!

没有装箱,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);
}

除 :: 运算符外:

String numString = numbers.stream()
  .map(String::valueOf)
  .collect(Collectors.joining(", "));

这在较新的 Java-Versions 中可能很重要。