网站做实名验证成都广告设计培训班

news/2025/9/25 18:39:31/文章来源:
网站做实名验证,成都广告设计培训班,ui设计师mike个人网站,wordpress付费知识管理插件世界上只有一种英雄主义#xff0c;就是看清生活的真相之后依然热爱生活。对于 Lombok 我相信大部分人都不陌生#xff0c;但对于它的实现原理以及缺点却鲜为人知#xff0c;而本文将会从 Lombok 的原理出发#xff0c;手撸一个简易版的 Lombok#xff0c;让你理解这个热门… 世界上只有一种英雄主义就是看清生活的真相之后依然热爱生活。对于 Lombok 我相信大部分人都不陌生但对于它的实现原理以及缺点却鲜为人知而本文将会从 Lombok 的原理出发手撸一个简易版的 Lombok让你理解这个热门技术背后的执行原理以及它的优缺点。简介 在讲原理之前我们先来复习一下 Lombok (老司机可直接跳过本段)。Lombok 是一个非常热门的开源项目 (https://github.com/rzwitserloot/lombok)使用它可以有效的解决 Java 工程中那些繁琐又重复代码例如 Setter、Getter、toString、equals、hashCode 以及非空判断等都可以使用 Lombok 有效的解决。使用 1.添加 Lombok 插件在 IDE 中必须安装 Lombok 插件才能正常调用被 Lombok 修饰的代码以 Idea 为例添加的步骤如下点击 File Settings Plugins 进入插件管理页面点击 Browse repositories...搜索 Lombok Plugin点击 Install plugin 安装插件重启 IntelliJ IDEA安装完成如下图所示2.添加 Lombok 库接下来我们需要在项目中添加最新的 Lombok 库如果是 Maven 项目直接在 pom.xml 中添加如下配置dependencies!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --dependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdversion1.18.12/versionscopeprovided/scope/dependency /dependencies 如果是 JDK 9 可使用模块的方式添加配置如下annotationProcessorPathspathgroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdversion1.18.12/version/path /annotationProcessorPaths 3.使用 Lombok接下来到了前半部分中最重要的 Lombok 使用环节了我们先来看在没有使用 Lombok 之前的代码public class Person {private Integer id;private String name;public Integer getId() {return id;}public void setId(Integer id) {this.id id;}public String getName() {return name;}public void setName(String name) {this.name name;} } 这是使用 Lombok 之后的代码Getter Setter public class Person {private Integer id;private String name; } 可以看出在 Lombok 之后用一个注解就搞定了之前所有 Getter/Setter 的代码让代码瞬间优雅了很多。Lombok 所有注解如下val用在局部变量前面相当于将变量声明为 finalNonNull给方法参数增加这个注解会自动在方法内对该参数进行是否为空的校验如果为空则抛出 NPENullPointerExceptionCleanup自动管理资源用在局部变量之前在当前变量范围内即将执行完毕退出之前会自动清理资源自动生成 try-finally 这样的代码来关闭流Getter/Setter用在属性上再也不用自己手写 setter 和 getter 方法了还可以指定访问范围ToString用在类上可以自动覆写 toString 方法当然还可以加其他参数例如 ToString(exclude”id”) 排除 id 属性或者 ToString(callSupertrue, includeFieldNamestrue) 调用父类的 toString 方法包含所有属性EqualsAndHashCode用在类上自动生成 equals 方法和 hashCode 方法NoArgsConstructor, RequiredArgsConstructor and AllArgsConstructor用在类上自动生成无参构造和使用所有参数的构造函数以及把所有 NonNull 属性作为参数的构造函数如果指定 staticNameof 参数同时还会生成一个返回类对象的静态工厂方法比使用构造函数方便很多Data注解在类上相当于同时使用了 ToString、EqualsAndHashCode、Getter、Setter 和 RequiredArgsConstrutor 这些注解对于 POJO 类十分有用Value用在类上是 Data 的不可变形式相当于为属性添加 final 声明只提供 getter 方法而不提供 setter 方法Builder用在类、构造器、方法上为你提供复杂的 builder APIs让你可以像如下方式一样调用Person.builder().name(xxx).city(xxx).build()SneakyThrows自动抛受检异常而无需显式在方法上使用 throws 语句Synchronized用在方法上将方法声明为同步的并自动加锁而锁对象是一个私有的属性 或LOCK而 Java 中的 synchronized 关键字锁对象是 this锁在 this 或者自己的类对象上存在副作用就是你不能阻止非受控代码去锁 this 或者类对象这可能会导致竞争条件或者其它线程错误Getter(lazytrue)可以替代经典的 Double Check Lock 样板代码Log根据不同的注解生成不同类型的 log 对象但是实例名称都是 log有六种可选实现类CommonsLog Creates log org.apache.commons.logging.LogFactory.getLog(LogExample.class);Log Creates log java.util.logging.Logger.getLogger(LogExample.class.getName());Log4j Creates log org.apache.log4j.Logger.getLogger(LogExample.class);Log4j2 Creates log org.apache.logging.log4j.LogManager.getLogger(LogExample.class);Slf4j Creates log org.slf4j.LoggerFactory.getLogger(LogExample.class);XSlf4j Creates log org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);它们的具体使用如下① val 使用val sets new HashSetString(); // 相当于 final SetString sets new HashSet(); ② NonNull 使用public void notNullExample(NonNull String string) {string.length(); } // 相当于 public void notNullExample(String string) {if (string ! null) {string.length();} else {throw new NullPointerException(null);} } ③ Cleanup 使用public static void main(String[] args) {try {Cleanup InputStream inputStream new FileInputStream(args[0]);} catch (FileNotFoundException e) {e.printStackTrace();}// 相当于InputStream inputStream null;try {inputStream new FileInputStream(args[0]);} catch (FileNotFoundException e) {e.printStackTrace();} finally {if (inputStream ! null) {try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}} } ④ Getter/Setter 使用Setter(AccessLevel.PUBLIC) Getter(AccessLevel.PROTECTED) private int id; private String shap; ⑤ ToString 使用ToString(exclude id, callSuper true, includeFieldNames true) public class LombokDemo {private int id;private String name;private int age;public static void main(String[] args) {// 输出 LombokDemo(superLombokDemo48524010, namenull, age0)System.out.println(new LombokDemo());} } ⑥ EqualsAndHashCode 使用EqualsAndHashCode(exclude {id, shape}, callSuper false) public class LombokDemo {private int id;private String shap; } ⑦ NoArgsConstructor、RequiredArgsConstructor、AllArgsConstructor 使用NoArgsConstructor RequiredArgsConstructor(staticName of) AllArgsConstructor public class LombokDemo {NonNullprivate int id;NonNullprivate String shap;private int age;public static void main(String[] args) {new LombokDemo(1, Java);// 使用静态工厂方法LombokDemo.of(2, Java);// 无参构造new LombokDemo();// 包含所有参数new LombokDemo(1, Java, 2);} } ⑧ Builder 使用Builder public class BuilderExample {private String name;private int age;Singularprivate SetString occupations;public static void main(String[] args) {BuilderExample test BuilderExample.builder().age(11).name(Java).build();} } ⑨ SneakyThrows 使用public class ThrowsTest {SneakyThrows()public void read() {InputStream inputStream new FileInputStream();}SneakyThrowspublic void write() {throw new UnsupportedEncodingException();}// 相当于public void read() throws FileNotFoundException {InputStream inputStream new FileInputStream();}public void write() throws UnsupportedEncodingException {throw new UnsupportedEncodingException();} } ⑩ Synchronized 使用public class SynchronizedDemo {Synchronizedpublic static void hello() {System.out.println(world);}// 相当于private static final Object $LOCK new Object[0];public static void hello() {synchronized ($LOCK) {System.out.println(world);}} } ⑪ Getter(lazy true) 使用public class GetterLazyExample {Getter(lazy true)private final double[] cached expensive();private double[] expensive() {double[] result new double[1000000];for (int i 0; i result.length; i) {result[i] Math.asin(i);}return result;} } // 相当于 import java.util.concurrent.atomic.AtomicReference; public class GetterLazyExample {private final AtomicReferencejava.lang.Object cached new AtomicReference();public double[] getCached() {java.lang.Object value this.cached.get();if (value null) {synchronized (this.cached) {value this.cached.get();if (value null) {final double[] actualValue expensive();value actualValue null ? this.cached : actualValue;this.cached.set(value);}}}return (double[]) (value this.cached ? null : value);}private double[] expensive() {double[] result new double[1000000];for (int i 0; i result.length; i) {result[i] Math.asin(i);}return result;} } 原理分析 我们知道 Java 的编译过程大致可以分为三个阶段解析与填充符号表注解处理分析与字节码生成编译过程如下图所示而 Lombok 正是利用「注解处理」这一步进行实现的Lombok 使用的是 JDK 6 实现的 JSR 269: Pluggable Annotation Processing API (编译期的注解处理器) 它是在编译期时把 Lombok 的注解代码转换为常规的 Java 方法而实现优雅地编程的。这一点可以在程序中得到验证比如本文刚开始用 Data 实现的代码在我们编译之后查看 Person 类的编译源码发现代码竟然是这样的可以看出 Person 类在编译期被注解翻译器修改成了常规的 Java 方法添加 Getter、Setter、equals、hashCode 等方法。Lombok 的执行流程如下可以看出在编译期阶段当 Java 源码被抽象成语法树 (AST) 之后Lombok 会根据自己的注解处理器动态的修改 AST增加新的代码 (节点)在这一切执行之后再通过分析生成了最终的字节码 (.class) 文件这就是 Lombok 的执行原理。手撸一个 Lombok 我们实现一个简易版的 Lombok 自定义一个 Getter 方法我们的实现步骤是自定义一个注解标签接口并实现一个自定义的注解处理器利用 tools.jar 的 javac api 处理 AST (抽象语法树)使用自定义的注解处理器编译代码。这样就可以实现一个简易版的 Lombok 了。1.定义自定义注解和注解处理器首先创建一个 MyGetter.java 自定义一个注解代码如下import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;Retention(RetentionPolicy.SOURCE) // 注解只在源码中保留 Target(ElementType.TYPE) // 用于修饰类 public interface MyGetter { // 定义 Getter} 再实现一个自定义的注解处理器代码如下import com.sun.source.tree.Tree; import com.sun.tools.javac.api.JavacTrees; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Type; import com.sun.tools.javac.processing.JavacProcessingEnvironment; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.TreeMaker; import com.sun.tools.javac.tree.TreeTranslator; import com.sun.tools.javac.util.*;import javax.annotation.processing.*; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import javax.tools.Diagnostic; import java.util.Set;SupportedSourceVersion(SourceVersion.RELEASE_8) SupportedAnnotationTypes(com.example.lombok.MyGetter) public class MyGetterProcessor extends AbstractProcessor {private Messager messager; // 编译时期输入日志的private JavacTrees javacTrees; // 提供了待处理的抽象语法树private TreeMaker treeMaker; // 封装了创建AST节点的一些方法private Names names; // 提供了创建标识符的方法Overridepublic synchronized void init(ProcessingEnvironment processingEnv) {super.init(processingEnv);this.messager processingEnv.getMessager();this.javacTrees JavacTrees.instance(processingEnv);Context context ((JavacProcessingEnvironment) processingEnv).getContext();this.treeMaker TreeMaker.instance(context);this.names Names.instance(context);}Overridepublic boolean process(Set? extends TypeElement annotations, RoundEnvironment roundEnv) {Set? extends Element elementsAnnotatedWith roundEnv.getElementsAnnotatedWith(MyGetter.class);elementsAnnotatedWith.forEach(e - {JCTree tree javacTrees.getTree(e);tree.accept(new TreeTranslator() {Overridepublic void visitClassDef(JCTree.JCClassDecl jcClassDecl) {ListJCTree.JCVariableDecl jcVariableDeclList List.nil();// 在抽象树中找出所有的变量for (JCTree jcTree : jcClassDecl.defs) {if (jcTree.getKind().equals(Tree.Kind.VARIABLE)) {JCTree.JCVariableDecl jcVariableDecl (JCTree.JCVariableDecl) jcTree;jcVariableDeclList jcVariableDeclList.append(jcVariableDecl);}}// 对于变量进行生成方法的操作jcVariableDeclList.forEach(jcVariableDecl - {messager.printMessage(Diagnostic.Kind.NOTE, jcVariableDecl.getName() has been processed);jcClassDecl.defs jcClassDecl.defs.prepend(makeGetterMethodDecl(jcVariableDecl));});super.visitClassDef(jcClassDecl);}});});return true;}private JCTree.JCMethodDecl makeGetterMethodDecl(JCTree.JCVariableDecl jcVariableDecl) {ListBufferJCTree.JCStatement statements new ListBuffer();// 生成表达式 例如 this.a a;JCTree.JCExpressionStatement aThis makeAssignment(treeMaker.Select(treeMaker.Ident(names.fromString(this)), jcVariableDecl.getName()), treeMaker.Ident(jcVariableDecl.getName()));statements.append(aThis);JCTree.JCBlock block treeMaker.Block(0, statements.toList());// 生成入参JCTree.JCVariableDecl param treeMaker.VarDef(treeMaker.Modifiers(Flags.PARAMETER),jcVariableDecl.getName(), jcVariableDecl.vartype, null);ListJCTree.JCVariableDecl parameters List.of(param);// 生成返回对象JCTree.JCExpression methodType treeMaker.Type(new Type.JCVoidType());return treeMaker.MethodDef(treeMaker.Modifiers(Flags.PUBLIC),getNewMethodName(jcVariableDecl.getName()), methodType, List.nil(),parameters, List.nil(), block, null);}private Name getNewMethodName(Name name) {String s name.toString();return names.fromString(get s.substring(0, 1).toUpperCase() s.substring(1, name.length()));}private JCTree.JCExpressionStatement makeAssignment(JCTree.JCExpression lhs, JCTree.JCExpression rhs) {return treeMaker.Exec(treeMaker.Assign(lhs,rhs));} } 自定义的注解处理器是我们实现简易版的 Lombok 的重中之重我们需要继承 AbstractProcessor 类重写它的 init() 和 process() 方法在 process() 方法中我们先查询所有的变量在给变量添加对应的方法。我们使用 TreeMaker 对象和 Names 来处理 AST如上代码所示。当这些代码写好之后我们就可以新增一个 Person 类来试一下我们自定义的 MyGetter 功能了代码如下MyGetter public class Person {private String name; } 2.使用自定义的注解处理器编译代码上面的所有流程执行完成之后我们就可以编译代码测试效果了。首先我们先进入代码的根目录执行以下三条命令。进入的根目录如下① 使用 tools.jar 编译自定义的注解器javac -cp $JAVA_HOME/lib/tools.jar MyGetter* -d .注意命令最后面有一个“.”表示当前文件夹。② 使用自定义注解器编译 Person 类javac -processor com.example.lombok.MyGetterProcessor Person.java③ 查看 Person 源码javap -p Person.class源码文件如下可以看到我们自定义的 getName() 方法已经成功生成了到这里简易版的 Lombok 就大功告成了。Lombok 优缺点 Lombok 的优点很明显它可以让我们写更少的代码节约了开发时间并且让代码看起来更优雅它的缺点有以下几个。缺点1降低了可调试性Lombok 会帮我们自动生成很多代码但这些代码是在编译期生成的因此在开发和调试阶段这些代码可能是“丢失的”这就给调试代码带来了很大的不便。缺点2可能会有兼容性问题Lombok 对于代码有很强的侵入性加上现在 JDK 版本升级比较快每半年发布一个版本而 Lombok 又属于第三方项目并且由开源团队维护因此就没有办法保证版本的兼容性和迭代的速度进而可能会产生版本不兼容的情况。缺点3可能会坑到队友尤其对于组人来的新人可能影响更大假如这个之前没用过 Lombok当他把代码拉下来之后因为没有安装 Lombok 的插件在编译项目时就会提示找不到方法等错误信息导致项目编译失败进而影响了团结成员之间的协作。缺点4破坏了封装性面向对象封装的定义是通过访问权限控制隐藏内部数据外部仅能通过类提供的有限的接口访问和修改内部数据。也就是说我们不应该无脑的使用 Lombok 对外暴露所有字段的 Getter/Setter 方法因为有些字段在某些情况下是不允许直接修改的比如购物车中的商品数量它直接影响了购物详情和总价因此在修改的时候应该提供统一的方法进行关联修改而不是给每个字段添加访问和修改的方法。小结 本文我们介绍了 Lombok 的使用以及执行原理它是通过 JDK 6 实现的 JSR 269: Pluggable Annotation Processing API (编译期的注解处理器) 在编译期时把 Lombok 的注解转换为 Java 的常规方法的我们可以通过继承 AbstractProcessor 类重写它的 init() 和  process() 方法实现一个简易版的 Lombok。但同时 Lombok 也存在这一些使用上的缺点比如降低了可调试性、可能会有兼容性等问题因此我们在使用时要根据自己的业务场景和实际情况来选择要不要使用 Lombok以及应该如何使用 Lombok。最后提醒一句再好的技术也不是万金油就好像再好的鞋子也得适合自己的脚才行感谢阅读希望本文对你能所启发。觉得不错的话分享给需要的朋友谢谢。参考 鸣谢https://juejin.im/post/5a6eceb8f265da3e467555fehttps://www.tuicool.com/articles/y6rUz2V【END】《大厂内部资料》Redis 性能优化的 13 条军规全网首发因为我说volatile 是轻量级的 synchronized面试官让我回去等通知Java14发布Switch竟如此简单Lombok也不需要了来用Idea搭建Java14吧关注下方二维码订阅更多精彩内容朕已阅

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/917379.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI Agent如何重塑人力资源管理?易路iBuilder平台实战案例深度解析

