找到java代码中没有被使用的公用方法

最近,我打算对我们项目的代码进行清理,准备把一些没有被使用到的公用方法清理掉,但是我在网络找了一遍,像PMD,Findbugs等静态工具,都只能找到没有被使用的私有方法。

无奈之下,只能直接写代码来实现这个功能,具体代码如下:

package com;
import java.io.File;
import java.io.FileReader;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.List;
public class FindUnUsedCode {
 public static final int TYPE_METHOD = 0; //方法
 public static final int TYPE_ATTRIBUTE = 1; //属性
 
 /**
  * 类对象
  */
 class ClassObject{
  public List<String> methods = new ArrayList<String>(); //公用方法集合
  public String className; //类名
  public List<String> attributes = new ArrayList<String>(); //属性名
 }
 
 /**
  * 熟悉对象
  */
 class MethodObject{
  public String methodName; //方法名
 }
 
 class UnUsedCode{
  public String className; //类名
  public String codeName; //方法名或者属性名
  public int type; //0:方法名,1:属性名
  public String descript; //描述
 }
 //类集合
 private List<ClassObject> classList = new ArrayList<ClassObject>(); 
 
 //java定义的数据类型
 private String[] dataTypes = {"void", "int", "boolean", "long", "char", "float", "double"};
 
 //java定义的访问权限
 private String[] callAuths = {"public", "friendly", "protected", "private"};
 
 //java的关键字
 private String[] keyWords = {"public", "friendly", "protected", "private", "void", "int", "boolean", "long", "char", "float", "double"
   , "{", "}"};
 
 /**
  * 检查一个文件名是否java文件
  * @param fileName
  * @return
  */
 private boolean checkIsJava(String fileName)
 {
  boolean result = false;
 
  if (fileName.lastIndexOf(".java") != -1)
  {
   result = true;
  }
 
  return result;
 }
 
 /**
  * 分析java文件,返回类对象
  * @param fullName
  * @return
  */
 public ClassObject analyseJavaFile(String path, String fileName) throws Exception
 {
  //全路径
  String fullName = path + "/" + fileName;
 
  //文件对象
  File file = new File(fullName);
 
  //创建对象
  ClassObject classObject = new ClassObject();
 
  //设置类名
  classObject.className = fileName.substring(0, fileName.length()-5);
 
  //得到文件读对象
  RandomAccessFile randomAccessFile  = new RandomAccessFile(file, "r");
 
  //读取一行数据
  String line = "";
  do
  {
   line = randomAccessFile.readLine();
 
   if (line == null)
   {
    break;
   }
   else
   {
    //去掉前后空格
    line = line.trim();
   }
 
   //System.out.println("line:" + line);
 
   if (line.indexOf(" class ") != -1)
   {
    //为类定义行,则不处理该行
    continue;
   } 
 
   //判断是否公用对象
   if (line.startsWith("public"))
   {
    //把数据拆分出来
    String[] strs = line.split(" ");
 
    //顺序获取数据,从第三个开始读,因为第一个为public,第二个为数据类型,第三个才可能是名字
    for (int i = 2; i < strs.length; i++)
    {
     //判断是否java的关键字
     if (isKeyWords(strs[i]))
     {
      continue;
     }
 
     //判断是否以小写字符开始
     if (isStartWithLower(strs[i]))
     {
      //找到是否包含有括号
      int loc = strs[i].indexOf("(");
 
      if (loc == -1)
      {//不包含扩展
       if (strs[i].indexOf(";") == -1)
       {//不包含分号
        if ((strs.length > (i+1)) && (strs[i+1].indexOf("(") == -1))
        {
         //下一个数据也不包含括号,那么则是属性
         classObject.attributes.add(strs[i]);
 
         break;
        }
        else
        {
         //下个数据包含括号,则是方法
         classObject.methods.add(strs[i]);
 
         //System.out.println("22222222222222222:" + line);
 
         break;
        }
       }
       else
       {
        //没有括号,而且已经分号结束了,那么则是属性名
        classObject.attributes.add(strs[i].substring(0, strs[i].length() - 1 ));
 
        break;
       }
      }
      else
      {
       //包含了括号,则是方法
       classObject.methods.add(strs[i].substring(0, loc));
 
       //System.out.println("1111111111111111:" + line);
 
       break;
      }
     }
    }
   }
  }while (line != null);
 
  return classObject;
 }
 
