【简化开发】lombok的使用、编译后的代码及源码


文章较长,可以按需查阅

导入依赖

首先Maven项目在pom.xml导入依赖

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.24</version>
        </dependency>

一、@getter、@Setter、@toString

1、@getter、@Setter分别生成getxxx()和setxxx()方法

可以将注解加需要生成getter和setter方法的成员变量上。
如果加在了类上,但是要某个成员变量生成特殊getter和setter怎么办?
可以直接手动编写该变量的getter和sette方法,当lombok检测到你已经为该变量编写了相应的getter和setter方法后,就不会再自动生成了。

2、@toString生成toString()方法,按顺序打印类名称以及每个字段,并以逗号分隔

二、@NoArgsConstructor、@RequiredArgsConstructor、@AllArgsConstructor

1、@NoArgsConstructor无参构造函数

@NoArgsConstructor注解共有staticName、onConstructor、access以及force四个属性参数可以进行配置:

staticName

staticName代表的是是否生成静态构造方法,也就是说当staticName属性有值时则会生成一个静态构造方法,这时无参构造方法会被私有,然后创建一个指定名称的静态构造方法,并且是公有的,如下所示:

/**
 * 编译前代码
 */
@RequiredArgsConstructor(staticName = "UserStatic")
public class UserInfo() {
    
    
	
    private String username;
    private String password;
}

/**
 * 编译后代码
 */
public class UserInfo() {
    
    
	
    private String username;
    private String password;
    
    private UserInfo() {
    
    
    }
    
    public UserStatic() {
    
    
    	return new UserStatic();
    }
}

onConstructor

onConstructor
经常写Spring或者SpringBoot代码的人应该知道,Spring对于依赖注入提供了三种写法,分别是属性注入、Setter方法注入以及构造器注入,但是在日常工作中我们更多采用的是依赖于@Autowired注解方式进行依赖注入,不过过多的依赖注入会使我们的代码过于冗长,甚至Spring4.0起就已经开始不推荐这种写法了,而是推荐使用Setter方法注入以及构造器注入,lombok的生成构造器的方法就可以很方便的实现这种写法。
举一个通过构造器注入的例子:

@Controller
public class SysLoginController() {
    
    
	
    private final TokenUtils tokenUtils;
    
    private final SysLoginService sysLoginService;
    
    /**
     * 在这里 @Autowired 是可以省略的,在这里使用只是为了介绍 onConstructor 参数
     */
    @Autowired
    public SysLoginController (TokenUtils tokenUtils, SysLoginService sysLoginService) {
    
    
    	
        this.tokenUtils = tokenUtils;
        this.sysLoginService = sysLoginService;
    }
}

这样注入Bean在数量较多时我们仍需编写大量代码,这个时候就可以使用@RequiredArgsConstructor注解来解决这个问题,至于为什么不使用@AllArgsConstructor注解是因为这个注解是针对所有参数的,而在这个情境下,我们只需构造Bean所对应的属性而不是非Bean,所以我们只需在Bean对应的属性前加上final关键字进行修饰就可以只生成需要的有参构造函数,如下所示:

/**
 * 编译前
 */
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class SysLoginController() {
    
    
	
    private final TokenUtils tokenUtils;
    
    private final SysLoginService sysLoginService;
}

/**
 * 编译后
 */
public class SysLoginController() {
    
    
	
    private final TokenUtils tokenUtils;
    
    private final SysLoginService sysLoginService;
    
    @Autowired
    public SysLoginController (TokenUtils tokenUtils, SysLoginService sysLoginService) {
    
    
    	
        this.tokenUtils = tokenUtils;
        this.sysLoginService = sysLoginService;
    }
}

access

有的时候我们会使用单例模式,这个时候需要我们创造一个私有的无参构造方法,那么就可以使用access这样一个属性来设置构造起的权限,如下所示:

/**
 * 编译前代码
 */
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public class UserInfo() {
    
    
	
    private String username;
    private String password;
}

/**
 * 编译后代码
 */
public class UserInfo() {
    
    
	
    private String username;
    private String password;
    
    private UserInfo() {
    
    
    }
}

access的可选等级:
public enum AccessLevel {
PUBLIC,
MODULE,
PROTECTED,
PACKAGE,
PRIVATE,
NONE;

private AccessLevel() {
}

}

force

当类中有被final关键字修饰的字段未被初始化时,编译器会报错,这时也可以设置force属性为true来为字段根据类型生成一个默认值0/false/null,这样编译器就不会再报错了,如下所示:

/**
 * 编译前代码
 */
@RequiredArgsConstructor(force = true)
public class UserInfo() {
    
    
	
    private final String gender;
    private String username;
    private String password;
}

/**
 * 编译后代码
 */
public class UserInfo() {
    
    
	
    private final String gender = null;
    private String username;
    private String password;
    
    private UserInfo() {
    
    
    }
}

2、@RequiredArgsConstructor

@RequiredArgsConstructor在类上使用,这个注解可以生成带参或者不带参的构造方法。
若带参数,只能是类中所有带有@NonNull注解的和以final修饰的未经初始化的字段,如下所示:

