zoukankan      html  css  js  c++  java
  • 打印Java数组最优雅的方式

    在逛 Stack Overflow 的时候,发现了一些访问量像‎安第斯山一样高的问题,比如说这个:打印 Java 数组最优雅的方式是什么?访问量足足有 220W+,想不到啊,这么简单的问题竟然有这么多程序员被困扰过。
    来回顾一下提问者的问题吧:

    在 Java 中,数组虽然是一个对象,但并未明确的定义这样一个类,因此也就没有覆盖 toString() 方法的机会。如果尝试直接打印数组的话,输出的结果并不是我们预期的结果。那有没有一些简单可行的方式呢?

    如果大家也被这个问题困扰过,或者正在被困扰,就请随来,咱们肩并肩手拉手一起梳理一下这个问题,并找出最佳答案。Duang、Duang、Duang,打怪进阶喽!

    01、为什么不能直接打印

    很好奇,是不是,为什么不能直接使用 System.out.println() 等系列方法来打印数组?来看这样一个例子。

    String [] cmowers = {"沉默","王二","一枚有趣的程序员"};
    System.out.println(cmowers);
    

    程序打印的结果是:

    [Ljava.lang.String;@3d075dc0
    

    [Ljava.lang.String; 表示字符串数组的 Class 名,@ 后面的是十六进制的 hashCode——这样的打印结果太“人性化”了,一般人表示看不懂!为什么会这样显示呢?查看一下 java.lang.Object 类的 toString() 方法就明白了。

    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }
    

    PS:数组虽然没有显式定义成一个类,但它的确是一个对象,继承了祖先类 Object 的所有方法。

    那为什么数组不单独定义一个类来表示呢?就像字符串 String 类那样呢?

    一个合理的解释是 Java 将其隐藏了。假如真的存在一个 Array.java,我们也可以假想它真实的样子,它必须要定义一个容器来存放数组的元素,就像 String 类那样。

    public final class String
        implements java.io.Serializable, Comparable<String>, CharSequence {
        /** The value is used for character storage. */
        private final char value[];
    }
    

    但这样做真的有必要吗?为数组单独定义一个类,是不是有点画蛇添足的意味。

    02、使用 Stream

    如果使用的是 JDK8 以上的版本,我们可以使用 Stream 这种时髦、fashion 的方式来遍历数组,顺带将其打印出来。

    第一种:

    Arrays.asList(cmowers).stream().forEach(s -System.out.println(s));
    

    第二种:

    Stream.of(cmowers).forEach(System.out::println);
    

    第三种:

    Arrays.stream(cmowers).forEach(System.out::println);
    

    打印的结果如下所示。

    沉默
    王二
    一枚有趣的程序员
    

    没错,这三种方式都可以轻松胜任本职工作,并且显得有点高大上,毕竟用到了 Stream,以及 lambda 表达式。但在我心目中,它们并不是最优雅的方式。

    03、使用 for 循环

    当然了,如果不喜欢 Stream 的方式,也可以使用 for 循环对数组进行变量顺便打印的方式,甚至 for-each 也行。

    for(int i = 0; i < cmowers.length; i++){
        System.out.println(cmowers[i]);
    }
    for (String s : cmowers) {
    	System.out.println(s);
    }
    

    但如果你是一名有追求的程序员的话,不免觉得这样的方式有点 low。那到底最优雅的方式是什么呢?

    04、使用 Arrays.toString()

    Arrays.toString() 可以将任意类型的数组转成字符串,包括基本类型数组和引用类型数组,截个图大家感受一下。

    img

    Arrays 类就不用我多做介绍了吧?虽然我的意思大家懂,但我还是忍不住要废话两句:该类包含了各种操作数组的便捷方法,与其命名为 Arrays,不如命名为 ArrayUtil。

    使用 Arrays.toString() 方法来打印数组再优雅不过了,就像,就像,就像蒙娜丽莎的微笑。

    img

    被逗笑了吧?来,怀揣着愉快的心情看一下代码示例。

    String [] cmowers = {"沉默","王二","一枚有趣的程序员"};
    System.out.println(Arrays.toString(cmowers));
    

    程序打印结果:

    [沉默, 王二, 一枚有趣的程序员]
    

    哇,打印格式不要太完美,不多不少!完全是我们预期的结果:[] 表明是一个数组,, 点和空格用来分割元素。

    顺便再来看一下 toString() 方法的源码。

    public static String toString(Object[] a) {
        if (a == null)
            return "null";
        int iMax = a.length - 1;
        if (iMax == -1)
            return "[]";
        StringBuilder b = new StringBuilder();
        b.append('[');
        for (int i = 0; ; i++) {
            b.append(String.valueOf(a[i]));
            // 此处为自己之前没有这样写过的,学习了 *****************
            if (i == iMax)
                return b.append(']').toString();
            b.append(", ");
        }
    }
    

    1)如果数组为 null,那就返回“null”字符串,考虑很周全,省去了 NullPointerException 的麻烦。

    2)如果数组长度为 0,那就返回“[]”字符串。注意,此处没有使用 a.length == 0 进行判空,而是用了 a.length - 1 == -1,又为之后的 for 循环中的 i == iMax 埋下了伏笔,资源一点也没有浪费。

    3)for 循环中字符串的拼接更是巧妙,for 循环的条件中没有判断 i < a.length,而在循环体内使用了 i == iMax,这样有什么好处呢?

    通常来说,一般的程序员拼接字符串的时候是这样做的。

    StringBuilder b = new StringBuilder();
    b.append('[');
    for (int i = 0; i < cmowers.length; i++) {
        b.append(cmowers[i]);
        b.append(", ");
    }
    b.delete(b.length()-2, b.length());
    b.append(']');
    

    没错吧,非常的循规蹈矩,但比起 toString() 方法源码中的写法,就要相形见绌了。情不自禁地感慨一下啊:要想成为一名卓越的程序员,而不只是一名普通的程序员,最快的捷径就是学习 Java 的源码

    05、使用 Arrays.deepToString()

    如果需要打印多维码数组的话,Arrays.toString() 就无能为力了。

    String[][] deepArray = new String[][] {{"沉默", "王二"}, {"一枚有趣的程序员"}};
    System.out.println(Arrays.toString(deepArray));
    

    打印结果如下所示。

    [[Ljava.lang.String;@7ba4f24f, [Ljava.lang.String;@3b9a45b3]
    

    不不不,这不是我们期望的结果,怎么办呢?使用 Arrays.deepToString(),专为多维数组而生。

    String[][] deepArray = new String[][] {{"沉默", "王二"}, {"一枚有趣的程序员"}};
    System.out.println(Arrays.deepToString(deepArray));
    

    打印结果如下所示。

    [[沉默, 王二], [一枚有趣的程序员]]
    

    优秀吧!至于 deepToString() 的源码,本文就不再分析了,大家感兴趣的话自己看一看。(如果你想卓越的话,必须要看啊)

    转载:https://juejin.im/post/5e042ba5518825127324b275

  • 相关阅读:
    Session的使用与Session的生命周期
    Long-Polling, Websockets, SSE(Server-Sent Event), WebRTC 之间的区别与使用
    十九、详述 IntelliJ IDEA 之 添加 jar 包
    十八、IntelliJ IDEA 常用快捷键 之 Windows 版
    十七、IntelliJ IDEA 中的 Maven 项目初体验及搭建 Spring MVC 框架
    十六、详述 IntelliJ IDEA 创建 Maven 项目及设置 java 源目录的方法
    十五、详述 IntelliJ IDEA 插件的安装及使用方法
    十四、详述 IntelliJ IDEA 提交代码前的 Code Analysis 机制
    十三、IntelliJ IDEA 中的版本控制介绍(下)
    十二、IntelliJ IDEA 中的版本控制介绍(中)
  • 原文地址:https://www.cnblogs.com/nxzblogs/p/12106291.html
Copyright © 2011-2022 走看看