<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
本文 Github.com/niumoo/JavaNotes 和 未讀程式碼部落格 已經收錄,有很多系列文章。
今天一個很簡單的功能,觸發了一個 BUG,處理後我想起了最近爆火的 ChatGPT,於是我嘗試測試 ChatGPT 能否發現這個 BUG。這篇文章會先介紹功能程式碼,然後手動分析 BUG 原因;接著測試 ChatGPT 能否發現這個 BUG。
先說下結論,測試結束,ChatGPT 今後可能是我程式設計路上的好幫手。
今天在測試一個準備上線的新功能時,裡面有一段簡單的函數,出現了一個 BUG。我先說一下這個函數的功能,看下你會怎麼寫。
功能描述
輸入:一個資料夾路徑。
輸出:這個資料夾中的資料夾數量。
這是一個實現起來比較簡單的函數,我順手寫了下面的程式碼:
String pathString = "/Users/darcy/"; File fileDir = new File(pathString); if (!fileDir.exists() || !fileDir.isDirectory()) { throw new RuntimeException("xxx...."); } String[] fileList = fileDir.list(); int count = 0; for (String filePath : fileList) { if (new File(pathString + filePath).isDirectory()) { count++; } } System.out.println(count);
功能是實現了,但是很明顯,程式碼比較繁瑣,於是我又順手優化了一下。
Path path = Paths.get("/Users/darcy/"); if (!Files.exists(path) || !Files.isDirectory(path)) { throw new RuntimeException("xxx...."); } long dirCount = Files.list(path).filter(Files::isDirectory).count(); System.out.println(dirCount);
效果是一樣的,因為使用了 JDK 7 引入的 Files 類,讓程式碼簡單了不少。
不過正是這段程式碼,觸發了 BUG,我先賣個關子,你先看下 BUG 在什麼地方。
你看出問題了嗎?改造後的程式碼執行少量次數的情況下,都是可以正常輸出的。但是它有一個問題,就是 Files.list 返回的 Stream 流沒有進行關閉,這就導致如果這段程式碼被頻繁的呼叫,一段時間後將會因為開啟的檔案過多而報錯,可以測試出這種異常情況。
在迴圈中不斷執行這段程式碼:
while (true){ Path path = Paths.get("/Users/darcy/"); if (!Files.exists(path) || !Files.isDirectory(path)) { throw new RuntimeException("xxx...."); } long dirCount = Files.list(path).filter(Files::isDirectory).count(); System.out.println(dirCount); }
一段時間後控制檯收到報錯:Too many open files
報錯的原因是因為每個程序可以開啟的檔案數量是有限制的,如果一直開啟不進行關閉,在達到限制時會報出這個錯誤。
不妨讓程式碼執行速度降低,然後監控下隨著程式的執行,執行程序持有的檔案數是否不斷增加。
while (true){ Path path = Paths.get("/Users/darcy/"); if (!Files.exists(path) || !Files.isDirectory(path)) { throw new RuntimeException("xxx...."); } long dirCount = Files.list(path).filter(Files::isDirectory).count(); System.out.println(dirCount); Thread.sleep(1000); }
下面是用到的命令。
## 查詢程序 ID ➜ ~ jps -mlVv | grep testFileList ## 檢視指定程序參照的檔案數量 ➜ ~ lsof -p 62248 | wc -l
從測試結果中可以看到隨著程式的執行,程序持有的檔案數量不斷上升。
原因已經知道了,既然 Files.list 返回的 Stream 流沒有進行關閉,那麼進行關閉就可以解決問題。
while (true){ Path path = Paths.get("/Users/darcy/"); if (!Files.exists(path) || !Files.isDirectory(path)) { throw new RuntimeException("xxx...."); } // 方式1:手動關閉流 // Stream<Path> pathStream = Files.list(path); // long dirCount = pathStream.filter(Files::isDirectory).count(); // pathStream.close(); // 方式2:使用 try resource 自動關閉流 try (Stream<Path> pathStream = Files.list(path);){ long dirCount = pathStream.filter(Files::isDirectory).count(); System.out.println(dirCount); } Thread.sleep(1000); }
再次執行後,參照的檔案數量不再上漲,BUG 解決。
➜ ~ lsof -p 62879 | wc -l 321 ➜ ~ lsof -p 62879 | wc -l 321 ➜ ~ lsof -p 62879 | wc -l 321 ➜ ~ lsof -p 62879 | wc -l 321 ➜ ~ lsof -p 62879 | wc -l 321 ➜ ~ lsof -p 62879 | wc -l 321
如果這段程式碼使用 ChatGPT 分析,它能發現問題嗎?我先告訴你答案,它能發現,而且描述的很好,並且給出了修復建議。
我問:
下面這段 Java 程式碼有什麼問題嗎?
Path path = Paths.get("/Users/darcy/"); if (!Files.exists(path) || !Files.isDirectory(path)) { throw new RuntimeException("fileDir.isDirectory() error"); } long dirCount = Files.list(path).filter(Files::isDirectory).count(); System.out.println(dirCount);
ChatGPT:
這段程式碼首先會檢查 /Users/darcy/
目錄是否存在並且是一個目錄,如果不是,則會丟擲 RuntimeException
。接著,它會計算 /Users/darcy/
目錄下的子目錄數量並將其列印到控制檯。
這段程式碼看起來沒有語法錯誤,但是在執行時可能會丟擲 IOException
,因為對檔案系統進行操作時可能會出現各種異常情況。特別是,如果指定的路徑不存在,則會丟擲 NoSuchFileException
。因此,在程式碼中最好捕獲可能發生的異常並進行處理,或者在方法簽名中宣告丟擲異常以通知呼叫方。
此外,還需要注意的是,Files.list(path)
方法返回的是一個 Stream<Path>
物件,需要注意其資源釋放問題,以避免潛在的資源洩漏問題。通常情況下,可以使用 try-with-resources
語句來自動關閉流,例如:
try (Stream<Path> stream = Files.list(path)) { long dirCount = stream.filter(Files::isDirectory).count(); System.out.println(dirCount); } catch (IOException e) { // 處理異常 }
下面是對話截圖:
問:
幫我用 Java 寫一串程式碼。 功能描述。
輸入:一個資料夾路徑。
輸出:這個資料夾中的資料夾數量。
ChatGPT 回答:
以下是 Java 程式碼範例,用於計算指定資料夾路徑下的資料夾數量:
import java.io.File; public class FolderCount { public static void main(String[] args) { String path = "path/to/folder"; // 替換成你的資料夾路徑 File folder = new File(path); int count = 0; if (folder.isDirectory()) { File[] files = folder.listFiles(); for (File file : files) { if (file.isDirectory()) { count++; } } } System.out.println("該資料夾中的資料夾數量為:" + count); } }
該程式首先接收一個資料夾路徑作為輸入,然後建立一個 File 物件來代表該資料夾。然後它遍歷該資料夾中的所有檔案,如果找到一個資料夾,則將計數器加一。最後,它輸出計數器的值作為結果。
下面是對話截圖:
在本文中,我們介紹了一個簡單功能的 Java 程式碼 BUG,即未關閉 Files.list()
返回的流物件,導致程式執行時可能會開啟過多的檔案而出現異常。我們通過手動分析程式碼和測試,找出了問題所在,並提供了兩種解決方案,一種是手動關閉流,另一種是使用 try-with-resources 自動關閉流。最後,我們還使用 ChatGPT 測試了是否可以用 AI 自動識別程式碼中存在的問題,結果表明 ChatGPT 可以幫助我們發現這類問題,為我們的程式設計工作提供了有力的支援。
上面這個總結,也是 ChatGPT 幫我寫的,相對於 ChatGPT 能給出具體的程式碼,我更震驚於 ChatGPT 對於語意的理解,不僅能理解我的輸入,還能對程式碼意思進行自然語言描述。今後你很可能分辨不出你所閱讀的文章是人類寫的,還是 ChatGPT 自動生成的。
以下測試結果都是 ChatGPT 的具體回答,我沒有改動一個字元。
幫我用 Java 寫一段程式碼。
輸入:一個時間字串,這個時間資訊包含年月日時分秒。
處理:提取時間字串中的月份 輸出:這個月份有多少天
ChatGPT 回答:
以下是一個範例Java程式碼,它接受一個時間字串作為輸入,並從中提取出月份並計算該月有多少天:
import java.time.*; import java.time.format.DateTimeFormatter; public class MonthDays { public static void main(String[] args) { String dateString = "2023-02-14 12:34:56"; // 輸入時間字串 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); LocalDateTime dateTime = LocalDateTime.parse(dateString, formatter); int daysInMonth = YearMonth.from(dateTime).lengthOfMonth(); // 提取月份並計算該月有多少天 System.out.println(daysInMonth); // 輸出該月天數 } }
在這個範例中,我們使用了Java 8引入的java.time
包來處理日期和時間。首先,我們將輸入時間字串解析為一個LocalDateTime
物件。然後,我們從LocalDateTime
物件中提取出年月,並使用YearMonth
類的lengthOfMonth()
方法計算該月份有多少天。最後,我們將該天數輸出到控制檯。
下面是測試截圖:
幫我用 Java 寫一段程式碼。
輸入:一個時間字串,這個時間資訊包含年月日時分秒。
輸出:把這個時間字串進行轉換。獲取這個時間當天的第三小時第一秒
ChatGPT 回答:
以下是用 Java 實現獲取輸入時間當天第三小時第一秒的程式碼範例:
import java.time.LocalDateTime; import java.time.LocalTime; import java.time.format.DateTimeFormatter; public class Main { public static void main(String[] args) { String timeString = "2023-02-14 12:34:56"; // 代表輸入的時間字串 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); LocalDateTime dateTime = LocalDateTime.parse(timeString, formatter); // 解析時間字串 // 獲取當天的3:00:01 LocalDateTime targetDateTime = LocalDateTime.of(dateTime.toLocalDate(), LocalTime.of(3, 0, 1)); System.out.println(targetDateTime); } }
解釋:
timeString
。DateTimeFormatter
類建立一個日期時間格式化器,以便將時間字串轉換為 LocalDateTime
物件。此處使用的格式化器模式字串為 "yyyy-MM-dd HH:mm:ss"
,其中:yyyy
代表四位數的年份,例如 2023。MM
代表兩位數的月份,例如 02。dd
代表兩位數的日期,例如 14。HH
代表兩位數的小時數(24 小時制),例如 12。mm
代表兩位數的分鐘數,例如 34。ss
代表兩位數的秒數,例如 56。LocalDateTime.parse()
方法將時間字串解析為 LocalDateTime
物件。LocalDateTime.toLocalDate()
方法獲取輸入時間所在的日期,並使用 LocalTime.of()
方法建立一個 LocalTime
物件,代表目標時間當天的 3:00:01。LocalDateTime.of()
方法將日期和時間組合成一個 LocalDateTime
物件,即獲取了輸入時間當天的第三小時第一秒。列印該物件即可。注意:這裡的程式碼範例假設輸入時間字串的格式是固定的。如果輸入時間的格式可能會發生變化,需要根據實際情況調整格式化器模式字串。
幫我用 Java 寫一段程式碼。
輸入:一個長度為10的全是小寫字母的字串
處理1:把這個字串按字母逆序
處理2:把這個字串第3,6,9位字母轉換成大寫
處理3:擷取字串的前7位進行輸出
ChatGPT 回答:
以下是用 Java 實現對輸入字串進行處理的程式碼範例:
public class Main { public static void main(String[] args) { String inputStr = "abcdefghij"; // 輸入的字串 // 處理1:按字母逆序 String reverseStr = new StringBuilder(inputStr).reverse().toString(); // 處理2:第3,6,9位字母轉換成大寫 StringBuilder resultStrBuilder = new StringBuilder(reverseStr); resultStrBuilder.setCharAt(2, Character.toUpperCase(reverseStr.charAt(2))); resultStrBuilder.setCharAt(5, Character.toUpperCase(reverseStr.charAt(5))); resultStrBuilder.setCharAt(8, Character.toUpperCase(reverseStr.charAt(8))); String resultStr = resultStrBuilder.toString(); // 處理3:擷取前7位進行輸出 String outputStr = resultStr.substring(0, 7); System.out.println(outputStr); } }
解釋:
inputStr
。StringBuilder
類的 reverse()
方法將字串逆序,並使用 toString()
方法轉換為普通字串。將逆序後的字串儲存在 reverseStr
變數中。StringBuilder
類建立一個新的字串構建器,將逆序後的字串 reverseStr
作為初始字串。setCharAt()
方法將第3,6,9位字母轉換成大寫字母。resultStr
變數中。substring()
方法從處理後的字串 resultStr
中擷取前7位,儲存在 outputStr
變數中。System.out.println()
方法輸出 outputStr
變數的值。到此這篇關於ChatGPT幫我看下這段程式碼有什麼問題的文章就介紹到這了,更多相關ChatGPT分析這段程式碼內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45