网站怎么做png阴影/百度seo文章
JDK 的编译子系统暴露给用户直接控制的功能相对很少,除了虚拟机即时编译的若干参数,便只有 JSR-296
中定义的插入式注解处理器 API;
文章目录
- 1. 目标
- 2. 实现
- 3. 运行与测试
- 4. 其他应用案例
1. 目标
前端编译器在讲 Java 源码编译成字节码时对源码做了各方面检查,主要是看程序写到对不对
,较少去看写得好不好
,业界有一些如 CheckStyle、FindBug、Klocwork 等的工具用于检查代码好坏,有一些用于扫描 Java 源码,也有一些是扫描字节码;我们的目标是通过注解处理器 API 实现自己编码风格的校验工具:NameCheckProcessor
;
根据《Java 语言规范》要求,Java 程序命名推荐使用如下书写规范:
- 类(接口):驼峰命名法,首字母大写;
- 方法:驼峰命名法,首字母小写;
- 字段
- 类或实例变量:驼峰命名法,首字母小写;
- 常量:全部由大写字母或下划线构成,第一个字符不能是下划线;
为 javac 编译器添加额外的功能,在编译程序时检查程序名是否符合上述对类、接口、方法、字段的命名要求;
2. 实现
注解处理器可以通过继承抽象类 javax.annotation.processing.AbstractProcessor
复写抽象方法 process()
来实现;javac 编译器在执行注解处理器代码时会调用 process()
;
annotations
,此注解处理器所要处理的注解集合;roundEnv
,当前这个轮次(Round)中的抽象语法树节点,每个语法树节点表示一个 Element;processingEnv
,AbstractProcessor 中的一个 protected 变量,代表了注解处理器框架提供的一个上下文环境,可用来创建新的代码、向编译器输出信息、获取其他工具类等;
javax.lang.model.ElementKind 定义了 18 类 Element,包含 Java 代码中可能出现的全部元素,如包(Package)、枚举(Enum)、类(Class)、注解(AnnotationType)、接口(Interface)、枚举值(EnumConstant)、字段(Field)、参数(Parameter)、本地变量(LocalVariable)、异常(ExceptionnParameter)、方法(Method)、构造函数(Constructor)、静态语句块(StaticInit,即 static{} 块)、实例语句块(InstanceInit,即 {} 块)、参数化类型(TypeParameter,泛型尖括号内的类型)、资源变量(ResourceVariable,try-resource 中定义的变量)、模块(Module)、未定义的其他语法树节点(Other);
@SupportedAnnotationTypes
,代表这个注解处理器对哪些注解感兴趣;@SuppertedSourceVersion
,表示这个注解处理器可以处理哪些版本的 Java 代码;
注解处理器 NameCheckProcessor
/*** "*" 表示支持所有 Annotations* 只支持 JDK 8 的 Java 代码** @author Aurelius Shu* @since 2023-02-19*/
@SupportedAnnotationTypes("*")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class NameCheckProcessor extends AbstractProcessor {private NameChecker nameChecker;/*** 初始化名称检查插件*/@Overridepublic void init(ProcessingEnvironment processingEnv) {super.init(processingEnv);nameChecker = new NameChecker(processingEnv);}/*** 对输入的语法树的各个节点进行名称检查*/@Overridepublic boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {if (!roundEnv.processingOver()) {for (Element element : roundEnv.getRootElements())nameChecker.checkNames(element);}return false;}
}
命名检查器 NameChecker
/*** 程序名称规范的编译器插件* 如果程序命名不合规范,将会输出一个编译器的 WARNING 信息** @author Aurelius Shu* @since 2023-02-19*/
public class NameChecker {private final Messager messager;NameCheckScanner nameCheckScanner = new NameCheckScanner();NameChecker(ProcessingEnvironment processsingEnv) {this.messager = processsingEnv.getMessager();}/*** 对Java程序命名进行检查,根据《Java语言规范》第三版第 6.8 节的要求,Java程序命名应当符合下列格式: * 类或接口:符合驼式命名法,首字母大写。* 方法:符合驼式命名法,首字母小写。* 字段:* 类、实例变量: 符合驼式命名法,首字母小写。* 常量: 要求全部大写。*/public void checkNames(Element element) {nameCheckScanner.scan(element);}/*** 名称检查器实现类,继承了 JDK 8 中新提供的ElementScanner8<br> * 将会以 Visitor 模式访问抽象语法树中的元素*/private class NameCheckScanner extends ElementScanner8<Void, Void> {/*** 此方法用于检查 Java 类*/@Overridepublic Void visitType(TypeElement e, Void p) {scan(e.getTypeParameters(), p);checkCamelCase(e, true);super.visitType(e, p);return null;}/*** 检查方法命名是否合法*/@Overridepublic Void visitExecutable(ExecutableElement e, Void p) {if (e.getKind() == METHOD) {Name name = e.getSimpleName();if (name.contentEquals(e.getEnclosingElement().getSimpleName())) {messager.printMessage(WARNING, "一个普通方法 “" + name + "”不应当与类名重复,避免与构造函数产生混淆", e);}checkCamelCase(e, false);}super.visitExecutable(e, p);return null;}/*** 检查变量命名是否合法*/@Overridepublic Void visitVariable(VariableElement e, Void p) {// 如果这个Variable是枚举或常量,则按大写命名检查,否则按照驼式命名法规则检查if (e.getKind() == ENUM_CONSTANT || e.getConstantValue() != null || heuristicallyConstant(e))checkAllCaps(e);else checkCamelCase(e, false);return null;}/*** 判断一个变量是否是常量*/private boolean heuristicallyConstant(VariableElement e) {if (e.getEnclosingElement().getKind() == INTERFACE) return true;else if (e.getKind() == FIELD && e.getModifiers().containsAll(EnumSet.of(PUBLIC, STATIC, FINAL)))return true;else {return false;}}/*** 检查传入的 Element 是否符合驼式命名法,如果不符合,则输出警告信息*/private void checkCamelCase(Element e, boolean initialCaps) {String name = e.getSimpleName().toString();boolean previousUpper = false;boolean conventional = true;int firstCodePoint = name.codePointAt(0);if (Character.isUpperCase(firstCodePoint)) {previousUpper = true;if (!initialCaps) {messager.printMessage(WARNING, "名称“" + name + "”应当以小写字母开头", e);return;}} else if (Character.isLowerCase(firstCodePoint)) {if (initialCaps) {messager.printMessage(WARNING, "名称“" + name + "”应当以大写字母开头", e);return;}} else {conventional = false;}if (conventional) {int cp = firstCodePoint;for (int i = Character.charCount(cp); i < name.length(); i += Character.charCount(cp)) {cp = name.codePointAt(i);if (Character.isUpperCase(cp)) {if (previousUpper) {conventional = false;break;}}}previousUpper = true;} else previousUpper = false;if (!conventional)messager.printMessage(WARNING, "名称“" + name + "”应当符合驼式命名法(Camel Case Names)", e);}/*** 大写命名检查,要求第一个字母必须是大写的英文字母,其余部分可以是下划线或大写字母*/private void checkAllCaps(Element e) {String name = e.getSimpleName().toString();boolean conventional = true;int firstCodePoint = name.codePointAt(0);if (!Character.isUpperCase(firstCodePoint)) {conventional = false;} else {boolean previousUnderscore = false;int cp = firstCodePoint;for (int i = Character.charCount(cp); i < name.length(); i += Character.charCount(cp)) {cp = name.codePointAt(i);if (cp == (int) '_') {if (previousUnderscore) {conventional = false;break;}previousUnderscore = true;} else {previousUnderscore = false;if (!Character.isUpperCase(cp) && !Character.isDigit(cp)) {conventional = false;break;}}}}if (!conventional) {messager.printMessage(WARNING, "常量“" + name + "”应当全部以大写字母或下划线命名,并且以字母开头", e);}}}
}
NameChecker
通过继承 javax.lang.model.util.ElementScanner8
的 NameCheckScanner
类,以 Visitor 模式实现对语法树的遍历;通过 checkCamelCase() 与 checkAllCaps() 实现驼峰命名法和全大写命名的检查;分别在 visitType()、visitVariable()、visitExecutable() 中对类、字段、方法进行检查;
3. 运行与测试
不符合规范的代码演示
public class BADLY_NAMED_CODE {enum colors {red, blue, green;}static final int _FORTY_TWO = 42;public static int NOT_A_CONSTANT = _FORTY_TWO;protected void BADLY_NAMED_CODE() {return;}public void NOTcamelCASEmethodNAME() {return;}
}
运行注解处理器
# 编译注解处理器,切换到 src/main/java 路径
javac edu/aurelius/jvm/compiler/NameChecker.java
javac edu/aurelius/jvm/compiler/NameCheckProcessor.java# 编译时运行注解处理器
javac -processor edu.aurelius.jvm.compiler.NameCheckProcessor edu/aurelius/jvm/compiler/BADLY_NAMED_CODE.java
检查效果
edu/aurelius/jvm/compiler/BADLY_NAMED_CODE.java:7: warning: 名称“BADLY_NAMED_CODE”应当符合驼式命名法(Camel Case Names)
public class BADLY_NAMED_CODE {^
edu/aurelius/jvm/compiler/BADLY_NAMED_CODE.java:8: warning: 名称“colors”应当以大写字母开头enum colors {^
edu/aurelius/jvm/compiler/BADLY_NAMED_CODE.java:9: warning: 常量“red”应当全部以大写字母或下划线命名,并且以字母开头red, blue, green;^
edu/aurelius/jvm/compiler/BADLY_NAMED_CODE.java:9: warning: 常量“blue”应当全部以大写字母或下划线命名,并且以字母开头red, blue, green;^
edu/aurelius/jvm/compiler/BADLY_NAMED_CODE.java:9: warning: 常量“green”应当全部以大写字母或下划线命名,并且以字母开头red, blue, green;^
edu/aurelius/jvm/compiler/BADLY_NAMED_CODE.java:12: warning: 常量“_FORTY_TWO”应当全部以大写字母或下划线命名,并且以字母开头static final int _FORTY_TWO = 42;^
edu/aurelius/jvm/compiler/BADLY_NAMED_CODE.java:13: warning: 名称“NOT_A_CONSTANT”应当以小写字母开头public static int NOT_A_CONSTANT = _FORTY_TWO;^
edu/aurelius/jvm/compiler/BADLY_NAMED_CODE.java:15: warning: 一个普通方法 “BADLY_NAMED_CODE”不应当与类名重复,避免与构造函数产生混淆protected void BADLY_NAMED_CODE() {^
edu/aurelius/jvm/compiler/BADLY_NAMED_CODE.java:15: warning: 名称“BADLY_NAMED_CODE”应当以小写字母开头protected void BADLY_NAMED_CODE() {^
edu/aurelius/jvm/compiler/BADLY_NAMED_CODE.java:19: warning: 名称“NOTcamelCASEmethodNAME”应当以小写字母开头public void NOTcamelCASEmethodNAME() {^
10 warnings
-XprintRounds
、-XprintProcessorInfo
参数可以进一步跟踪注解处理器的运作详细信息;
4. 其他应用案例
- 校验 Hibernate 标签的正确性(Hibernate Validator Annotation Processor);
- 自动为字段生成 getter、setter 方法等辅助内容(Lombok,根据已有元素生成新的语法树元素);
上一篇:「JVM 编译优化」Java 语法糖(泛型、自动装箱/拆箱、条件编译)
PS:感谢每一位志同道合者的阅读,欢迎关注、评论、赞!
参考资料:
- [1]《深入理解 Java 虚拟机》
相关文章:

「JVM 编译优化」插入式注解处理器(自定义代码编译检查)
JDK 的编译子系统暴露给用户直接控制的功能相对很少,除了虚拟机即时编译的若干参数,便只有 JSR-296 中定义的插入式注解处理器 API; 文章目录1. 目标2. 实现3. 运行与测试4. 其他应用案例1. 目标 前端编译器在讲 Java 源码编译成字节码时对源…...

一文彻底理解大小端和位域 BIGENDIAN LITTLEENDIAN
一文彻底理解大小端和位域 为什么有大小端 人们一直认为大道至简,就好像物理学上的世界追求使用一个理论来统一所有的现象。为什么cpu存在大小端之分,一言以蔽之,这两种模式各有各的优点,其各自的优点就是对方的缺点,…...

面试准备知识点与总结——(虚拟机篇)
目录JVM的内存结构JVM哪些部分会发生内存溢出方法区、永久代、元空间三者之间的关系JVM内存参数JVM垃圾回收算法1.标记清除法2.标记整理3.标记复制说说GC和分代回收算法三色标记与并发漏标的问题垃圾回收器项目中什么时候会内存溢出,怎么解决类加载过程三个阶段何为…...

spring cloud 集成 seata 分布式事务
spring cloud 集成 seata 分布式事务 基于 seata-server 1.6.x 序言 下载 seata-server 准备一个数据库 seata 专门为 seata-server 做存储,如, 可以指定 branch_tabledistributed_lockglobal_tablelock_table 准备一个业务库,比如存放定单ÿ…...

k8s篇之概念介绍
文章目录时光回溯什么是K8SK8S不是什么一、K8S构成组件控制平面组件(Control Plane Components)kube-apiserveretcdkube-schedulerkube-controller-managercloud-controller-managerNode 组件kubeletkube-proxy容器运行时(Container Runtime&…...

JavaScript学习第1天:浏览器组成、JS的组成、变量、数据类型转化、运算符、while和do...while循环
目录一、浏览器的组成二、JS的组成三、变量1、同时声明多个变量2、声明变量特殊情况四、数据类型1、数据类型2、 isNaN()方法3、字符串转义符4、字符串拼接5、特殊拼接五、数据类型转换1、转化为字符串2、转化为数字型3、转化为布尔值六、运算符1、递增和递减运算符2、逻辑运算…...

【Flutter入门到进阶】Dart进阶篇---Dart多线程异步原理
1 Isolate 1.1 什么是Isolate 1.1.1 概念 线程?异步?隔离?到底什么意思? Isolate中文意思是隔离,从使用角度来说是Dart的线程,但是从本质虚拟机的实现角度来讲Isolate是一组封装。 isolate可以理解为dar…...

WEB系列(二)-----------XSS
XSS原理及基础 定义 恶意攻击者会往Web页面里插入JS代码,当用户点击网页时.镶嵌的JS代码就会执行,从而达到恶意的特殊目的. 原因 程序对输入和输出的控制不够严格,导致payload输出到前段时被浏览器当做有效代码执行从而产生危害。 分类 存储型反射型DOM型 测…...

[python入门㊾] - python异常中的断言
目录 ❤ 断言的功能与语法 ❤ 常用断言 ❤ 常用的断言表达方式 ❤ 异常断言 ❤ 正则断言 ❤ 检查断言装饰器 ❤ 断言的功能与语法 Python assert(断言)用于判断一个表达式,在表达式条件为 False 的时候触发异常 断言可以在条件…...

一文告诉你什么是财务数据治理?
大家好,我是梦想家Alex,今天是周末,就不给大家分享技术文了~应出版社老师推荐,文末给大家送几本DAMA中国主席力荐,20位行业专家历时2年共同打造的《财务数据治理实战》,将数据治理理论应用于财务…...

MySQL数据库调优————ORDER BY语句
ORDER BY调优的核心原理,原则是利用索引的有序性跳过排序环节 关于ORDER BY语句的一些尝试 我们使用employees表进行尝试,索引情况如下 在执行计划的结果中,Extra里如果存在,Using filesort则表示,排序没有使用到索…...

Linux命令之grep
Linux grep是一个非常强大的文本搜索工具。按照给定的正则表达式对目标文本进行匹配检查,打印匹配到的行。grep命令可以跟其他命令一起使用,对其他命令的输出进行匹配。 grep语法如下: grep [options] [pattern] content 文本检索 grep可以对…...

一起学 pixijs(4):如何绘制文字md
大家好,我是前端西瓜哥,今天我们来学 pixijs 如何绘制文字。pixijs 版本为 7.1.2。 使用原生的 WebGL 来绘制文字是非常繁琐的,pixijs 对此进行了高层级的封装,提供了 Text 类和 BitMapText 类来绘制文字。 Text 最基本的写法&…...

mac m1设备上安装Qt并使用qt编程遇到的问题以及解决方式
# 简介: 首先在M1平台上的程序可以看到有两种架构,分别是intel的(x86-64)和苹果的m1(arm64架构),根据苹果的介绍,当在m1上面运行intel程序的时候使用的是转译的方式运行的ÿ…...

tensorflow 学习笔记(二):神经网络的优化过程
前言: 学习跟随 如何原谅奋力过但无声的 tensorflow 笔记笔记。 本章主要讲解神经网络的优化过程:神经网络的优化方法,掌握学习率、激活函数、损失函数和正则化的使用,用 Python 语言写出 SGD、Momentum、Adagrad、RMSProp、Ada…...

【Java】《Java8 实战》 CompletableFuture 学习
文章目录前言1. 并发(Concurrent) 和 并行(Parallel)1.1 并发的来源1.2 并发技术解决了什么问题2. 并行的来源2.1 并行解决了什么问题3. CompletableFuture 简介4. CompletableFuture 简单应用5. CompletableFuture 工厂方法的应用6. CompletableFuture join() 方法7. 使用 Par…...

Vue3之条件渲染
1.何为条件渲染 条件渲染就是在指定的条件下,渲染出指定的UI。比如当我们显示主页的时候,应该隐藏掉登录等一系列不相干的UI元素。即UI元素只在特定条件下进行显示。而在VUE3中,这种UI元素的显示和隐藏可以通过两个关键字,v-if 和…...

将Nginx 核心知识点扒了个底朝天(四)
为什么 Nginx 不使用多线程? Apache: 创建多个进程或线程,而每个进程或线程都会为其分配 cpu 和内存(线程要比进程小的多,所以 worker 支持比 perfork 高的并发),并发过大会榨干服务器资源。 Nginx: 采用…...

设计模式之工厂模式
文章の目录一、什么是工厂模式二、工厂模式有什么用?三、应用场景四、示例1、用字面量的方式创建对象2、使用工厂模式创建对象参考写在最后一、什么是工厂模式 工厂模式是一种众所周知的设计模式,广泛应用于软件工程领域,用于抽象创建特定对…...

80.链表-由来
链表是怎么发展来的 线性表:是n个具有相同特性的数据元素的有限序列。 链表:具有线性存储结构的线性表。 为什么需要使用链表?(链表是如何被设计出来的) 程序开发最重要的部分是如何在项目程序中找到一种合适的、好…...

元胞自动机
文章目录前言文献阅读摘要主要贡献方法框架实验结论元胞自动机元胞自动机是什么?构成及规则案例及代码实现总结前言 This week,the paper proposes a Multi-directional Temporal Convolutional Artificial Neural Network (MTCAN) model to impute and forecast P…...

设计模式之各种设计模式总结与对比
目录1 目标2 定位3 一句话归纳设计原则4 G0F 23种设计模式简介5 设计模式使用频次总结6 —句话归纳设计模式7 设计模式之间的关联关系和对比1 目标 1、 简要分析GoF 23种设计模式和设计原则,做整体认知。 2、 剖析Spirng的编程思想,启发思维,为之后深入学习Spring…...

JAVA练习55- Fizz Buzz
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 一、题目-Fizz Buzz 1.题目描述 2.思路与代码 2.1 思路 2.2 代码 总结 前言 提示:这里可以添加本文要记录的大概内容: 2月19日练习…...

LeetCode笔记:Biweekly Contest 98
LeetCode笔记:Biweekly Contest 98 1. 题目一 1. 解题思路2. 代码实现 2. 题目二 1. 解题思路2. 代码实现 3. 题目三 1. 解题思路2. 代码实现 4. 题目四 比赛链接:https://leetcode.com/contest/biweekly-contest-98 1. 题目一 给出题目一的试题链接如…...

HNUCM-《算法分析与设计》期末考试考前复习题
问题 A: X星人的地盘题目描述一天,X星人和Y星人在一张矩形地图上玩抢地盘的游戏。X星人每抢到一块地,在地图对应的位置标记一个“X”;Y星人每抢到一块地,在地图对应的位置标记一个“Y”;如果某一块地无法确定其归属则标…...

算法导论【分治思想】—大数乘法、矩阵相乘、残缺棋盘
这里写自定义目录标题分治法概述特点大数相乘问题分治算法矩阵相乘分治算法残缺棋盘分治算法分治法概述 在分而治之的方法中,一个问题被划分为较小的问题,然后较小的问题被独立地解决,最后较小问题的解决方案被组合成一个大问题的解决。 通常…...

Java【七大排序】算法详细图解,一篇文章吃透
文章目录一、排序相关概念二、七大排序1,直接插入排序2,希尔排序3,选择排序4,堆排序5,冒泡排序5.1冒泡排序的优化6,快速排序6.1 快速排序的优化7,归并排序三、排序算法总体分析对比总结提示&…...

Autosar OS IOC
Inter-OS-Application Communicator 背景和基本原理General purposeIOC functionalityCommunicationNotificationIOC interface背景和基本原理 The IOC implementation shall be part of the Operating System IOC和操作系统紧密相关,是操作系统实现的一部分 The IO…...

记录一次Binder内存相关的问题导致APP被杀的BUG排查过程
事情的起因的QA压测过程发生进程号变更,怀疑APP被杀掉过,于是开始看日志 APP的压测平台会上报进程号变更时间点,发现是在临晨12:20分,先大概确定在哪个日志文件去找关键信息一开始怀疑是crash,然后就在日志…...

设计模式(十)----结构型模式之适配器模式
1、概述 如果去欧洲国家去旅游的话,他们的插座如下图最左边,是欧洲标准。而我们使用的插头如下图最右边的。因此我们的笔记本电脑,手机在当地不能直接充电。所以就需要一个插座转换器,转换器第1面插入当地的插座,第2面…...