您好,今天的文章解决了一个看似不受欢迎的观点,我相信它会遇到一些阻力。仅仅因为某件事在技术上可行并不能自动认可其实用性或适用性。因此,我将尝试证实为什么我相信使用 lombok 可能会对您的代码产生不利影响。
在深入研究不太流行的细节之前,让我简要解释一下 lombok 库的功能。
project lombok 充当一个库,在编译时将代码注入到类中,这看起来几乎很神奇。要理解它的操作,了解java编译过程是必不可少的。 java编译主要分为三个阶段(图1):解析与输入、注解处理、分析与生成,如下图所示:
图 1 – 抽象语法树 (ast)
解析并输入:
在这里,编译器将源文件转换为抽象语法树(ast)。仅因语法无效而引发错误,而不会因错误的类或方法使用而引发错误。
注释处理:
在此阶段,自定义注释处理器会验证类或生成新资源(例如源文件)。如果生成新的源,这可能会触发新的编译周期。
分析并生成:
在最后阶段,编译器从 ast 生成字节码,检查损坏的引用,验证逻辑流,执行类型擦除,并对语法糖进行脱糖。
project lombok 作为注释处理器运行,通过注入新方法、字段或表达式来修改 ast。与生成新源的典型处理器不同,lombok 会更改现有类,这一区别使其能够直接影响生成的字节码。
j2se 1.5 中引入的 annotationprocessor 无法更改现有文件。它只能创建新文件或字节码。这使得 lombok 的实现很有趣,因为它们在编译阶段使用 annotationprocessor 来修改现有的 java 类文件。这是 的概述
使用 lombok 的编译过程(
图 2)。
图2 – 编译过程和lombok
针对龙目岛的案件增加编译时间
利益错位
@data @builder public class course { public enum type { online, onsite; @jsonvalue @override public string tostring() { return super.tostring().tolowercase(); } } private long id; private type type; }及其用法:
public class coursecreator { public static course createcourse(enrollment enrollment, registration registration) { course.type coursetype = enrollment.getvenue().equals(registration.getvenue()) ? course.type.onsite : course.type.online; return course.builder() .id(enrollment.getid()) .type(coursetype) .build(); } public static void main(string[] args) { registration registration = new registration(); enrollment enrollment = new enrollment(); course course = createcourse(enrollment, registration); system.out.println(course); } }虽然构建器模式得到了有效的实现,但也引发了有关所创建对象的完整性和有效性的关键问题。
如果我们在构建器中省略 .type(),我们将实例化什么类型的课程?
这行代码可以编译,但它让我们产生疑问:我们实际上创建了什么类型的课程?这是有效的课程实例吗?
course.builder().id(1l).build();这些担忧表明,开发人员可能会受到注释便利性的影响,可能会忽视维护业务逻辑完整性所需的彻底的域建模。不要让 lombok 决定我们的设计,更重要的是确保与业务需求保持一致的深思熟虑的方法。
考虑调整实施,以确保任何课程创建都清晰且受业务环境的约束:
@data public class course { private enum type { online, onsite; @jsonvalue @override public string tostring() { return super.tostring().tolowercase(); } } public static course online(long id) { return new course(id, type.online); } public static course onsite(long id) { return new course(id, type.onsite); } private long id; private type type; public boolean isonline() { return type.online.equals(this.type); } public boolean isonsite() { return type.onsite.equals(this.type); } }通过重新设计类:
public class coursemanagement { public static course createappropriatecourse(enrollment enrollment, registration registration) { return enrollment.getvenue().equals(registration.getvenue()) ? course.onsite(enrollment.getid()) : course.online(enrollment.getid()); } public static void main(string[] args) { registration registration = new registration(); enrollment enrollment = new enrollment(); course createdcourse = createappropriatecourse(enrollment, registration); system.out.println(createdcourse); } }修改后的设计确保了 course 对象的创建是明确且万无一失的,反映了领域固有的受限选择并消除了歧义。
此外,通过将 type 枚举设为私有并提供清晰、显式的方法(如 isonline() 和 isonsite()),我们确保仅公开和操作有效状态,从而保护域完整性。
通过这种深思熟虑的重组,我们证明了虽然 lombok 这样的工具可以显着减少样板代码,但它们并不能替代仔细的设计和对该领域的深入理解。它强调应该明智地使用 lombok,补充而不是掩盖强大的架构实践。这确保了我们代码的优雅不会以牺牲其正确性和清晰度为代价。
@data public class movie { private string title; private int releaseyear; } // can be replaced with: public record movie(string title, int releaseyear) {}
为了远离 lombok 的 @nonnull 注释并确保 java 本身的鲁棒性,java.util.objects 类中的 objects.requirenonnull() 方法非常有用。
此方法通过确保对象不为 null 来简化 null 检查,如果是,则抛出 nullpointerexception 并带有明确的消息。这种显式的异常抛出机制可以防止潜在的与 null 相关的错误在运行时出现,从而促进在开发周期中进行早期检测。这是一个示例,展示了此方法如何替换 lombok 的功能
public class nonnullexample { private student student; public nonnullexample(@nonnull student student) { this.student = student; } }等效的纯 java 方法:
import java.util.Objects; public class NonNullExample { private Student student; public NonNullExample(Student student) { this.student = Objects.requireNonNull(student, "Student cannot be null"); } }向本机 java 处理的过渡通过显式进行空检查来增强代码透明度,这有利于代码维护和理解。
构造函数的灵活性和可重用性
评估样板代码:lombok 的诱惑与现代 java 功能的对比
getters、setters、equals、hashcode 和 有效地减少了可见的混乱) tostring 方法,这种便利可能会掩盖潜在的陷阱。然而,随着 java 14 中引入的 java records 的出现,出现了一种更好的替代方案,它本身支持不可变数据载体的简洁声明。最集成
开发环境 (ide) 还能够以最少的用户输入自动生成这些样板代码,从而在 lombok 的自动化和传统 java 编码的控制之间提供平衡。
java标准
javac 进行编译而不进行 lombok 预处理可能会导致错误,指示缺少方法。虽然有些人可能认为 lombok 注入代码的能力是一个聪明的“技巧”,但批判性地评估相关风险和替代方案至关重要。问题的核心在于java的注解处理规范并不正式支持在编译期间修改现有的类。依赖这些非官方技术使得 lombok 容易受到未来 java 更新的影响,这些更新可能会破坏或禁用其功能。
最终,这些考虑因素强调了不仅要评估 lombok 等工具的直接好处的重要性,还要评估它们对可维护性、兼容性以及与 java 标准的一致性的长期影响。随着 java 的不断发展,对稳定、标准化功能的依赖对于确保软件项目的可持续性和可靠性变得越来越重要。结论
“lombok java”。必须认识到,过度依赖 lombok 可能会掩盖 java 本质,可能会导致代码不够健壮,并且在没有 lombok 的情况下更难以管理。
如果过度依赖 lombok 是管理代码库的解决方案,那么可能是时候重新评估底层架构和实践了。 java 的真正优势在于其清晰性和结构,而不是外部库提供的快捷方式。
如果有机会,我会选择从我的项目中放弃 lombok。