一道簡(jiǎn)單的 Java 筆試題,但值得很多人反思建芙!

前言

面試別人没隘,對(duì)我來(lái)說(shuō)是一件新奇事,以前都是別人面試我禁荸。
我清楚地知道右蒲,我在的地域與公司,難以吸引到中國(guó)的一流軟件人才屡限。所以品嚣,我特地調(diào)低了期望,很少問(wèn)什么深入的技術(shù)問(wèn)題钧大,只問(wèn)一些廣泛的翰撑、基礎(chǔ)的。我只要最終給Leader一句“這個(gè)人技術(shù)還行/很好/非常好”啊央,就行了眶诈。至于其它能力、綜合水平瓜饥,由別人把關(guān)逝撬。為此,在挑選唯一的一道筆試題時(shí)乓土,我特別地上心宪潮。

首先溯警,我不敢用網(wǎng)上那些廣為流傳的,比如Leetcode狡相、《程序員面試寶典》里的題——這些都太難了梯轻!正兒八經(jīng)做,其實(shí)很少有人能在1小時(shí)內(nèi)完美做出來(lái)尽棕,除非之前遇到過(guò)喳挑。我本人也并非什么思維敏捷的牛人,不然也不會(huì)混得這么慘滔悉。正所謂己所不欲伊诵,勿施于人,我也不希望以后別人考我特別麻煩的算法題回官,所以自創(chuàng)了一道特別簡(jiǎn)單的曹宴。

其次,對(duì)(Android平臺(tái)的)Java程序員來(lái)說(shuō)歉提,大多數(shù)情況下不需要寫(xiě)什么復(fù)雜的算法浙炼。相反,Java層主要做的是界面控制唯袄、業(yè)務(wù)邏輯、數(shù)據(jù)流之類(lèi)的蜗帜,更提倡代碼的簡(jiǎn)單和可讀恋拷,盡量用既有的公共類(lèi)庫(kù),不惜損失一些運(yùn)行效率厅缺。拿一道復(fù)雜的算法題蔬顾,考一個(gè)Java程序員,多少有點(diǎn)刁難人湘捎。

最后诀豁,還是那個(gè)薪資待遇和人才梯度問(wèn)題。沒(méi)有Google的工資窥妇,就別考Google的題舷胜;沒(méi)有Google的向心力,就別期待有Google級(jí)別的人才來(lái)面試活翩。

亮題

以下有一個(gè)static method烹骨,類(lèi)外會(huì)調(diào)用它,一個(gè)個(gè)地插入一些元素進(jìn)入一個(gè)List材泄【诨溃可以改變這個(gè)List內(nèi)容的,只有這一個(gè)method拉宗,要求任何時(shí)候這個(gè)List都是有序的峦树。
比如辣辫,依次插入3、2魁巩、1急灭、2,我希望List的順序是1歪赢、2化戳、2、3埋凯。

class Solution {
    private static List<Integer> sSorted = new LinkedList<>();
    public static void addElement(int e) {
        // TODO: Insert e to sSorted and make sure sSorted is always sorted.
    }
}

我會(huì)給出15分鐘的時(shí)間点楼,而其實(shí)往往會(huì)再多給10分鐘。(有興趣白对,你可以停在這試試掠廓。相信在看文章這種輕松的環(huán)境下,理清這道題的思路也就10~30秒甩恼。)

(為什么下限是10秒呢蟀瞧?唉……一不小心暴露了我智商的峰值。我實(shí)際問(wèn)過(guò)一些同事条摸,他們通常在理解的同時(shí)悦污,就立刻給出了正確的思路,過(guò)程不足5秒钉蒲,其中甚至包括一個(gè)硬件工程師切端,和一個(gè)只負(fù)責(zé)溝通和文檔的妹子。)

提示

