IDEA插件之快速删除Java代码中的注释

背景

有时,我们需要删除Java源代码中的注释。目前有不少方法,比如:

  • 实现状态机。该方式较为通用,适用于多种语言(取决于状态机支持的注释符号)。
  • 正则匹配。该方式容易误判,尤其是容易误删字符串。
  • 利用第三方库。该方式局限性较强,比如不同语言可能有不同的第三方库。

本文针对Java语言,介绍一种利用第三方库的方式,可以方便快速地移除代码中的注释。

原理

这个第三方库叫做JavaParser。它可以分析Java源码,并生成语法分析树(AST),其中注释也属于AST中的节点。

因此核心思路即为:

  • JavaParser解析源码并得到AST。
  • 识别出注释类型的节点并将其删掉。
  • 将AST中剩余的节点按一定规则打印出来。

在实践之前,我们先要了解Java中的几种注释类型:

  • LineComment 单行注释。
  • BlockComent 块注释。
  • JavadocComment Java文档注释。

下面举个简单例子,说明三种注释的区别:

import java.util.ArrayList;
import java.util.stream.Collectors;

/**
 * @author xiaoxi666
 * @date 2021-02-15 17:13
 * 我是 Javadoc 注释
 */
public class Input {
  /**
   * 我是 Javadoc 注释
   *
   * @param param1
   * @param param2
   */
  public static void someMethod(String param1, // 我是单行注释
                 String param2
// 我是单行注释 String param3,
/* 我是块注释 String param4,
                 String param5,
                 String param6 */
    /* 我是块注释 String param4 */)
 {
    // 我是单行注释
    int a = 1;
    /* 我是块注释,注意我和Javadoc注释的区别,我只有一个星号 */
    int b = 2;
    /*
     * 我是块注释
     */
    int c = 3;
    String s1 = "// 我是字符串中的内容,不是注释";
    String s2 = "/* 我是字符串中的内容,不是注释 */";
    String s3 = "/** 我是字符串中的内容,不是注释 */";
  }
}

下面我们实践一下,看看怎么移除源码中的注释。
我这里使用maven管理项目,首先引入JavaParser依赖:

<dependencies>
  <dependency>
     <groupId>com.github.javaparser</groupId>
     <artifactId>javaparser-symbol-solver-core</artifactId>
     <version>3.18.0</version>
  </dependency>
</dependencies>

然后编写核心代码:

package core;import com.github.javaparser.JavaParser;
import com.github.javaparser.ParseResult;
import com.github.javaparser.ParserConfiguration;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.comments.BlockComment;
import com.github.javaparser.ast.comments.Comment;
import com.github.javaparser.ast.comments.LineComment;
import com.github.javaparser.printer.lexicalpreservation.LexicalPreservingPrinter;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author xiaoxi666
 * @date 2021-02-15 20:09
 * 几个注释的概念:
 * LineComment
 * BlockComment
 * JavadocComment
 */
public final class CommentsRemover {
  private CommentsRemover() {}

  public static String doAction(String content) {
    JavaParser javaParser = createJavaParser();
    ParseResult<CompilationUnit> result = javaParser.parse(content);
    Optional<CompilationUnit> optionalCompilationUnit = result.getResult();
    if (!optionalCompilationUnit.isPresent()) {
      return "";
    }
    CompilationUnit compilationUnit = optionalCompilationUnit.get();
    removeComments(compilationUnit);
    return LexicalPreservingPrinter.print(compilationUnit);
  }

  private static void removeComments(CompilationUnit compilationUnit) {
    List<Comment> comments = compilationUnit.getAllContainedComments();
    List<Comment> unwantedComments = comments
      .stream()
      .filter(CommentsRemover::isValidCommentType)
      .collect(Collectors.toList());
    unwantedComments.forEach(Node::remove);
  }

  /**
   * 创建源码解析器。我们设置LexicalPreservationEnabled为true,保留源码中的所有语法。
   *
   * @return JavaParser
   */
  private static JavaParser createJavaParser() {
    ParserConfiguration parserConfiguration = new ParserConfiguration();
    parserConfiguration.setLexicalPreservationEnabled(true);
    return new JavaParser(parserConfiguration);
  }

