使用普通的JAVA Stream 收集 int 数组的值

6

在我的程序中,我试图使用Stream打印已排序的整数数组。但是,在使用普通流时,输出错误。而在使用int stream时,正确的细节会被打印。

请参考以下核心代码片段以了解更多详情。

package com.test.sort.bubblesort;

import java.util.Arrays;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class BubbleSortWithRecursion {

    public static void bubbleSort(int[] arr, int n) {

        if (n < 2) {
            return;
        }

        int prevValue;
        int nextValue;
        for (int index = 0; index < n-1; index++) {
            prevValue = arr[index];
            nextValue = arr[index+1];

            if  (prevValue > nextValue) {
                arr[index] = nextValue;
                arr[index+1] = prevValue;
            }
        }

        bubbleSort(arr, n-1);
    }

    public static void main(String[] args) {
        int arr[] = new int[] {10,1,56,8,78,0,12};
        bubbleSort(arr, arr.length);

        **//False Output** :  [I@776ec8df
        String output = Arrays.asList(arr)
            .stream()
            .map(x -> String.valueOf(x))
            .collect(Collectors.joining(","));

        System.out.println(output);

        //Correct Output : 0,1,8,10,12,56,78
        String output2 = IntStream
            .of(arr)
            .boxed()
            .map(x -> Integer.toString(x))
            .collect(Collectors.joining(","));

        System.out.println(output2);

    }


}

我在控制台上看到了以下输出:

[I@776ec8df
0,1,8,10,12,56,78

第一行输出使用的是普通的Java流,这是不正确的。

为什么我在使用普通JAVA流时得到了错误的内容?我有什么遗漏吗?

3个回答

10
您可以这样解决您的问题:
String output = Arrays.stream(arr)
        .boxed()
        .map(String::valueOf)
        .collect(Collectors.joining(",")); // 0,1,8,10,12,56,78

解释发生了什么:

当您使用Arrays.asList()时,会发生以下情况:

public static <T> List<T> asList(T... a) {
    return new ArrayList<>(a);
}

它使用类型为T的可变参数。在你的情况下,你将它用于int[]对象,所以Arrays.asList()将返回int[]List而不是一个int流。因此,你需要使用Arrays.stream,它看起来像这样:

public static IntStream stream(int[] array) {
    return stream(array, 0, array.length);
}

获取正确的数据。


1
非常感谢您在此分享建议。您的答案与Eran的答案类似,但Eran的答案更清楚地解释了可变参数映射。因此,我接受了这个答案。 - Gunjan Shah

7

Arrays.asList(arr)返回一个List<int[]>,其中唯一的元素是arr。 因此,对该List进行流处理,然后将该单个元素映射为String.valueOf(x)并使用Collectors.joining(",")收集,将导致一个String,其值为该单个数组的toString(),这就是您看到的输出。

String output = Arrays.asList(arr) // List<int[]>
    .stream() // Stream<int[]>
    .map(x -> String.valueOf(x)) // Stream<String> having a single element - "[I@776ec8df"
    .collect(Collectors.joining(",")); // "[I@776ec8df"

当你从一个int数组创建一个IntStream时,你会得到一个由单独元素(即int值)组成的流,所以你可以对它们进行装箱,将它们转换为String并连接它们来获得期望的输出。
如果你改变以下内容,你就可以让你的第一段代码片段工作:
int arr[] = new int[] {10,1,56,8,78,0,12};

to:

Integer arr[] = new Integer[] {10,1,56,8,78,0,12};

由于这种方法 Arrays.asList(arr) 会产生一个包含输入数组所有元素的List<Integer>


谢谢分享答案。但我还有一个疑惑。当使用原始类型时,Arrays.asList会生成List<int[]>,而不是应该生成List<Integer[]>吗? - Gunjan Shah
为了更好地理解, Integer 是一个对象,而 int 只是一种本地类型。因此,当您使用本地类型的数组时,它可以被视为一个对象,而不是 Integer 数组,则被视为对象数组。 - Youcef LAIDANI
1
@GunjanShah 签名为 static <T> List<T> asList(T... a)。 T 必须是引用类型,因此如果您传递原始数组,则该数组本身就是该引用类型。如果您传递某种引用类型的数组(例如 Integer 数组),则 T 将成为数组的元素类型(Integer)。 - Eran
哇...这看起来很简单,但是这里隐藏着一个非常好的概念。这个答案帮助我更清楚地理解了我的可变参数概念。谢谢! - Gunjan Shah

0

甚至可以更短一点:

String output = Arrays.stream(arr)
        .mapToObj(String::valueOf)
        .collect(Collectors.joining(","));

结果是0,1,8,10,12,56,78

首先创建一个IntStream,然后获取一个Stream<String>,最后将其收集到最终的String中。


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