 /**
  * 判断字符串是否以小写字符开始
  * @param str
  * @return
  */
 public boolean isStartWithLower(String str)
 {
  return str.startsWith(str.toLowerCase().substring(0, 1));
 }
 
 /**
  * 判断是否java的关键字
  * @param str
  * @return
  */
 public boolean isKeyWords(String str)
 {
  return isInculeList(str, keyWords);
 }
 
 /**
  * 判断是否java的数据类型
  * @param str
  * @return
  */
 public boolean isDataType(String str)
 {
  return isInculeList(str, dataTypes);
 }
 
 /**
  * 判断是否java的访问权限类型
  * @param str
  * @return
  */
 public boolean isCallAuth(String str)
 {
  return isInculeList(str, callAuths);
 }
 
 /**
  * 判断一个字符串是否在一个数据列表中
  * @param str
  * @param lists
  * @return
  */
 public boolean isInculeList(String str, String[] lists)
 {
  boolean result = false;
 
  //获取java的所有类型
  for (int i = 0; i < lists.length; i++)
  {
   if (lists[i].equals(str))
   {
    //包含在列表中
    result = true;
 
    break;
   }
  }
 
  return result;
 }
 
 /**
  * 去类集合
  * @param path
  * @return
  */
 public List<ClassObject> getClassList(String path) throws Exception
 {
  File file = new File(path);
 
  String[] list = file.list();
 
  //文件名
  String fileName = "";
 
  //类对象
  ClassObject classObject;
 
  //循环获取数据
  for (int i = 0; i < list.length; i++)
  {
   //得到文件的全路径
   fileName = path + "/" + list[i];
 
   //得到文件对象
   file = new File(fileName);
 
   //判断是否java文件
   if (checkIsJava(list[i]))
   {
    //得到java数据
    classObject = analyseJavaFile(path,  list[i]);
 
    if (classObject != null)
    {
     //增加一个数据
     this.classList.add(classObject);
    }
   }
   else if (file.isDirectory())
   {//是一个目录
    //递归执行
    getClassList(fileName);
   }
  }
 
  return this.classList;
 }
 
 /**
  * 文件中是否包含某个字符串
  * @param fullPath
  * @param str
  * @return
  * @throws Exception
  */
 public boolean isIncludeStr(String fullPath, String str) throws Exception
 {
  List<String> list = new ArrayList<String>();
  list.add(str);
 
  return isIncludeStrs(fullPath, list);
 }
 
 /**
  * 文件中是否包含了知道的字符串
  * @param fullPath
  * @param strs
  * @return
  */
 public boolean isIncludeStrs(String fullPath, List<String> strs) throws Exception
 {
  boolean result = false;
 
  List<String> tempStrs = strs;
 
  //得到文件读对象
  RandomAccessFile randomAccessFile  = new RandomAccessFile(fullPath, "r");
 
  //读取一行数据
  String line = "";
  do
  {
   //读一行
   line = randomAccessFile.readLine();
 
   if (line == null)
   {
    break;
   }
   else
   {
    //去掉前后空格
    line = line.trim();
   }
 
   if ((tempStrs != null) && (!tempStrs.isEmpty()))
   {
    for (int i = 0; i < tempStrs.size(); i++)
    {
     //包含改字符串
     if (line.indexOf(tempStrs.get(i)) != -1)
     {
      //去掉该数据
      tempStrs.remove(i);
     }
    }
   }
   else
   {
    //已经为空,则表示已经完全匹配了所以字符串,跳出
    break;
   }
  }while (line != null);
 
  if ((tempStrs == null) || (tempStrs.isEmpty()))
  {
   //完全比配
   result = true;
  }
 
  return result;
 }
 