  /**
   * 我们只识别单行注释和块注释
   *
   * @param comment
   * @return true if meet the correct type
   */
  private static boolean isValidCommentType(Comment comment) {
    return comment instanceof LineComment || comment instanceof BlockComment;
  }
}

在上面的代码中,我们首先创建JavaParser,再解析源码,然后移除单行注释和块注释,最后再用LexicalPreservingPrinter将处理后的源码打印出来,这个打印器可以保留源代码所有词法,比如空格、换行之类的元素。上述代码已有注释,因此不再详述。

封装为IDEA插件

考虑到我们平时可能会大量使用该功能,因此将其封装为了IDEA插件,名为remove.comments。下面简要介绍该插件的工作原理及使用方式。

PS:本文不会详细介绍如何编写IDEA插件。

IDEA插件的原理基本都是事件驱动,如下图所示,我们创建了一个事件监听器,当检测到编辑器中点击右键后,即可弹出菜单,我们的插件在菜单中的第一个位置。

接下来,实现事件处理器:

其中包含两段核心代码:

  • 删除源码注释。首先读取当前文件内容也即源码,然后交给前面已经介绍过的CommentsRemover.doAction处理,就拿到了删除注释后的源码。
  • 格式化代码。删除注释后,可能会引入多余的空格,因此我们自动格式化,这样用户就不用再手动格式化一次了。
/**
 * 移除代码中的注释
 *
 * @param editor
 * @return true if remove comments successfully
 */
private boolean removeComments(Editor editor) {
  String src = editor.getDocument().getText();
  if (Strings.isNullOrEmpty(src)) {
    return false;
  }
  String dst = CommentsRemover.doAction(checkEndLineAndModifyIfNeed(src));
  if (Strings.isNullOrEmpty(dst)) {
    return false;
  }
  editor.getDocument().setText(dst);
  return true;
}

/**
 * 由于我们保留了源码格式,移除注释之后会引入不必要的空格,因此需要再格式化一下
 *
 * @param editor
 * @param project
 */
private void reformat(Editor editor, Project project) {
  PsiDocumentManager.getInstance(project).commitAllDocuments();
  PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
  if (file == null) {
    return;
  }
  LastRunReformatCodeOptionsProvider provider = new LastRunReformatCodeOptionsProvider(PropertiesComponent.getInstance());
  ReformatCodeRunOptions currentRunOptions = provider.getLastRunOptions(file);
  TextRangeType processingScope = TextRangeType.WHOLE_FILE;
  currentRunOptions.setProcessingScope(processingScope);
  (new FileInEditorProcessor(file, editor, currentRunOptions)).processCode();
}

然后打包插件:

插件打包好之后,用户就可以从本地磁盘安装了:

在弹出的目录树中,选中remove.comments.zip安装包,确定即可。

重启IDEA后,可以看到插件已安装成功:

此时我们就可以使用该插件,一键删除代码中的注释了。演示一下效果:

不严格性能测试(响应时间包括插件处理时间和IDEA界面更新时间):

  • 对于500行左右的文件,响应时间约200ms,几乎瞬间完成。
  • 对于1000行左右的文件,响应时间约为1s。
  • 对于3000行左右的文件,响应时间约需2s。
  • 对于5000行左右的文件,响应时间约需3s。

总之,日常使用毫无压力。

总结

本文首先介绍了若干删除注释的手段;继而介绍了一种利用第三方库JavaParser删除Java注释的思路,并加以分析和实践;最终将其封装为IDEA插件,方便其他用户使用。

另外,由于本人对JavaParser的认知不是特别深入,难免存在未考虑到的场景。若大家在使用过程中发现bug,欢迎到github提issue甚至pr。

资源

源码均已放在github:https://github.com/xiaoxi666/remove.comments

扩展

针对文中提出的第一种状态机思路,之前也写文章介绍过。有兴趣的读者可尝试动手实现一下。链接:https://www.cnblogs.com/xiaoxi666/p/7931763.html