在過(guò)程中顷啼,我會(huì)逐步給出一些提示踏枣,從接口到思路,都會(huì)主動(dòng)提供钙蒙,其它也基本有問(wèn)必答茵瀑。如果單純考算法,C語(yǔ)言才是最合適的躬厌,因?yàn)樗鼪](méi)有什么高級(jí)的工具類(lèi)马昨,什么復(fù)雜點(diǎn)的都得自己寫(xiě)。而Java扛施,則有一些“基礎(chǔ)”類(lèi)庫(kù)是難以記憶的偏陪。比如前面出現(xiàn)的java.util.List,就沒(méi)有多少人能在紙上寫(xiě)出它的常用接口煮嫌。

我并不想考察什么死記硬背笛谦,在這個(gè)時(shí)代,斷網(wǎng)后本來(lái)就沒(méi)幾個(gè)程序員能正常編程昌阿。所以我會(huì)主動(dòng)提供一份List的不完全接口列表饥脑。

public interface List<E> extends Collection<E> {
    public void add(int location, E object);
    public void add(E object);
    public void clear();
    public boolean contains(Object object);
    public boolean equals(Object object);
    public E get(int location);
    public int indexOf(Object object);
    public boolean isEmpty();
    public E remove(int location);
    public E set(int location, E object);
    public int size();
}

我沒(méi)有給出完全的接口恳邀,因?yàn)榻o多了無(wú)疑是誤導(dǎo)人。真正能用上的接口其實(shí)也就3個(gè)灶轰,但我也總不能只給3個(gè)谣沸,提示得太明顯,也限制了對(duì)方的思路笋颤。所以乳附,給出了可能用得上的這幾個(gè)。我也沒(méi)給出注釋?zhuān)驗(yàn)橛新暶骶鸵呀?jīng)夠了伴澄。而且如果對(duì)方問(wèn)起赋除,我也會(huì)給出解釋。

一開(kāi)始我想非凌,考一個(gè)排序算了举农。但是轉(zhuǎn)念一想,這也太不負(fù)責(zé)任了敞嗡。對(duì)面要是背一道冒泡排序的解法上來(lái)颁糟,達(dá)不到考察技術(shù)水平的目的,Boss也不會(huì)認(rèn)可喉悴。本著“放水不能太明顯”的原則棱貌,我想考插入排序,并且把題目弄得沒(méi)多少人見(jiàn)過(guò)箕肃。

排序是一類(lèi)基本算法键畴,合格的程序員至少會(huì)一種。大多數(shù)人都只會(huì)入門(mén)級(jí)的冒泡排序突雪,而我更喜歡插入排序,原因……你會(huì)明白的涡贱。

插入排序咏删,其實(shí)就是把數(shù)組或列表在邏輯上分成兩部分,一部分是待排序的问词,一部分是有序的督函。一開(kāi)始,有序的部分只有一個(gè)元素(或者一個(gè)都沒(méi)有)激挪,然后從待排序的部分里一個(gè)個(gè)抽出來(lái)辰狡,插入到有序的部分。等元素都插入到了有序的部分垄分,排序過(guò)程也就完成了宛篇。

你看,也就抽插N次的事薄湿。而我這道題叫倍,就是只考插入排序算法的一半偷卧,會(huì)插就行。

在面試過(guò)程中吆倦,我甚至常常親自解釋插入排序是怎么回事——放水到這個(gè)份上听诸,我都不忍心再退步了。

真正的考察點(diǎn)

這是一份Android平臺(tái)的開(kāi)發(fā)工作蚕泽,Boss要求的是能干活晌梨、干好活。我給出的建議要求是:

  1. 熟悉Java须妻。
  2. 有良好的溝通仔蝌、表達(dá)能力。
  3. 學(xué)習(xí)能力強(qiáng)璧南,喜歡不斷拓展計(jì)算機(jī)領(lǐng)域的知識(shí)掌逛。
  4. 有良好的編碼習(xí)慣,愿意為代碼的簡(jiǎn)潔司倚、優(yōu)雅而反復(fù)修改豆混。

我建議Boss放棄學(xué)歷和工作年限的要求,技術(shù)崗位就應(yīng)該只考察技術(shù)(和其它基本能力)动知,不應(yīng)該考察技術(shù)的間接證明皿伺。

