如何在Java中用单行打印数组

140 阅读4分钟

简介

Java是一门类型安全的语言,是一门冗长的语言。这有其优点,但也有一些缺点。也就是--经常有很多模板代码,简单的操作如打印一个数组并不像提供给println() 方法那么简单。

int[] array = new int[]{1, 2, 3, 4, 5, 6};
System.out.println(array);

这导致内存中的对象引用的哈希值,而不是其内容。

[I@7c3df479

这是因为Java的数组并没有覆盖Object 类的toString() 方法,而只是返回对象本身的哈希值。这显然是语言中缺失的功能,而且也不太清楚为什么会缺失这样的功能,尤其是在其他语言都支持打印这种基本数据结构的情况下。

在本指南中,我们将看看在一行中打印数组的几种方法--利用内置的辅助方法和Stream API,权衡这些方法之间的差异以及何时使用哪一种。

Arrays.toString()

在一行中打印数组的最简单和最直接的方法是使用帮助工具Arrays ,它位于java.util 包中。

int[] array = new int[]{1, 2, 3, 4, 5, 6};
System.out.println(Arrays.toString(array));

在引擎盖下,它使用一个StringBuilder ,通过一个简单的for 循环来追加每个元素,你会得到一个你在打印数组时可能期望的结果。

[1, 2, 3, 4, 5, 6]

**注意:**这种方法在嵌套数组上失败了,在这种情况下,一个元素一个数组,所以它对内存中的对象的引用被添加,而不是它的内容。

所以,这个二维数组不能用Arrays.toString()

int[][] array = new int[][]{{1, 2, 3, 4, 5, 6}, {7, 8, 9, 10, 11, 12}};
System.out.println(Arrays.toString(array));

而导致的结果是

[[I@7c3df479, [I@7106e68e]

Arrays.deepToString()

如果你想处理嵌套数组,你可以用deepToString() 方法代替。

int[][] array = new int[][]{{1, 2, 3, 4, 5, 6}, {7, 8, 9, 10, 11, 12}};
System.out.println(Arrays.deepToString(array));

这样就能得到预期的输出结果

[[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12]]

用Java Streams在一行中打印数组

Arrays.toString() 和 只是以一种固定的方式打印内容,并且是作为方便的方法添加的,这样就不需要你手动创建一个 循环。不过在打印时,你可能想对输出进行一些格式化,或者在浏览元素时对其进行额外的操作。Arrays.toDeepString() for

流API是在Java 8中添加的,是将函数式编程范式引入Java的第一步。一般来说,当用Stream 打印一个数组时,你会调用forEach() 方法,尽管有多种方法可以从一个数组中获得一个流

从数组中获取流的最简单的方法是Stream.of() ,该方法也可以用于其他集合(但取决于数据类型),不过你也可以使用Arrays.stream() (更稳健),或者通过Arrays.asList().stream() ,将数组转换为一个列表并进行流处理(虽然有点多余)。

从所有这些来看--你最有可能使用Arrays.stream() 方法,因为它不关心元素是原始类型还是对象,这在使用Stream.of() 方法时是个问题。

使用Stream.of() ,根据你使用的数据类型,你要么使用Stream ,要么使用派生变体,如IntStream 。这很重要,以免代码返回一个哈希值而不是内容。

int[] intArray = new int[]{1, 2, 3, 4, 5, 6};
String[] objArray = new String[]{"Java", "Python", "JavaScript"};

// If using Stream.of(), primitive types need to be flatmapped
Stream.of(intArray).flatMapToInt(Arrays::stream).forEach(System.out::print);
IntStream.of(intArray).forEach(System.out::print);
// Stream.of() with objects
Stream.of(objArray).forEach(System.out::print);

// Arrays.stream() works with both primitive types and objects
Arrays.stream(intArray).forEach(System.out::print);
Arrays.stream(objArray).forEach(System.out::print);

// If using asList(), primitive types need to be flatMapped
Arrays.asList(intArray).stream().flatMapToInt(Arrays::stream).forEach(System.out::print);
Arrays.asList(objArray).stream().forEach(System.out::print);

这些都会导致

123456
JavaPythonJavaScript

一般来说,Arrays.stream() 方法是最安全的方法,也是最短/最易读的方法。

虽然现在还不是很有风格--使用Streams允许你在管道中添加任何中间操作,所以如果你想用一个分隔符来收集这些内容,例如,你可以使用Collector

System.out.println(Arrays.stream(objArray).collect(Collectors.joining(",")));

这样的结果是

Java,Python,JavaScript

你可以在这里发挥创意,进行多种操作,比如转换数值,过滤它们,然后连接。

String[] objArray = new String[]{"Java", "Python", "JavaScript"};

System.out.println(Arrays.stream(objArray)
        map(String::toUpperCase)
        filter(e -> e.startsWith("J"))
        collect(Collectors.joining(",")));

它把所有的元素都映射成大写的对应值,给定一个谓词(一个元素以 "J "开头)进行过滤,然后用一个分隔符把它们连接起来。

JAVA,JAVASCRIPT

结论

在本指南中,我们看了如何在Java中用单行打印数组--这是默认情况下缺少的功能。

我们看了如何通过Arrays 类的内置辅助方法来打印数组,以及如何利用Stream API来定制这一过程。