到此这篇关于IDEA插件之快速删除Java代码中的注释的文章就介绍到这了,更多相关idea删除java代码注释内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 使用idea插件进行java代码生成的操作

    java代码生成 使用idea的插件codehelper.generator进行代码生成,可以根据entity,生成对应的 1.建表sql语句 2.dao.java文件 3.dao.xml文件 4.service.java文件 同时这个插件还能在new了entity之后生成所有的set方法 多次生成,不会影响自己手动添加的代码 安装 安装插件codehelper.generator 案例 @Data @AllArgsConstructor @NoArgsConstructor public cl

  • Intellij IDEA中一次性折叠所有Java代码的快捷键设置

    问题:在Java文件中,想把所有的Java方法代码都一次性给折叠起来,用哪个点开哪个. 问题来源:在新建model bean的时候,要是属性很多,那么对应的getter和setter就会很多,要是所有的方法代码都是展开状态,那么这个文件看着也不甚美观,所以,可以把方法都折叠起来. 下面看怎么设置快捷键:看法宝... 要是看不懂,系统自带的快捷键配置,大可以,自己再修改个,就像这个折叠代码的这个快件,折叠一个方法的快捷键是:  ctrl + 减号. 我就把折叠所有的快捷键设置成:ctrl+shif

  • 详解基于IDEA2020.1的JAVA代码提示插件开发例子

    之前因为项目组有自己的代码规范,为了约束平时的开发规范,于是基于2019.1.3版本开发了一个代码提示的插件.但是在把IDEA切换到2020.1版本的时候,却发现疯狂报错,但是网上关于IDEA插件开发的相关文章还是不够多,只能自己解决.于是根据官方的SDK文档,使用Gradle重新构建了一下项目,把代码拉了过来.下文会根据2020.1版本简单开发一个代码异常的提示插件,把容易踩坑的地方提示一下. 1.首先先根据IDEA插件开发官方文档,用Gradle新建一个project 选中file -> n

  • IntelliJ IDEA中折叠所有Java代码,再也不怕大段的代码了

    问题: 在Java文件中,想把所有的Java方法代码都一次性给折叠起来,用哪个点开哪个. 问题来源: 在新建model bean的时候,要是属性很多,那么对应的getter和setter就会很多,要是所有的方法代码都是展开状态,那么这个文件看着也不甚美观,所以,可以把方法都折叠起来. 下面看怎么设置快捷键:看法宝. 要是看不懂,系统自带的快捷键配置,大可以,自己再修改个,就像这个折叠代码的这个快件,折叠一个方法的快捷键是:  ctrl + 减号. 我就把折叠所有的快捷键设置成:ctrl+shif

  • IDEA插件之快速删除Java代码中的注释

    背景 有时,我们需要删除Java源代码中的注释.目前有不少方法,比如: 实现状态机.该方式较为通用,适用于多种语言(取决于状态机支持的注释符号). 正则匹配.该方式容易误判,尤其是容易误删字符串. 利用第三方库.该方式局限性较强,比如不同语言可能有不同的第三方库. 本文针对Java语言,介绍一种利用第三方库的方式,可以方便快速地移除代码中的注释. 原理 这个第三方库叫做JavaParser.它可以分析Java源码,并生成语法分析树(AST),其中注释也属于AST中的节点. 因此核心思路即为: J

  • Python删除Java源文件中全部注释的实现方法

    本文实例讲述了Python删除Java源文件中全部注释的实现方法.分享给大家供大家参考,具体如下: 同事想删除一个Java项目中的全部注释,让我帮忙想想办法. 没找不到合适工具,就写了这个脚本,遍历指定目录,查找*.java文件,删除其中/* */之间,及// 至行末的内容. (用之前要改改其中的路径): #!D:\Python32 # 过滤JAVA程序中的注释 # 如果字符串中有注释符号的话会有问题. import os import re import io # 改这个目录!!! top_d

  • 快速理解Java设计模式中的组合模式

    组合模式是一种常见的设计模式(但我感觉有点复杂)也叫合成模式,有时又叫做部分-整体模式,主要是用来描述部分与整体的关系. 个人理解:组合模式就是将部分组装成整体. 定义如下: 将对象组合成树形结构以表示"部分-整体"的层次结构,使得用户对单个对象和组合对象的使用具有一致性. 通用类图如下: 组合模式的包含角色: ● Component 抽象构件角色 定义参加组合对象的共有方法和属性,可以定义一些默认的行为或属性. ● Leaf 叶子构件 叶子对象,其下再也没有其他的分支,也就是遍历的最

  • 教你在JNA中将本地方法映射到JAVA代码中的示例

    目录 简介 Library Mapping Function Mapping Invocation Mapping 防止VM崩溃 性能考虑 总结 简介 不管是JNI还是JNA,最终调用的都是native的方法,但是对于JAVA程序来说,一定需要一个调用native方法的入口,也就是说我们需要在JAVA方法中定义需要调用的native方法. 对于JNI来说,我们可以使用native关键字来定义本地方法.那么在JNA中有那些在JAVA代码中定义本地方法的方式呢? Library Mapping 要想

  • PHP正则删除HTML代码中宽高样式的方法

    本文实例讲述了PHP正则删除HTML代码中宽高样式的方法.分享给大家供大家参考,具体如下: 因工作需要,需要采集html,并把html内容保存到数据库中.为了避免影响使用,宽高样式需要删除.例如图片和div中的width, height等. 不过采集到的html中,样式的写法各有不同,例如大小写,中间有空格等. 因此使用php正则编写了下面这个方法,对这些奇葩的样式进行过滤. 代码如下: <?php /** * 清除宽高样式 * @param String $content 内容 * @retu

  • php正则删除html代码中class样式属性的方法 原创

    本文实例讲述了php正则删除html代码中class样式属性的方法.分享给大家供大家参考,具体如下: 一.问题: 有如下代码: <div class="jb51"><div class="jb51_txt">欢迎访问我们</div></div> 要求:删除HTML代码中的class属性. 二.实现方法: php实现代码如下: $str='<div class="jb51"><div

  • PHP正则删除html代码中a标签并保留标签内容的方法 原创

    本文实例讲述了PHP正则删除html代码中a标签并保留标签内容的方法.分享给大家供大家参考,具体如下: 一.问题: 有HTML代码如: <div>欢迎访问我们<a href=http://www.jb51.net>www.jb51.net</a></div> 要求正则删除a标签,同时保留a标签内容,如下: <div>欢迎访问我们www.jb51.net</div> 二.解决方法: $str = "<div>欢迎访

  • 在java代码中获取JVM参数的方法

    实例如下: MemoryMXBean memorymbean = ManagementFactory.getMemoryMXBean(); MemoryUsage usage = memorymbean.getHeapMemoryUsage(); System.out.println("INIT HEAP: " + usage.getInit()); System.out.println("MAX HEAP: " + usage.getMax()); System.

  • 在Java代码中解析html,获取其中的值方法

    有时我们获取到了页面需要在Java代码中进行解析,获取html中的数据,Jsoup是一个很方便的工具. 一.什么是Jsoup? 官网网站:http://jsoup.org/ 可在官网下载对应的jar 通俗的将Jsoup就是一个解析网页的东西 二.示例 1.页面,通过查询获取到了一些数据: 2.源码,这是一个table,class="list",通过这些来唯一标识它 3.代码,将html以String的形式传进来,使用Jsoup进行解析: import org.jsoup.Jsoup;

  • 详解java代码中init method和destroy method的三种使用方式

    在java的实际开发过程中,我们可能常常需要使用到init method和destroy method,比如初始化一个对象(bean)后立即初始化(加载)一些数据,在销毁一个对象之前进行垃圾回收等等. 周末对这两个方法进行了一点学习和整理,倒也不是专门为了这两个方法,而是在巩固spring相关知识的时候提到了,然后感觉自己并不是很熟悉这个,便好好的了解一下. 根据特意的去了解后,发现实际上可以有三种方式来实现init method和destroy method. 要用这两个方法,自然先要知道这两

随机推荐