Java是Android的基本功(我們不玩Kotlin、Scala盒粮、React Native等新花樣)鸵鸥,這門(mén)語(yǔ)言如果不扎實(shí),那至少得帶半年丹皱。

我沒(méi)有在Android崗明確地要求考察Android妒穴,是因?yàn)锳ndroid的那些東西相對(duì)來(lái)說(shuō)容易學(xué)習(xí)。即便是毫無(wú)經(jīng)驗(yàn)的新手摊崭,要搞清楚什么“四大組件”“五大布局”讼油,也就一兩天的事。而如果Java不夠扎實(shí)呢簸,各種肉眼可見(jiàn)的大小bug就會(huì)層出不窮矮台,知識(shí)盲點(diǎn)一兩年都補(bǔ)不完。

溝通是職場(chǎng)基本功根时。如果話都說(shuō)不清瘦赫,那么會(huì)顯著降低團(tuán)隊(duì)的溝通效率。而且蛤迎,我個(gè)人認(rèn)為确虱,話說(shuō)不清的人,代碼一定寫(xiě)不好替裆。語(yǔ)言條理清晰蝉娜,邏輯層次分明唱较,體現(xiàn)到代碼上,就是簡(jiǎn)潔召川、明朗南缓。

學(xué)習(xí)能力、求知欲荧呐,是作為一個(gè)程序員的基本素養(yǎng)汉形。因?yàn)椋蟛糠秩说墓ぷ鞅恫?lèi)似于在一堆按鈕中概疆,找到合適的那個(gè)按下去;而程序員的工作峰搪,往往是閉著眼睛這么干岔冀。開(kāi)發(fā)工程師通常是在一堆未知(沒(méi)讀過(guò)的代碼、不知道的接口)中概耻,把一小部分變成已知(讀懂了的代碼或接口)使套,進(jìn)行一些增刪改,最后達(dá)成外界(產(chǎn)品經(jīng)理、設(shè)計(jì)師、測(cè)試工程師)賦予的業(yè)務(wù)目標(biāo)也颤。

一些職業(yè)賣(mài)口水,一些職業(yè)賣(mài)口才县好。一些職業(yè)賣(mài)青春,一些職業(yè)賣(mài)肉體(咳咳,我說(shuō)的是空姐和搬磚,想歪的去面壁)瞧壮。一些職業(yè)賣(mài)知識(shí),一些職業(yè)賣(mài)能力匙握。

程序員咆槽,或者說(shuō)軟件開(kāi)發(fā)工程師,賣(mài)的是學(xué)習(xí)能力(其實(shí)也包括青春和肉體)肺孤,快速學(xué)會(huì)各種知識(shí),找到那些藏在屏幕外的按鈕济欢,并且正確的按下去赠堵。比如,像Bash這類(lèi)Command line工具法褥,就是自己敲命令出來(lái)執(zhí)行茫叭,而不是去界面上找功能對(duì)應(yīng)的按鈕;而程序設(shè)計(jì)半等、實(shí)現(xiàn)揍愁,就是去發(fā)現(xiàn)呐萨、或者創(chuàng)造一種解決問(wèn)題的辦法,然后用代碼表達(dá)出來(lái)——你看莽囤,都是在干一些反UI谬擦、UX設(shè)計(jì)的事。唯有不斷地學(xué)習(xí)朽缎,才能提高效率惨远,把自己從加班中解脫出來(lái),把項(xiàng)目從bug中拯救出來(lái)话肖。所以北秽,厭學(xué)的人當(dāng)不了好程序員,也干不長(zhǎng)最筒。

編碼習(xí)慣贺氓,相對(duì)次之。部分觀點(diǎn)認(rèn)為床蜘,這東西伴隨一生辙培,如果一開(kāi)始沒(méi)有好習(xí)慣,這輩子都沒(méi)辦法改了悄泥。Boss就是這么認(rèn)為的虏冻,我倒是不這么認(rèn)為。我相信編碼習(xí)慣的可塑性是很高的——你不按規(guī)范寫(xiě)弹囚,我不給你merge厨相,改不改?

