1. 程式人生 > >[Java]綜合性實驗 Java原始碼分析程式

[Java]綜合性實驗 Java原始碼分析程式

題目

Java課程的綜合實驗…大三的時候寫過的,不過現在回頭看,發現寫得真爛,所以在學習Java過程中重構了程式碼.
在這裡插入圖片描述
基本不算重構而是重寫…改的時候差點看不懂自己寫過什麼…好了言歸正傳:
實驗的要求如下:
一、題目:綜合性實驗 Java原始碼分析程式
二、型別:綜合型、探索型
三、目的:初步掌握運用面向物件方法編寫應用程式,掌握類、物件、封裝等;瞭解並應用Java語言的字串處理、文字檔案的讀寫
四、內容:
1.背景描述:
(1)Java語言共有50個關鍵字。
(2)Java源程式是以“.java”為副檔名的文字檔案。
(3)可以考慮在Java源程式中的行共有3種:
程式碼行,可執行的Java原始碼。例如:
int n = 10;
註釋行,3種註釋均可。例如:
/**
文件註釋
*/

/*
多行註釋
/
//單行註釋
空行,既無程式碼,也無註釋;
(4)特殊行的處理方法
如果有以下行尾單行註釋的情況,將該行判定為程式碼行。
int number; //number表示人數
int n; /n表示數量/
如果有以下行尾多行註釋的情況,第1行判定為程式碼行,第二行判定為註釋行。
int number; /
number為整型
表示人數 */
假設被分析程式原始碼無其他特殊情況,如:
int /人數/ number;
2. 專案名和類名為JavaCodeAnalyzer,主類名等其他類名自行定義。

  1. 實現功能:
    (1) 程式執行時要求輸入一個目錄的名稱。目錄不存在或不是目錄要提示錯誤並重新輸入。
    (2) 找出輸入目錄中所有的Java源程式檔案(副檔名為“.java”), 並進行源程式檔案進行分析。
    需要分析的結果有:
    目錄中源程式檔案個數
    所有源程式檔案總的位元組數
    所有源程式檔案中程式碼行數、註釋行數、空行數及總行數。說明:行以回車結束。
    (3) 統計並按從多到少輸出所有源程式檔案中使用的Java關鍵字及其出現次數。
    (4) 統計分析的結果除在螢幕顯示外,還需要儲存到一個文字檔案中,檔案內容應該如下:

    目錄名稱:XXXXX(絕對路徑方式)
    共有源程式檔案XX個,總的大小為:XXXXXX 位元組
    源程式檔案總行數:xxxx,其中:
    程式碼行數:xxx,佔xx.xx%
    註釋行數:xxx,佔xx.xx%
    空白行數:xxx,佔xx.xx%

    源程式檔案中使用過的關鍵字有(按使用次數降序排列):
    關鍵字1:xx次
    關鍵字2:xx次
    關鍵字3:xx次
    關鍵字4:xx次
    關鍵字5:xx次

本次分析時間:年-月-日,時-分-秒
注意:統計關鍵字使用次數時,要排除註釋中出現的關鍵字和字串直接量中出現的關鍵字。
好了,總的來說可以分成以下幾個模組:
1.判斷輸入目錄是否正確
2.搜尋Java檔案並儲存到ArrayList
3.計算Java檔案個數和總大小
4.統計原始檔的程式碼行數,註釋行數等
5.統計原始檔的關鍵字出現次數
6.將輸出結果儲存到檔案
7.輸出計算用時
其中


2,3可以參考我的文章 [Java]統計指定目錄中檔案的個數和總的大小
4可以參考[Java]統計Java原始檔程式碼行數,註釋行數,空白行數
5可以參考 [Java]統計目錄下Java原始檔的關鍵字出現次數

程式碼實現

※重構程式碼中對6,7不做實現

1.判斷輸入目錄是否正確

    public static String getPathName() {
        System.out.println("輸入目錄路徑:");
        Scanner keyboardInput = new Scanner(System.in);
        String pathName = null;
        File root = null;
        while (true) {
            pathName = keyboardInput.nextLine();
            root = new File(pathName);
            if (root.isFile()) {
                System.out.println("輸入不是目錄,請重新輸入");
            } else if (!root.exists()) {
                System.out.println("目錄不存在,請重新輸入");
            } else {
                break;
            }
        }
        return pathName;
    }

2.搜尋Java檔案並儲存到ArrayList

    public void searchFiles() {
        File[] files = root.listFiles();
        int length = files.length;
        for (int i = 0; i < length; i++) {
            if (files[i].isDirectory()) {
                root = files[i];
                searchFiles();
            } else {
                if (files[i].getName().endsWith(".java"))
                    fileList.add(files[i]);
            }
        }
    }

3.計算Java檔案個數和總大小

    public void countFiles() {
        long totalSize = 0;
        System.out.println("目錄名稱:" + fileList.get(0).getParent());
        System.out.println("檔案數:" + fileList.size());
        for (int i = 0; i < fileList.size(); i++) {
            totalSize += fileList.get(i).length();
        }
        System.out.println("檔案總大小(bytes):" + totalSize);
    }

4.統計原始檔的程式碼行數,註釋行數等