来源|商学院9月刊 文|吕笑颜 ID | BMR2004 导读:本文深度报道了易路iBuilder作为国内首个HR垂直AI Agent操作系统,如何通过39个智能体全面重构人力资源管理价值链。文章基于对易路CEO王天扬的专访,系统阐述了iBui…

docker-compose + macvlan + Elasticsearch - 9.1.4 + Kibana - 9.1.4

操作过程创建工作目录mkdir -p /opt/porsCloud/24-elastic进入工作目录cd /opt/porsCloud/24-elastic创建必要的目录mkdir es_conf es_data es_logs es_plugins kibana_conf kibana_data赋予权限chown -R 1000:0 es_co…

WinForm 计时器 Timer 学习笔记

1. Timer 是干啥的? 就是个“自动闹钟”: 你设定每隔多少毫秒(比如 1000 毫秒 = 1 秒),它就自动执行一段代码。 常见用途:实时显示时间 倒计时 定时刷新数据 轮询状态2. 怎么用?三步搞定(WinForm 拖控件方式)…

RocketMQ入门:基本概念、安装、本地部署与集群部署 - 详解

RocketMQ入门:基本概念、安装、本地部署与集群部署 - 详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consol…

重庆制作网站公司简介梵克雅宝五花手链

React中的“端口(Portals)”是一种将子节点渲染到DOM****树以外的部分的技术。在React应用中,通常情况下组件的渲染是遵循DOM的层次结构,即子组件会渲染在父组件的DOM节点内部。然而,有些情况下,开发者可能…