 /**
  * 检查代码是否被使用,0:被使用了,1:没有被使用,2:无法确定
  * @param path
  * @param className
  * @param codeName
  * @return
  */
 public int checkUsed(String path, String className, String codeName) throws Exception
 {
  //没有被使用
  int result = 1;
 
  File file = new File(path);
 
  //得到列表
  String[] list = file.list();
 
  //全路径
  String fullPath = "";
 
  List<String> checkList = new ArrayList<String>();
  checkList.add(className);
  checkList.add(codeName);
  if ((list != null) && (list.length > 0))
  {
   //循环获取数据
   for (int i = 0; i < list.length; i++)
   {
    //如果为同一个类,则不检查
    if (list[i].equals(className + ".java"))
    {
     continue;
    }
 
    //得到文件的全路径
    fullPath = path + "/" + list[i];
 
    file = new File(fullPath);
 
    //判断是文件还是目录
    if (file.isFile())
    {
     if (isIncludeStrs(fullPath, checkList))
     {
      //既包含了类名,又包含方法名,则表示该方法,铁定被使用了
      return 0;
     }
     else if (isIncludeStr(fullPath, codeName))
     {
      //调用了方法,且没有找到类,则无法确定
      result = 2;
 
      //继续判断下一个
      continue;
     }
    }
    else if (file.isDirectory())
    {//是一个目录
     //递归执行
     checkUsed(fullPath, className, codeName);
    }
   }
  }
 
  return result;
 }
 
 /**
  * 获取没有被使用的代码
  * @param path
  * @param className
  * @param codeNames
  * @param type
  * @return
  * @throws Exception
  */
 public List<UnUsedCode> getUnUsedCode(String path, String className, List<String> codeNames, int type) throws Exception
 {
  List<UnUsedCode> result = new ArrayList<UnUsedCode>();
  UnUsedCode unUsedCode;
 
  if ((codeNames != null) && (!codeNames.isEmpty()))
  {
   //循环获取属性
   for (int j = 0; j < codeNames.size(); j++)
   {
    String codeName = codeNames.get(j);
 
    //判断是否被使用
    int usedType = checkUsed(path, className, codeName);
 
    //没有被使用
    if (usedType != 0)
    {
     //创建对象
     unUsedCode = new UnUsedCode();
 
     unUsedCode.className = className; //类名
     unUsedCode.codeName = codeName; //属性名
     unUsedCode.type = type; //类型为属性
 
     if (usedType == 1)
     {
      unUsedCode.descript = "没有被使用";
     }
     else if (usedType == 2)
     {
      unUsedCode.descript = "无法确定";
     }
 
     //增加一条数据
     result.add(unUsedCode);
    }
   }
  }
 
  return result;
 }
 
 /**
  * 得到未使用的代码
  * @param path
  * @return
  */
 public List<UnUsedCode> getUnUsedCode(String path) throws Exception
 {
  //结果
  List<UnUsedCode> result = new ArrayList<UnUsedCode>();
 
  //得到类对象
  List<ClassObject> classList = getClassList(path);
 
  ClassObject classObject;
 
  List<UnUsedCode> unUsedAttrList;
 
  List<UnUsedCode> unUsedMethodList;
 
  //数据不为空
  if ((classList != null) && (!classList.isEmpty()))
  {
   //循环获取数据
   for (int i = 0; i < classList.size(); i++)
   {
    //获取一个数据
    classObject = classList.get(i);
 
    //得到一个类中没有使用的属性列表
    unUsedAttrList = getUnUsedCode(path, classObject.className, classObject.attributes, TYPE_ATTRIBUTE);
 
    if ((unUsedAttrList != null) && (!unUsedAttrList.isEmpty()))
    {
     //增加数据
     result.addAll(unUsedAttrList);
    }
 
    //得到一个类中没有使用的属性列表
    unUsedMethodList = getUnUsedCode(path, classObject.className, classObject.methods, TYPE_METHOD);
 
    if ((unUsedMethodList != null) && (!unUsedMethodList.isEmpty()))
    {
     //增加数据
     result.addAll(unUsedMethodList);
    }
   }
  }
 
  return result;
 }
 