但是鸥鹉,編碼習(xí)慣作為程序員的軟技能蛮穿,還是可以一定程度上看出其技術(shù)素養(yǎng)、代碼質(zhì)量的毁渗。至于優(yōu)雅什么的践磅,我其實(shí)沒(méi)有真的敢這么期待。

所以灸异,我這道題其實(shí)是考察這四點(diǎn)府适。

  1. 能寫(xiě)出來(lái),并且無(wú)明顯問(wèn)題肺樟,代表Java基本功扎實(shí)檐春。
  2. 理解我對(duì)題目的描述,和我確認(rèn)清楚題目的細(xì)節(jié)么伯,這是看溝通能力疟暖。
  3. List接口不知道,我給你啊俐巴;插入排序不會(huì)骨望,我教你啊欣舵;其它還有什么不會(huì)擎鸠,你問(wèn)啊——這是在考察學(xué)習(xí)能力。
  4. 代碼的字里行間邻遏,可以明顯看出編碼習(xí)慣糠亩。

面試結(jié)果

總體來(lái)說(shuō),我很傷心准验。

第一位就讓我很傷心赎线,當(dāng)我看了他前兩行代碼,就不忍心接著往下看:

private static List<Integer> sSorted = new LinkedList<>();
public static void addElement(int e) {
    if (null == sorted) {
        sorted.add(e);
    }
    // I couldn't read more!

第一行就編譯不過(guò)糊饱。如果他對(duì)Java的一些命名規(guī)范有一定的了解垂寥,就絕不會(huì)把sSorted寫(xiě)成sorted。(當(dāng)然另锋,sSorted也許并不是合適的命名方式滞项,因?yàn)閟和m這類(lèi)前綴有些冗余。我通常遵守Android源碼的通用規(guī)范夭坪,它是有這類(lèi)前綴的文判。)
第二行必然拋出NullPointerException,而不知道是該慶幸還是悲傷的是室梅,它永遠(yuǎn)執(zhí)行不到戏仓。根據(jù)我已經(jīng)給出的一個(gè)接口addElement,和可以猜到或者問(wèn)出來(lái)的讀取接口亡鼠,都是不會(huì)把sSorted變成null的赏殃。這體現(xiàn)了溝通、理解能力的一點(diǎn)問(wèn)題间涵。
此外仁热,即使sSorted因?yàn)槭裁碽ug而變成null,這里也不應(yīng)該做處理勾哩,而是任其拋出NullPointerException抗蠢,或者轉(zhuǎn)義一下,主動(dòng)拋出IllegalStateException思劳。否則迅矛,此處將變成一個(gè)不會(huì)crash的隱藏bug。不能用正常處理敢艰,代替異常處理诬乞;當(dāng)然册赛,也不能用異常處理钠导,代替流程控制震嫉。

另外,更令我失望的是牡属,有一位是這么寫(xiě)的:

for (int i = 0; i < sSorted.size(); i++) {
    if (e == sSorted.get(i)) {
        sSorted.add(i, e);
    }
}

我問(wèn)他票堵,如果這個(gè)元素不在這個(gè)List里存在怎么辦?如果這個(gè)List是空的怎么辦逮栅?他頓時(shí)一囧悴势,我也一起囧,心想自己是不是太壞了措伐。

還有一位特纤,仿佛聽(tīng)見(jiàn)了我這幾個(gè)問(wèn)題,他竟然一一作答:

if (sSorted.size == 0) {
    sSorted.add(e);
    return;
}
if (e >= sSorted.get(sSorted.size - 1)) {
    sSorted.add(e);
    return;
}
if (e <= sSorted.get(0)) {
    sSorted.add(0, e);
    return;
}
if (sSorted.contains(e)) {
    sSorted.add(sSorted.indexOf(e), e);
    return;
}
// more...

