一、前言 雖說上學期為了助眠看了一點 Java 但是散而不精,看而不敲,所以這學期正式學 Java 並沒有想想中那麼容易... 直觀感受:Java有很多和C/C不一樣的地方,Java太嚴謹了,但是相比C/C來說也更安全(不需要領著指針亂跑).... 前三次PTA題目集的小總結 總體來看,前兩次的題目 ...
目錄
一、前言
雖說上學期
為了助眠看了一點 Java 但是散而不精,看而不敲,所以這學期正式學 Java 並沒有想想中那麼容易...直觀感受:Java有很多和C/C++不一樣的地方,Java太嚴謹了,但是相比C/C++來說也更安全(不需要領著指針亂跑)....
前三次PTA題目集的小總結
總體來看,前兩次的題目集偏基礎一點,會使用簡單的迴圈結構、條件判斷、格式化輸出和字元串操作便可輕鬆滿分,題量難度都不算大,但是第三次的題目集便立馬感受到了壓力;
第三次的題目集不僅提高了對Java基礎的要求,還要求從面向過程的思路轉化到面向對象的思維上,在做題前看題便可以註意到,若不使用類和對象便會大大增加代碼量且不易於維護,另外,第三次題目集還對輸入格式的把控提出了苛刻的要求,還要求將數學知識運用到程式中,並時刻註意變數的存儲類型和輸出格式。最重要的是在動手寫之前構思:如何分配對象的方法,如何聯繫對象與對象之間.....
二、設計與分析
題目集2_7-2
源碼的生成報表
代碼類圖
分析 : 一眼丁真:純純的面向過程,代碼簡潔,充斥著
if-else
,可讀性不是很高
題目集3_7-1
源碼的生成報表
代碼類圖
分析 : 相比之前,有了更多的方法,代碼量也隨之增加
題目集3_7-2
源碼的生成報表
代碼類圖
分析 : 使用了更多的類,並以對象進行數據計算代碼清晰了很多
題目集3_7-3
源碼的生成報表
代碼類圖
分析 : 使用了更多的類,並以對象進行數據計算代碼清晰了很多
三、採坑心得
這波?這波是
Java
搞偷襲,是我大意了啊,沒有閃。但沒關係....$%^&%$!$%$'']$]!]@.~\·.!@^[\//*';]/=/[/[\&/]]@=/]/!\-[/-'%/¥
1)數據存儲與輸出
為無限迴圈浮點數保留規定位數並四捨五入
需求:在不知道浮點數的位數是否有限的情況下,為無限迴圈浮點數保留規定位數並四捨五入
踩坑筆記
踩坑思路:
printf
會自動四捨五入,所以直接使用printf格式化輸出
//假定要保留六位小數 public static void main(String[] args) { Scanner in = new Scanner(System.in); float a = in.nextFloat(), b = in.nextFloat(); System.out.printf("a/b: %.6f a+b: %.6f", a / b, a + b); }
發現問題:
a/b
是確確實實按6位保留並四捨五入了,但是a+b
本應輸出5.0
卻也多了幾個0//輸入 2 3 //輸出 a/b: 0.666667 a+b: 5.000000
影響:PTA答案錯誤!
解決方法
問題分析:
%f
會一視同仁格式化所有浮點數,所以只要讓其該根據數據位數來選擇是否要格式化為6位即可正確寫法:
//假定要保留六位小數 public static void formatPrint(float n) { final int esp = (int)1e6; if(((n*esp)%10)!=0) //小數點後第六位數不為0 System.out.printf("%.6f",n); //格式化輸出 else System.out.print(n); } public static void main(String[] args) { Scanner in = new Scanner(System.in); float a = in.nextFloat(), b = in.nextFloat(); System.out.print("a/b: "); formatPrint(a/b); System.out.print(" a+b: "); formatPrint(a+b); }
問題解決:
//輸入 2 3 //輸出 a/b: 0.666667 a+b: 5.0
反思:若第6位恰好是0呢?是否可以用
String.format()
格式化輸出?
2)其他
忽略if( )
中的判斷順序
需求:將字元串根據逗號
,
或者空格來分割成若幹部分字元串,並轉化為實數
踩坑筆記
踩坑原因:將迴圈邊界判斷放在了
charAt()
之後public static void main(String[] args) { Scanner in = new Scanner(System.in); String str = in.nextLine(); String[] nums = new String[10]; int idx=0; for(int i=0,j=0;i<=str.length();i++){ if(str.charAt(i)==',' || str.charAt(i)==' ' || i == str.length()){ nums[idx++] = str.substring(j,i); j = ++i; } } System.out.println(nums[0] + " " + nums[1] + " " + nums[2] + " " + nums[3]); }
發現問題:
數組越界?
//輸入 12,23 34.1,45 //報錯 Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 13 at java.base/java.lang.StringLatin1.charAt(StringLatin1.java:47) at java.base/java.lang.String.charAt(String.java:693) at Main.main(Main.java:24)
影響:程式運行異常終止
解決方法
問題分析:根據調試發現,
if()
括弧中的判斷遵循從左到右順序,由於i == str.length()
放在最後,所以先判斷str.charAt(i)
但是迴圈的條件是i<=str.length()
會使str.charAt(i)
越界正確寫法:
public static void main(String[] args) { Scanner in = new Scanner(System.in); String str = in .nextLine(); String[] nums = new String[10]; int idx=0; for(int i=0,j=0;i<=str.length();i++){ //先判斷i是否為末位 if(i==str.length() || str.charAt(i)==',' || str.charAt(i)==' '){ nums[idx++] = str.substring(j,i); j = ++i; } } System.out.println(nums[0] + " " + nums[1] + " " + nums[2] + " " + nums[3]); }
問題解決:
//輸入 12,23 34.1,45 //輸出 12 23 34.1 45
反思:挺完美了吧(指按格式正常輸入的話)
C/C++帶來的壞習慣
需求:簡化題目中多組數據的輸入,
踩坑筆記
踩坑原因:不知
Java
的類型一定要完全匹配//輸入T為組數,每組輸入一個數並將其輸出 public static void main(String[] args) { Scanner in = new Scanner(System.in); int T = in.nextInt(); int t; while(T--){ t = in.nextInt(); System.out.println(t); } }
影響:直接error
解決方法
問題分析:C/C++中,
0
是false
,非0
的數便是true
,但Java
不這麼認為,所以只要將int
轉化為boolean
就好正確寫法:
//輸入T為組數,每組輸入一個數並將其輸出 public static void main(String[] args) { Scanner in = new Scanner(System.in); int T = in.nextInt(); int t; while(T-->0){ t = in.nextInt(); System.out.println(t); } }
問題解決:
3 //輸入 111 //輸入 111 222 //輸入 222 333 //輸入 333 //進程已結束,退出代碼0
反思:若每組數據要輸入String,怎麼使其不讀入組數後的回車?
四、改進建議
由於前期的小題不需要有整體的構思,導致第三次實驗潦草起手,使得後期維護難上加難,所以動手之前應該考慮工程大小、各部分的責任範圍、
引言:貫穿始終的一條原則就是“想好再做”。如果實在“想不好”,那就“做一點”,出了問題再“好好想”。在實踐中,“做一點”的度很難把握,常常是開了閘就一瀉千里。怎麼判斷這個度呢?我覺得說到底是你對程式的掌控感,要保持程式始終在你的控制之下。比如如果一個函數超過了50行,就是一個危險的信號。
————————————————原文鏈接:https://blog.csdn.net/RiderOnStorm/article/details/594775
在第三次作業最開始的版本中,有很嚴重的代碼複製情況://比如這段 作用是將字元串從第二位下標開始,根據空格和逗號分割為若幹部分字元串,並將其轉化為實數存於數組 public static void main(String[] args) { Scanner in = new Scanner(System.in); String str = in.nextLine(); int choice = str.charAt(0) - '0'; str = str.substring(2); //跳過開始的兩個字元 String[][] nums = new String[4][]; String[] location = str.split(" "); //按空格分為若幹個字元串數組 for (int i = 0; i < 4; i++) nums[i] = location[i].split(","); //按逗號分為若幹個字元串數組 float[] fls = new float[8]; fls[0] = Float.parseFloat(nums[0][0]); fls[1] = Float.parseFloat(nums[0][1]); fls[2] = Float.parseFloat(nums[1][0]); fls[3] = Float.parseFloat(nums[1][1]); fls[4] = Float.parseFloat(nums[2][0]); fls[5] = Float.parseFloat(nums[2][1]); fls[6] = Float.parseFloat(nums[3][0]); fls[7] = Float.parseFloat(nums[3][1]); for (float j : fls) System.out.println(j); //僅供測試功能 } //////////////////////////////////////////////////// //輸入 1:1,2 3,4 5,6 7,8 //輸出 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 ////////////////////////////////////////////////////
其他地方或許只是數量不同
public static void main(String[] args) { Scanner in = new Scanner(System.in); String str = in.nextLine(); int choice = str.charAt(0) - '0'; str = str.substring(2); String[][] nums = new String[4][]; String[] location = str.split(" "); for (int i = 0; i < 3; i++) nums[i] = location[i].split(","); float[] fls = new float[6]; fls[0] = Float.parseFloat(nums[0][0]); fls[1] = Float.parseFloat(nums[0][1]); fls[2] = Float.parseFloat(nums[1][0]); fls[3] = Float.parseFloat(nums[1][1]); fls[4] = Float.parseFloat(nums[2][0]); fls[5] = Float.parseFloat(nums[2][1]); for (float j : fls) System.out.println(j); }
還有好幾段這樣類似的代碼,因為寫的過程中為了縮短工期而寫出的
屎山
明顯看到,可以對其進行優化,大大提升可維護性,並使代碼更簡潔
public static void main(String[] args) { Scanner in = new Scanner(System.in); String str = in.nextLine(); int choice = str.charAt(0) - '0'; str = str.substring(2); String[][] nums = new String[4][]; int len = 4; float[] fls = transform(len, str, nums); //傳入數據 for (float j : fls) System.out.println(j); } public static float[] transform(int size, String str, String[][] num) { float[] res = new float[2 * size]; String[] location = str.split(" "); for (int i = 0; i < size; i++) num[i] = location[i].split(","); ////////////////////這真的算是變‘簡潔’了嗎。。。 for (int i = 0, j = 0, k = 0; i < 2 * size; i++, k++, j += k / 2, k %= 2) { res[i] = Float.parseFloat(num[j][k]); } return res; } ///////////之前怎麼寫不出呢 ?_?
五、總結
通過該階段的學習,學到了程式基本的整體構思思路、類與類的分工。但對於輸入數據格式問題,仍存在考慮不全不周的問題,需要在今後的學習中著重註意。
對作業的感覺:挺有挑戰性的,值得一做!
對今後學習方法的建議:不要只看不敲,看懂不等於學會,當然,若能用最精簡的語言點通不懂的人,那便證明你真正學到點東西了。