 public static void main(String[] args)
 {
  FindUnUsedCode findUnUsedCode = new FindUnUsedCode();
 
  try
  {
   List<UnUsedCode> list = findUnUsedCode.getUnUsedCode("C:/com");
 
   if ((list != null) && (!list.isEmpty()))
   {
    for (int i = 0; i < list.size(); i++)
    {
     UnUsedCode unUsedCode = list.get(i);
 
     System.out.println(unUsedCode.className + "." + unUsedCode.codeName
       + "   " + (unUsedCode.type==TYPE_METHOD?"方法":"属性") + "   "  + unUsedCode.descript);
    }
 
   }
  }
  catch (Exception ex)
  {
   ex.printStackTrace();
  }
 } 
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏一个会写诗的程序员的博客

《Kotlin极简教程》第3章 Kotlin语言基础第3章 Kotlin语言基础《Kotlin极简教程》正式上架:参考资料

学习任何东西,都是一个由表及里的过程。学习一门编程语言也一样。对于一门编程语言来说,“表” 就是基本词汇(关键字、标识符等)、句子(表达式)和语法。

14820
来自专栏封碎

BitSet位图算法 博客分类: 算法 算法IDEA

位图算法,使用bit存储数据并排序,优点是快速、占用资源少,缺点是只能对整数使用。     Java和C++中都有已经实现的的BitSet类,可以直接使用...

59740
来自专栏java学习

面试题7(考察运算符的优先级)

请选择下面代码运行后打印的结果。 public static void main(String[]args){ int x=5; int y=3; x=x+(x...

35280
来自专栏Java编程

Java反射机制详解

动态语言,是指程序在运行时可以改变其结构:新的函数可以被引进,已有的函数可以被删除等在结构上的变化。比如众所周知的ECMAScript(JavaScript)便...

70410
来自专栏Golang语言社区

[Go语言]实现可以枚举的map

在golang-nuts上看到有人问怎么样去枚举一个map。在go语言层面,并不支持支持枚举map,也就是说你不能获得一个枚举器在任意时刻去枚举这个map,只能...

37670
来自专栏积累沉淀

Java设计模式(十六)----迭代子模式

迭代子模式 一、 概述 二、 结构 1.白箱聚集与外禀迭代子 2.黑箱聚集与内禀迭代子 主动...

224100
来自专栏Golang语言社区

[Go语言]实现可以枚举的map

在golang-nuts上看到有人问怎么样去枚举一个map。在go语言层面,并不支持支持枚举map,也就是说你不能获得一个枚举器在任意时刻去枚举这个map,只能...

38570
来自专栏進无尽的文章

Swift| 基础语法(四)

总结下 swift下的基础语法,里面涉及到:常量&变量、Swift中的数据类型、逻辑分支、循环、字符串相关、数组和字典、方法的书写调用等内容,考虑到阅读体验分多...

18110
来自专栏Felix的技术分享

霍夫曼压缩算法

38580
来自专栏Java帮帮-微信公众号-技术文章全总结

Java基础19(01)总结IO流,异常try…catch,throws,File类

1:异常(理解) (1)程序出现的不正常的情况。 (2)异常的体系 Throwable |--Error 严重问题,我们不处理。 |--Excepti...

43070

扫码关注云+社区

领取腾讯云代金券