他想干什么呢侥加?也許是優(yōu)化性能吧捧存,只能這么幫腔了。另外担败,他對(duì)size的理解昔穴,和數(shù)組的length相同。
這位算是經(jīng)驗(yàn)比較豐富(30歲)提前,對(duì)Java的理解比較深入的了吗货。他說(shuō)排序不需要手寫(xiě),Java里有現(xiàn)成的接口狈网。我說(shuō)宙搬,是這樣沒(méi)錯(cuò),但接口我沒(méi)給出孙援,如果你記得害淤,那就寫(xiě)出來(lái)吧。
于是他在剛才那一大段“優(yōu)化”的后面拓售,這么寫(xiě)了:

sSorted.add(e);
sSorted.sort(new Comp...able() {
    public boolean ?(left, right) {
        return right >= left;
    }
});

思路上窥摄,插入后再排序,我先不吐槽础淤。我明明說(shuō)了“記得”再寫(xiě)崭放,這Comparable及其接口int compareTo(T another)如果記不清,我就當(dāng)看lambda表達(dá)式了鸽凶”疑埃可是,他這個(gè)?分明是Comparator的int compare(T lhs, T rhs)接口呀玻侥!
不過(guò)决摧,其實(shí)這些我都可以捏著鼻子認(rèn)了,因?yàn)槲乙彩謱?xiě)不出來(lái)。但List是沒(méi)有sort方法的呀掌桩!
Arrays和Collections才有各自的sort方法边锁,它倆算是銀彈型工具類(lèi),而Array和Collection是沒(méi)有的波岛。這個(gè)細(xì)節(jié)茅坛,誰(shuí)用誰(shuí)知道,知道了就絕不會(huì)記錯(cuò)则拷,盡管就差一個(gè)s贡蓖。

還有一位,他先插入煌茬、再冒泡排序斥铺,是這么寫(xiě)的:

sSorted.add(e);
for (int i = 0, sSorted.size(i) > sSorted.get(e), i++) {
    temp = sSorted.get(e);
    sSorted.get(e) = sSorted.size(i);
    sSorted.size(i) = temp;
}
  1. 你沒(méi)看錯(cuò),for()里面是,分隔的坛善。
  2. 你沒(méi)看錯(cuò)仅父,temp是從石頭縫里蹦出來(lái)的。
  3. 你沒(méi)看錯(cuò)浑吟,List.get(e)是可以對(duì)其賦值的笙纤。
  4. 你沒(méi)看錯(cuò),List.size(i)是可以傳參數(shù)進(jìn)去的组力。

還有兩位省容,直接交白卷放棄了。
其中一位還比較認(rèn)真燎字,思考了一會(huì)兒腥椒,說(shuō)“我不想浪費(fèi)時(shí)間”。
我沒(méi)亂用詞候衍,他確實(shí)“比較認(rèn)真”笼蛛。另一位在我遞過(guò)去后,直接看兩眼就遞回來(lái)蛉鹿,“排序我不會(huì)”滨砍,然后看手機(jī)去了。

參考答案

我自己在紙上寫(xiě)的時(shí)候妖异,花了大概5分鐘去思考細(xì)節(jié)惋戏,再花5分鐘寫(xiě)出來(lái)。(唉……一不小心他膳,又暴露了自己奇慢無(wú)比的思維响逢,以及奇慢無(wú)比的寫(xiě)字速度。)這比我此前預(yù)計(jì)的時(shí)間多了好幾倍棕孙!

不過(guò)舔亭,以我給的15~25分鐘些膨,應(yīng)該不算太難為人……吧?

class Solution {
    private static List<Integer> sSorted = new LinkedList<>();

    public static void addElement(int e) {
        int i;
        for (i = 0; i < sSorted.size(); ++i) {
            if (e <= sSorted.get(i)) {
                break;
            }
        }
        sSorted.add(i, e);
    }
}

這是我自己在紙上寫(xiě)的答案钦铺。(如果有興趣傀蓉,可以停在此處,考慮下這是否是最優(yōu)算法职抡。)