/**
 * 编译前代码
 */
@RequiredArgsConstructor
public class UserInfo() {
    
    
	
    private final String gender;
    @NonNull
    private String username;
    private String password;
}

/**
 * 编译后代码
 */
public class UserInfo() {
    
    
	
    private final String gender;
    @NonNull
    private String username;
    private String password;
    
    public UserInfo(String gender, @NonNull String username) {
    
    
    	
        if (username == null) {
    
    
        	throws new NullPointerException("username is marked @NonNull but is null");
        } else {
    
    
        	this.gender = gender;
            this.username = username;
        }
    }
}

参数配置参照@NoArgsConstructor源码详解

3、@AllArgsConstructor

@AllArgsConstructor在类上使用,这个注解可以生成全参构造函数,且默认不生成无参构造函数。
不过需要注意的是,这里所说的全参并不包括已经被初始化的被final关键字修饰的字段,因为字段一旦被final关键字修饰被赋值后就不能再被修改,如下所示:

/**
 * 编译前代码
 */
@RequiredArgsConstructor
public class UserInfo() {
    
    
	
    private final String gender;
    private final Integer age = 18;
    
    private String username;
    private String password;
}

/**
 * 编译后代码
 */
public class UserInfo() {
    
    
	
    private final String gender;
    private final Integer age = 18;
    
    private String username;
    private String password;
    
    public User(String gender, String username, String password) {
    
    
    	
        this.gender = gender;
        this.username = username;
        this.password = password;
    }
}

参数配置参照@NoArgsConstructor源码详解

三、@Data

@Data注解包含了@Getter@Setter,且有toString(),equals(),canEqual()等方法

四、@Builder、@Singular

@Builder

在lombok日常使用场景中,总会碰到对象中包含集合的情况,这种情况下,我们对于对象中集合的赋值就需要像其他属性一样使用set方法进行赋值操作:

@Data
@Builder
class Student{
    
    
    private String name;
    private List<String> skills;
}

builder源码剖析:

public static class StudentBuilder {
    
    
	// 省略其他部分
    public Student.StudentBuilder skills(List<String> skills) {
    
    
        this.skills = skills;
        return this;
    }
}

这种方式来初始化集合属性不能说是错的,但是用起来还是不够人性化,我们对集合进行构建时主要也是为其添加元素,因此能不能有一个专门为该集合添加元素的方法,同时将集合的实例化隐藏在代码内部的操作呢,答案是肯定的,这就是接下来介绍的@Singular的作用.

@Singular

/**
 * 编译前代码
 */
@Builder
class Student{
    
    
    private String name;
    @Singular
    private List<String> skills;
}

/**
 * 编译后代码
 */
class Student {
    
    
    private String name;
    private List<String> skills;

    Student(String name, List<String> skills) {
    
    
        this.name = name;
        this.skills = skills;
    }

    public static StudentBuilder builder() {
    
    
        return new StudentBuilder();
    }

    public static class StudentBuilder {
    
    
        private String name;
        private ArrayList<String> skills;

        StudentBuilder() {
    
    
        }

        public StudentBuilder name(String name) {
    
    
            this.name = name;
            return this;
        }

        public StudentBuilder skill(String skill) {
    
    
            if (this.skills == null) {
    
    
                this.skills = new ArrayList();
            }

            this.skills.add(skill);
            return this;
        }

        public StudentBuilder skills(Collection<? extends String> skills) {
    
    
            if (skills == null) {
    
    
                throw new NullPointerException("skills cannot be null");
            } else {
    
    
                if (this.skills == null) {
    
    
                    this.skills = new ArrayList();
                }

                this.skills.addAll(skills);
                return this;
            }
        }

        public StudentBuilder clearSkills() {
    
    
            if (this.skills != null) {
    
    
                this.skills.clear();
            }

            return this;
        }

        public Student build() {
    
    
            List skills;
            switch (this.skills == null ? 0 : this.skills.size()) {
    
    
                case 0:
                    skills = Collections.emptyList();
                    break;
                case 1:
                    skills = Collections.singletonList(this.skills.get(0));
                    break;
                default:
                    skills = Collections.unmodifiableList(new ArrayList(this.skills));
            }

            return new Student(this.name, skills);
        }

        public String toString() {
    
    
            return "Student.StudentBuilder(name=" + this.name + ", skills=" + this.skills + ")";
        }
    }
}

对比与上一份代码,加入了@Singular注解后,lombok为我们添加了一个为集合添加元素的方法skill(),当我们不指定方法名时,lombok会根据英文自动推导出方法名,如:skills -> skill,集合名称为:skills,那么它会将复数去掉后,剩下的单词就是方法名称了。我们可以自定义方法名的名称@Singular(“addSkill”)。如果使用了不规范的命名则一定要指定方法名。

如有错误,还请多多指教!
转载或者引用本文内容请注明来源及原作者:橘足轻重;

猜你喜欢

转载自blog.csdn.net/weixin_44510587/article/details/129286919