【LeetCode】122. 买卖股票的最佳时机 II

122. 买卖股票的最佳时机 II 区间内,差值最大,注意并不是最低值和最大值差值就是最大,例如,3,7,1,3,4。差值最大是7-3 解法一若价格一直往下跌,不买入 假设第一天买入,若买入后价格往下跌,应该下一天买入 若…

VSCode 使用技巧笔记

VSCode 笔记备忘插件Git History (donjayamanne.githistory)可以按行查看 git 历史记录Git Graph (mhutchie.git-graph)Bookmarks (alefragnani.bookmarks)highlight (debugpig.highlight)高亮选中的词 小技巧选择包含…

Ansible + Docker 部署 Apache Kafka 3.9 集群

Ansible + Docker 部署 Apache Kafka 3.9 集群1. 准备工作 1.2 主机列表IP 主机名 内存(GB) CPU核数 磁盘 操作系统 CPU 架构10.0.0.13 arc-pro-dc01 my.registry.com 16 1 500GB CentOS 7.9.2009 x86_6410.0.0.14…

深入了解一波JVM内存模型

深入了解一波JVM内存模型 JDK体系结构与跨平台特性介绍通过官方的结构图看出,JVM提供底层的平台支持,JRE提供运行环境所必须的类,在这个基础上去跑我们的java程序。JVM为我们屏蔽了操作系统的差异性,使java程序得以…