@Override
    public E get(int location) {
        if (location >= 0 && location < size) {
            Link<E> link = voidLink;
            if (location < (size / 2)) {
                for (int i = 0; i <= location; i++) {
                    link = link.next;
                }
            } else {
                for (int i = size; i > location; i--) {
                    link = link.previous;
                }
            }
            return link.data;
        }
        throw new IndexOutOfBoundsException();
    }

這是 java.util.LinkedList在Android(API 23)上的實(shí)現(xiàn),而反編譯Oracle JDK 1.8的實(shí)現(xiàn)也大同小異误甚。也就是說(shuō)缚甩,我寫(xiě)的答案雖然看似簡(jiǎn)潔,但其最壞時(shí)間復(fù)雜度與先插入再排序也沒(méi)太大區(qū)別窑邦,都是O(n2)擅威。
終日打燕,反而被燕啄了眼8郧铡(暴露了真實(shí)水平郊丛。)
我后來(lái)又寫(xiě)了一個(gè)參考答案,算是勉強(qiáng)在臉上摸了些防曬霜瞧筛。(大家有興趣可以想想為什么這是一個(gè)改進(jìn)厉熟。當(dāng)然,一定還有更好的方案较幌。)

class Solution {
    private static List<Integer> sSorted = new LinkedList<>();

    public static void addElement(int e) {
        int i = 0;
        for (int j : sSorted) {
            if (e <= j) {
                break;
            }
            ++i;
        }
        sSorted.add(i, e);
    }
}

(我沒(méi)有在提示列表中給出迭代器揍瑟,結(jié)果自己也被晃過(guò)去了。)

隱藏的殺手锏

面試官在出題考察應(yīng)聘者時(shí)乍炉,應(yīng)聘者也在通過(guò)這道題考察這家公司绢片。

為了避免讓人覺(jué)得這家公司考題太簡(jiǎn)單、工作內(nèi)容太無(wú)趣岛琼、里面的員工(我)水平太低底循,我還準(zhǔn)備了一些后續(xù)問(wèn)題,由淺入深槐瑞,作為殺手锏熙涤。

  1. 為什么LinkedList可以賦值給List?
    考察多態(tài)(polymorphism)困檩。
  2. 為什么List<Integer>要寫(xiě)<>內(nèi)的內(nèi)容灭袁,而LinkedList<>()可以不寫(xiě)?
    考察泛型(generic)窗看。
  3. 為什么List里面是Integer茸歧,但放進(jìn)去和拿出來(lái)的都是int?
    (此處有坑显沈,其實(shí)拿出來(lái)的還是Integer软瞎。)
    考察基本數(shù)據(jù)類(lèi)型的自動(dòng)裝箱逢唤、拆箱(auto boxing/unboxing)。
  4. 如何在外面有多線程調(diào)用時(shí)涤浇,保證這個(gè)唯一的List的正確性鳖藕?
    考察synchronized和volatile。
  5. 如何在多線程狀態(tài)下的每一個(gè)線程只锭,各保持一個(gè)獨(dú)立的List著恩?
    考察ThreadLocal。

(當(dāng)然蜻展,還有一些和Android相關(guān)的問(wèn)題喉誊。)

我真心是沒(méi)想考算法,所以連算法復(fù)雜度的評(píng)估都沒(méi)打算問(wèn)纵顾。實(shí)際情況是伍茄,我往往沒(méi)有機(jī)會(huì)問(wèn)這些問(wèn)題,因?yàn)闆](méi)幾個(gè)人寫(xiě)出來(lái)施逾。

吐槽與建議

首先敷矫,噴一下大學(xué)擴(kuò)招……算了,不扯這么遠(yuǎn)了汉额。那兩位放棄做題的曹仗,一個(gè)是計(jì)算機(jī)學(xué)院的,一個(gè)是軟件工程學(xué)院的蠕搜。排序?qū)懖怀鰜?lái)整葡,竟然也是能畢業(yè)的!

