1. 程式人生 > >《Java程式設計》第七次學習總結

《Java程式設計》第七次學習總結

《Java程式設計》第七次學習總結

目錄

教材學習內容總結

教材學習中的問題和解決過程

程式碼除錯中的問題和解決過程

其他(感悟、思考等,可選)

正文

教材學習內容總結

學習了第十一章“異常”和第十二章“遞迴”。自己思考後總結如下:

  • 第十一章
    • 異常就是那些有可能出現錯誤的情況,而不是一定就是錯誤。
    • 異常分為兩類:“必檢異常”和“非必檢異常”,在有可能會丟擲“必檢異常”的方法名後面得加上 throws() 關鍵字,方法體中用throw 來丟擲可能發生的異常。
    • try()catch(){} 語句塊中可以有多個 catch(){} 欄位,分別來對應處理可能會出現的錯誤。
    • 如果有try()catch(){}欄位,則代表:對相應的異常進行了捕獲並處理 ,那麼異常發生後面的程式也可以被執行。反之,如果沒有try...catch 欄位則一遇到異常就會終止這段程式的執行,如果是被呼叫的則轉向呼叫的方法那裡,如果是main方法就直接結束整個程式了,並且打印出棧呼叫的軌跡和相應的異常資訊。
    • 不論是正常退出try塊,還是因丟擲一個異常而退出try塊,都要執行finally字句。
  • 第十二章 : recursion
    • 遞迴的思想:自己呼叫自己來解決問題。有個例子是:用decorate 來解釋decarate的意思。包括自己在學c語言時候就知道的用遞迴的方法來解決階乘的問題。
    • 關於遞迴,新的收穫有:其實一個遞迴有兩部分組成:
      • 基礎情形:base case;
      • 呼叫自身的過程。
    • 這裡的基礎情形可以讓呼叫自身這個過程不會無休止的進行下去(即:不會產生無窮遞迴),當自身呼叫自身過程到了base condition時,就會執行base condition 並且沿著一開始呼叫自身的“路徑”,開始往回“走”,一層一層的返回得到的值,只到回到最初的那個呼叫自身的開始處。
    • 由上面那個遞迴由兩部分構成這個結論,可以想到:實現遞迴最基本的結構就是 if-else 語句,用if-else其中某個分支來處理基礎情形(base case)的情況,另外一個分支負責來呼叫自身。
    • 每次呼叫自身,都會導致方法中的區域性變數重新被更新,而且,在往回走的時候區域性變數會自動回到上一次呼叫它時候的值,概念就是:形參在函式內的變化不會傳遞到呼叫這個函式的實參上。
    • 直接遞迴和間接遞迴。
    • 關於遞迴的書上的例子說明:

回到目錄

教材學習中的問題和解決過程

  • 問題一:關於 throws關鍵字和throw的區別,還有try-catch語句塊。問題的詳細描述如下:什麼時候需要用到throws?用在哪裡?throw關鍵字也是有同樣的問題?很明顯的一個就是,好像在使用java自帶的又可能出現異常的方法的時候就不需要用到throwsthrow關鍵字了,如果要捕獲異常得用到try-catch語句塊。但是,如果你自己程式設計序來自定義一個自己想要的必檢異常,那麼則需要用到throws關鍵字來附加到函式名字的尾部,同時,在會發生異常的部分來使用throw關鍵字來丟擲異常。同理捕獲得用那個語句塊。
  • 解決方法:上面自己的想法,大部分是對的。理一下:異常分為系統給出的異常,以及你自定義的異常。
    • 系統給出的異常中有必檢和非必檢兩大類,在呼叫這個有可能會出現異常的方法時,必須得在try語句塊中呼叫,否則會報錯“未報告異常錯誤”。
    • 自定義異常時就是得同時用到throwsthrow,這兩個關鍵字。
      throws是用在方法名的後面 throws xxxxException,這個方法就是那個可能會出現異常的方法。而throw關鍵字是用在這個方法體之中,通常是在一個if-else的某一個分支中,這個分支對應了出現了異常時應該進行的操作,即:使用throw關鍵字來丟擲異常類物件。異常類是你自己自定義的異常類xxxxException。定義這個異常類時注意是用到extend關鍵字來繼承Exception類的。