完整教程:K230基础-PWM控制介绍及应用

完整教程:K230基础-PWM控制介绍及应用pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Mon…

什么是UDFScript用户自定义脚本

本文分享自天翼云开发者社区《什么是UDFScript用户自定义脚本》.作者:郭****迎 UDFScript介绍 用户自定义脚本(User Defined Script,简称UDFScript)是一个可供您快速实现CDN定制化配置的工具箱,当CDN的标准配置无…

高端网站设计中的微交互:细节如何决定用户体验

高端网站设计中的微交互:细节如何决定用户体验在高端网站设计的语境下,“视觉审美”已经不再是唯一的竞争点。真正能打动用户、建立长期信任的,是那些嵌入在每一次操作、点击、过渡中的细节优化。微交互(Microinte…

合肥建设干部学校网站首页凡科 做网站

[原创]好买财富接口测试自动化实践

安徽建设工程信息网站广西建设工程协会网站

项目hbase数据库出现很诡异的assignment ,region移动的src和dest都是同一台regionserver,不过时间戳不同,启动的只有一个regionserver, 不知道怎么出现了两个时间戳 分析下源码解决一下 loadbalance只有一个实现 org.apache.hado…

软件开发公司如何通过 UI 设计服务打造差异化竞争力

软件开发公司如何通过 UI 设计服务打造差异化竞争力在数字化浪潮推动下,软件开发行业的竞争越来越激烈。功能上的差异化正逐渐缩小,技术壁垒也因开源生态与低代码平台而降低。在这种背景下,UI设计服务逐渐成为软件开…

CCPC2024-Zhengzhou G Same Sum(线段树)

CCPC2024-Zhengzhou G Same Sum 给一个序列。两种操作:区间加;查询一个偶数长区间,其中的值是否可以两两配对得到和相等。首先知道区间内的值两两配对得到的相等的和值为区间的平均数 m 。 可以转化为,这个区间的值…

短剧小程序开发全攻略:从技术选型到核心实现(前端+后端+运营干货) - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

Openwrt-DDNS 配置详解

在家庭或小型办公网络环境中,我们通常使用的是动态IP地址,这意味着每次重新连接互联网时,ISP可能会分配一个新的IP地址。这对于需要远程访问家庭网络中的设备(如NAS、监控摄像头或自建服务器)的用户来说是个问题。…

实用指南:Metal - 2. 3D 模型深度解析

实用指南:Metal - 2. 3D 模型深度解析pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Mon…

【2025.9.16】关于举办PostgreSQL数据库管理人才研修与评测班的通知

证书实图考核通过后,由工信部人才交流中心颁发证书,并纳入工信人才数据库 报名方式工信部人才交流中心组织的PostgreSQL认证,从2021起已经运营四年多时间,且获得行业高度认可,人大金仓、金蝶集团、迪思杰、用友、…