有兩位是某App的開(kāi)發(fā)者讥脐。我把他們的App下載下來(lái)遭居,發(fā)現(xiàn)了一堆bug后,本來(lái)想忍忍旬渠、就當(dāng)沒(méi)看見(jiàn)俱萍、碼農(nóng)何苦為難碼農(nóng),然后手機(jī)發(fā)熱告丢、卡頓枪蘑、滅屏后幾乎點(diǎn)亮不了(內(nèi)存泄露吃光了RAM,導(dǎo)致系統(tǒng)進(jìn)程沒(méi)有內(nèi)存可用)岖免。過(guò)了一陣最終好了岳颇,我查看耗電排行,運(yùn)行10分鐘就高居榜首颅湘,耗了17%的電——我嚇得立刻卸載了话侧。一個(gè)第三方App能把系統(tǒng)給卡成這樣,一般人還真做不到闯参。

還有兩位是“相關(guān)專(zhuān)業(yè)”的瞻鹏,非計(jì)算機(jī)悲立、軟件工程專(zhuān)業(yè),反而表現(xiàn)最佳新博,雖然還是沒(méi)寫(xiě)出來(lái)薪夕。

他們無(wú)一例外,都是在大學(xué)以外赫悄,又參加過(guò)某些Java原献、Android培訓(xùn)的。這些培訓(xùn)班的水平埂淮,可見(jiàn)一斑姑隅。問(wèn)題倒不一定是培訓(xùn)班的教學(xué)質(zhì)量,而是這種大規(guī)模提供人才轉(zhuǎn)型服務(wù)的形式本身——這個(gè)世界上同诫,本來(lái)就不是誰(shuí),都能當(dāng)一個(gè)好碼農(nóng)樟澜,哪怕工作要求只是復(fù)制粘貼误窖。

現(xiàn)在,很多碼農(nóng)都戲稱(chēng)自己是在“搬磚”秩贰、復(fù)制粘貼霹俺,但實(shí)際上程序員的工作不可能僅止于此。使用別人寫(xiě)好的基本算法毒费,參考別人的實(shí)現(xiàn)代碼丙唧,只是為了集中精力去解決抽象層次更高的業(yè)務(wù)問(wèn)題。

“我們不寫(xiě)代碼觅玻,我們只做代碼的搬運(yùn)工想际。”——萬(wàn)萬(wàn)不可把這句話當(dāng)做信條溪厘。

還有很多人胡本,在沒(méi)有Demo的情況下,無(wú)論給多么詳細(xì)的API或其它資料畸悬,仍然無(wú)法寫(xiě)代碼侧甫。他們只能在既有的基礎(chǔ)上,修修補(bǔ)補(bǔ)蹋宦,無(wú)法憑空創(chuàng)作披粟。

我推薦三本Java的基礎(chǔ)書(shū):

  • 《Java編程思想》(Think in Java)
    這本是最合適的Java語(yǔ)言入門(mén)書(shū)。其它很多語(yǔ)法書(shū)都是從C/C++的角度來(lái)講Java的變化冷冗,或者從C++的思路來(lái)討論Java怎么用守屉,而這本書(shū)的英文名則直接告訴你,請(qǐng)用Java來(lái)思考蒿辙、解決問(wèn)題胸梆。

  • 《Effective Java》
    Java中有很多坑敦捧,Java中也有很多糖。如果沒(méi)有看過(guò)這本書(shū)碰镜,那么不知不覺(jué)就會(huì)犯很多大忌兢卵。

  • 《代碼整潔之道》(Clean Code)
    我是在獨(dú)立寫(xiě)一個(gè)小項(xiàng)目的時(shí)候開(kāi)始看的⌒饔保看到一半時(shí)項(xiàng)目也寫(xiě)到一半秽荤,頓時(shí)連代碼都不會(huì)寫(xiě)了!每天都在寫(xiě)自己看不下去的代碼柠横,而不知道怎么寫(xiě)能看得過(guò)眼的窃款。加速看完后,重新開(kāi)始會(huì)寫(xiě)代碼牍氛。最終晨继,項(xiàng)目后半部分的代碼,和前半部分完全不同搬俊,不像一個(gè)人寫(xiě)的紊扬,我后來(lái)又重構(gòu)了一遍。