程式碼除錯中的問題和解決過程

  • 問題一:在程式設計時出現了,以前遇到過的“無限迴圈”的情形,明明輸入了停止字串,但是依然不能夠終止程式的執行。程式碼如下:
  • 解決方法:就如自己所感受到的,明明輸入了"DONE"但是程式並不會停止執行,其實應該很自然的想到是控制迴圈的條件出了問題,但是我是通過在IDEA中進行Debug來發現是控制迴圈的條件 "DONE" != str_input有問題的,我發現我輸入的"DONE"字串str_input根本和不等號的右邊 "DONE" 是不等的。然後就知道了,什麼是物件的別名,什麼是物件的引用,我上圖程式中的做法是在比較 str_input這個 “門牌號” 會不會等於DONE,這當然永遠不等啊!而我的初衷是想比較 str_input這個“門牌號”對應的房間裡住著的內容是不是DONE,不是來比較“門牌號”的。 所以正確的做法如下圖:

這裡充分體現了“門牌號”的概念,而且我自己編了一個程式,所以對書上之前講的一點內容有了更深入的理解:自己編的程式如下圖所示:

實際上,字串常量str3就是一個給門牌號賦值的過程,它使得str3這個門牌號就是Hello,而不是像str1或者str2那樣的數字門牌號,所以那一條語句才是真的。
書上的內容如下:

由此可見:在比較物件時,“ == ” 是用來判斷這個關係操作符左右兩邊的“門牌號”是否是貼在一個房間的門上,如果這兩個門牌號對應是兩個單獨的房間則是不等的,只有兩個門牌號貼在同一個房間上才是等的。

所以,比較字串物件內容是否是相等的,只能呼叫方法equals(),不能用關係操作符 “==”, 這是和麵向過程程式設計不同的!

  • 問題二:遞迴呼叫時:成員變數和區域性變數的差別。
  • 解決方法:這個問題出現的主要願意是在編pp12.9時出現的,原來的程式如下圖:

length 是一個區域性變數,每次遞迴呼叫時都會重新初始化,並且返回時,也能夠正常返回到原來的初始值。但是 n 就不一樣了,n是一份成員變數,我每次遞迴呼叫getValue()方法時,n的確初始值是對的,因為有 n = number,每次遞迴呼叫時的 number是在變化的,但是遞迴返回時,就有問題了,遞迴返回時,因為n 是成員變數,所以你在 getValue()方法中對 n 進行的操作都會被儲存著,它並不像形參 number 那樣對實參沒有影響,n並不能回到呼叫它時侯的方法。
這一點通過Debug也能看出來,所以,在用遞迴程式設計時候,儘量去用區域性變數,而不是去用成員變數。

  • 問題三:是在做pp11.1時候出現的,關於Scanner類中的方法next()
  • 解決方法:要知道,每使用一次scan.next()方法一次,就是相當於呼叫了一次這個方法了,這樣的話就是相當於要使用者輸入了兩次。但是我的初衷只是,在第二次用scan.next() 時把第一次呼叫該方法的值得到。所以,正確的做法是,把第一次呼叫next()方法,得到的值儲存在一個門牌號對應的房間裡。然後,後面在用這個房間裡的東西來進行比較。下面是一開始的錯誤程式碼:

  • 改正以後就出現了上面第一張圖裡的str_input變數名。

其他(感悟、思考等,可選)

這一次的學習讓我對遞迴有了更深的瞭解,同時也反映了我以前基礎不紮實的事實。但是,自己能夠編寫程式來驗證自己的猜想,是一個很不錯的做法。就是想自己來猜想 ==這個運算子的時候,一開始還沒有反應過來這是門牌號的差異。所以就想著自己編個簡單的程式來驗證一下 == 真的不能用來比較相等嗎?一程式設計序,發現真的不對,然後就去反思了。所以,以後出現了問題,真的可以嘗試編一個簡單的小程式來驗證自己的想法。

學習進度條

程式碼行數(新增/累積) 部落格量(新增/累積) 學習時間(新增/累積) 重要成長
目標 5000行 30篇 400小時
第七次 2329/5000 1/18 無記錄 遞迴和驗證的方法思想
[回到目錄](#index)

回到目錄

參考資料

  • [Java程式設計(第8版)]
  • [《Java程式設計基礎(第2版)》耿祥義]