在逛 Stack Overflow 的時候,發現了一些訪問量像安第斯山同樣高的問題,好比說這個:打印 Java 數組最優雅的方式是什麼?訪問量足足有 220W+,想不到啊,這麼簡單的問題居然有這麼多程序員被困擾過。java
來回顧一下提問者的問題吧:程序員
在 Java 中,數組雖然是一個對象,但並未明確的定義這樣一個類,所以也就沒有覆蓋
toString()
方法的機會。若是嘗試直接打印數組的話,輸出的結果並非咱們預期的結果。那有沒有一些簡單可行的方式呢?web
若是你們也被這個問題困擾過,或者正在被困擾,就請隨我來,我們肩並肩手拉手一塊兒梳理一下這個問題,並找出最佳答案。Duang、Duang、Duang,打怪進階嘍!數組
很好奇,是否是,爲何不能直接使用 System.out.println()
等系列方法來打印數組?來看這樣一個例子。app
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 的全部方法。ui
那爲何數組不單獨定義一個類來表示呢?就像字符串 String 類那樣呢?spa
一個合理的解釋是 Java 將其隱藏了。假如真的存在一個 Array.java,咱們也能夠假想它真實的樣子,它必需要定義一個容器來存放數組的元素,就像 String 類那樣。3d
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
}
複製代碼
但這樣作真的有必要嗎?爲數組單獨定義一個類,是否是有點多此一舉的意味。
若是使用的是 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 表達式。但在我心目中,它們並非最優雅的方式。
固然了,若是不喜歡 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。那到底最優雅的方式是什麼呢?
Arrays.toString()
能夠將任意類型的數組轉成字符串,包括基本類型數組和引用類型數組,截個圖你們感覺一下。
Arrays 類就不用我多作介紹了吧?雖然個人意思你們懂,但我仍是忍不住要廢話兩句:該類包含了各類操做數組的便捷方法,與其命名爲 Arrays,不如命名爲 ArrayUtil。
使用 Arrays.toString()
方法來打印數組再優雅不過了,就像,就像,就像蒙娜麗莎的微笑。
被逗笑了吧?來,懷揣着愉快的心情看一下代碼示例。
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 的源碼。
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()
的源碼,本文就再也不分析了,你們感興趣的話本身看一看。(若是你想卓越的話,必需要看啊)
好了各位讀者朋友們,以上就是本文的所有內容了。能看到這裏的都是最優秀的程序員,升職加薪就是你了👍。若是以爲不過癮,還想看到更多,我再給你們推薦幾篇。
五分鐘學Java:爲何會發生ArrayIndexOutOfBoundsException?
五分鐘學Java:爲何會發生ArrayIndexOutOfBoundsException?
五分鐘學Java:什麼是 NullPointerException?
平常操做來了!若是是二哥鐵桿讀者的話,請不要吝嗇你手中在看和轉發的權力,明人不說暗話,我喜歡這種被你們夥寵愛的感受。
PS:最近絞盡腦汁想到了一句魔性的宣傳詞,你們一塊兒高聲朗讀一下:
這裏是「沉默王二」公衆號,誰關注誰發大財,誰關注誰皮膚白。
本身忍不住笑場了(哈哈哈)。