程式碼與我的文章[Java]統計Java原始檔程式碼行數,註釋行數,空白行數一致.這裡僅貼程式碼,詳細解析請參考文章

import java.io.*;
import java.util.ArrayList;
import java.text.DecimalFormat;

public class CodeAnalyzer {

    public void codeAnalyze(ArrayList<File> fileList) {
        double rowsCount = 0;
        double commentsCount = 0;
        double blanksCount = 0;
        double codesCount = 0;
        DecimalFormat df = new DecimalFormat("#.##");
        for (File file : fileList) {
            try {
                rowsCount += countRows(file);
                blanksCount += countBlanks(file);
                commentsCount += countComments(file);
                codesCount = rowsCount - blanksCount - commentsCount;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //輸出結果
        System.out.println("源程式檔案總行數:" + (int) rowsCount);
        System.out.println("程式碼行數:" + (int) codesCount + ",佔" + df.format(codesCount / rowsCount * 100) + "%");
        System.out.println("註釋行數:" + (int) commentsCount + ",佔" + df.format(commentsCount / rowsCount * 100) + "%");
        System.out.println("空白行數:" + (int) blanksCount + ",佔" + df.format(blanksCount / rowsCount * 100) + "%");
    }

    public int countRows(File file) throws IOException {
        BufferedReader input = new BufferedReader(new FileReader(file));
        int rows = 0;
        while (input.readLine() != null) {
            rows++;
        }
        return rows;
    }

    public int countBlanks(File file) throws IOException {
        BufferedReader input = new BufferedReader(new FileReader(file));
        int blanks = 0;
        String line = null;
        while ((line = input.readLine()) != null) {
            if (line.trim().equals("")) blanks++;
        }
        return blanks;
    }

    public int countComments(File file) throws IOException {
        BufferedReader input = new BufferedReader(new FileReader(file));
        int comments = 0;
        String line = null;
        while ((line = input.readLine()) != null) {
            line = line.trim();
            if (line.startsWith("//")) {//單行註釋
                comments++;
            } else if (line.startsWith("/*")) { //多行及文件註釋
                comments++;
                while (!line.endsWith("*/")) {
                    line = input.readLine().trim();
                    comments++;
                }
            } else if (line.contains("/*")) { //下行尾多行註釋
                line = input.readLine().trim();
                if (line.endsWith("*/")) comments++;
            }

        }
        return comments;
    }
    
}

5.統計原始檔的關鍵字出現次數

與4一樣,這裡僅貼程式碼,詳情解析到-> [Java]統計目錄下Java原始檔的關鍵字出現次數

import java.io.*;
import java.util.*;

public class KeywordsAnalyzer {
    Map keywords;
    final String[] KEYWORDS = { //50個關鍵字
            "abstract", "assert", "boolean", "break", "byte",
            "case", "catch", "char", "class", "const",
            "continue", "default", "do", "double", "else",
            "enum", "extends", "final", "finally", "float",
            "for", "goto", "if", "implements", "import",
            "instanceof", "int", "interface", "long", "native",
            "new", "package", "private", "protected", "public",
            "return", "strictfp", "short", "static", "super",
            "switch", "synchronized", "this", "throw", "throws",
            "transient", "try", "void", "volatile", "while"
    };

    public KeywordsAnalyzer() {
        keywords = new HashMap();
        for (String word : KEYWORDS) {
            keywords.put(word, 0);
        }

    }

    public void keywordsAnalyze(ArrayList<File> fileList) {
        for (File file : fileList) {
            try {
                countKeyWords(file);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //排序並輸出結果
        List<Map.Entry<String, Integer>> list = new ArrayList<Map.Entry<String, Integer>>(keywords.entrySet());
        Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() {
            @Override
            public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                return o2.getValue().compareTo(o1.getValue());
            }
        });
        int count = 0;
        System.out.println("\n源程式檔案中使用過的關鍵字有(按使用次數降序排列):");
        for(int i=0;i<5;i++){
            System.out.println("關鍵字 "+list.get(i).getKey()+": "+list.get(i).getValue()+"次");
        }

    }

    public void countKeyWords(File file) throws IOException {
        BufferedReader input = new BufferedReader(new FileReader(file));
        String line = null;
        while ((line = input.readLine()) != null) {
            line = line.trim();
            if (line.startsWith("//")) continue; //不處理單行註釋
            else if (line.contains("/*")) { //多行,文件與尾行註釋
                if (!line.startsWith("/*")) matchKeywords(line);//第一行算程式碼,其餘算註釋
                while (!line.endsWith("*/")) {
                    line = input.readLine().trim();
                }
            }
            matchKeywords(line); //對程式碼行進行統計
        }
    }

    public void matchKeywords(String line) {
        String[] wordList = line.replaceAll("\\W", " ").split(" ");
        for (int i = 0; i < wordList.length; i++) {
            for (int j = 0; j < 50; j++) {
                if (wordList[i].equals(KEYWORDS[j])) {
                    int count = (int) keywords.get(KEYWORDS[j]);
                    keywords.put(KEYWORDS[j], count + 1);
                }
            }
        }
    }
}

測試結果

timer.java測試Timer.java,得到結果:

在這裡插入圖片描述

原始碼下載

包含原始碼,可執行的jar以及測試用例.

百度網盤