(為什么我不多推薦點(diǎn)書(shū)呢唉擂?一來(lái)餐屎,是我本人也沒(méi)看過(guò)多少,囧玩祟;二來(lái)腹缩,三本是極限,根據(jù)我的經(jīng)驗(yàn)空扎,推薦三本可以讓人看一本藏鹊,推薦三本以上,受眾一本也不會(huì)看转锈。)

我有一個(gè)朋友伙判,也是一個(gè)前同事,好學(xué)如好色黑忱。他周末都在找一個(gè)大學(xué)教室看書(shū)宴抚,甚至有時(shí)請(qǐng)年假去教室看書(shū)。一本《Java編程思想》甫煞,逐行精讀三遍以上菇曲。工作經(jīng)驗(yàn)不足兩年,跳槽三次抚吠,現(xiàn)在在一家百億級(jí)上市公司常潮,年薪三十萬(wàn),統(tǒng)率十人楷力。

究其原因喊式,無(wú)非基礎(chǔ)知識(shí)扎實(shí)孵户,口水噴死面試官爾

后記

我作為一個(gè)面試別人的初哥,一心只想著自己喜歡的抽插……呃不岔留,插入排序算法夏哭,給別人造成了不必要的麻煩,只能說(shuō)抱歉了献联。

和我一起面試的竖配,還有一個(gè)負(fù)責(zé)文檔和規(guī)范的妹子(前面提到過(guò)的那個(gè))。她也是有一票否決權(quán)的里逆,而且用得比我更頻繁进胯!

我最多只給交白卷的,和那個(gè)耗電超恐怖的App原押,這幾個(gè)人直接否決胁镐。而這個(gè)妹子,考察對(duì)方的其它綜合能力诸衔。

在實(shí)際工作中盯漂,她是需求的接口人,我們需要和她溝通署隘,實(shí)現(xiàn)各方對(duì)我們團(tuán)隊(duì)的需求宠能。所以亚隙,只要她說(shuō)一句“我和這個(gè)人難以溝通”磁餐,那么Boss基本上就直接拒絕了。

下次我還是換一道更簡(jiǎn)單的吧阿弃,碼農(nóng)何苦為難碼農(nóng)诊霹。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市渣淳,隨后出現(xiàn)的幾起案子脾还,更是在濱河造成了極大的恐慌,老刑警劉巖入愧,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鄙漏,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡棺蛛,警方通過(guò)查閱死者的電腦和手機(jī)怔蚌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)驻民,“玉大人震放,你說(shuō)我怎么就攤上這事拳恋“竦” “怎么了籍胯?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵竟闪,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我杖狼,道長(zhǎng)炼蛤,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任本刽,我火速辦了婚禮鲸湃,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘子寓。我一直安慰自己暗挑,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開(kāi)白布斜友。 她就那樣靜靜地躺著炸裆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪鲜屏。 梳的紋絲不亂的頭發(fā)上烹看,一...
    開(kāi)封第一講書(shū)人閱讀 51,287評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音洛史,去河邊找鬼惯殊。 笑死,一個(gè)胖子當(dāng)著我的面吹牛也殖,可吹牛的內(nèi)容都是我干的土思。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼忆嗜,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼己儒!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起捆毫,我...
    開(kāi)封第一講書(shū)人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤闪湾,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后绩卤,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體途样,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年濒憋,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了何暇。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡跋炕,死狀恐怖赖晶,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤遏插,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布捂贿,位于F島的核電站,受9級(jí)特大地震影響胳嘲,放射性物質(zhì)發(fā)生泄漏厂僧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一了牛、第九天 我趴在偏房一處隱蔽的房頂上張望颜屠。 院中可真熱鬧,春花似錦鹰祸、人聲如沸甫窟。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)粗井。三九已至,卻和暖如春街图,著一層夾襖步出監(jiān)牢的瞬間浇衬,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工餐济, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留耘擂,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓絮姆,卻偏偏與公主長(zhǎng)得像醉冤,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子滚朵,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容