2

引言

我们在项目中经常遇到一些很冗余的操作,导致一个小功能写成大工程,那么这时候我们就要考虑是否该升级下我们的技术了呢?拥抱 lombok,它会帮助我们解决一些让我们很烦躁的问题。以下是应用结合网络资料陆续整理而成的文档。

lombok解析流程

lombok解析流程.png

源码由javac解析到AST后,交给lombok annotation模块完成注解部分的解析工作,并输出修改后的AST

去掉 Setter 和 Getter

    @Setter @Getter public class UserDTO {
        @NotNull
        private String username;
        @NotNull
        private int age;
    
        public User convertToUser(){
            UserDTOConvert userDTOConvert = new UserDTOConvert();
            User convert = userDTOConvert.convert(this);
            return convert;
        }
    
        public UserDTO convertFor(User user){
            UserDTOConvert userDTOConvert = new UserDTOConvert();
            UserDTO convert = userDTOConvert.reverse().convert(user);
            return convert;
        }
    
        private static class UserDTOConvert extends Converter<UserDTO, User> {
            @Override
            protected User doForward(UserDTO userDTO) {
                User user = new User();
                BeanUtils.copyProperties(userDTO,user);
                return user;
            }
    
            @Override
            protected UserDTO doBackward(User user) {
                throw new AssertionError("不支持逆向转化方法!");
            }
        }
    }

看到了吧,烦人的 GetterSetter 方法已经去掉了。

bean 中的链式风格

改造前

public class Student {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public Student setAge(int age) {
        return this;
    }
}

相信合理使用这样的链式代码,会更多的程序带来很好的可读性,那看一下如果使用 lombok 进行改善呢,请使用 @Accessors(chain = true),看如下代码:

@Accessors(chain = true)
@Setter
@Getter
public class Student {
    private String name;
    private int age;
}

这样就完成了一个对于 bean 来讲很友好的链式操作。

静态构造方法

静态构造方法的语义和简化程度真的高于直接去 new 一个对象。比如 new 一个 List 对象,过去的使用是这样的:

List<String> list = new ArrayList<>();

看一下 guava 中的创建方式:

List<String> list = Lists.newArrayList();

Lists 命名是一种约定(俗话说:约定优于配置),它是指 ListsList 这个类的一个工具类,那么使用 List 的工具类去产生 List,这样的语义要比直接 new 一个子类来的更直接。再比如有一个工具类叫做 Maps,那你是否想到了创建 Map 的方法呢:

HashMap<String, String> objectObjectHashMap = Maps.newHashMap();

接上上边的静态构造方法和必传参数的构造方法,使用 lombok 将更改成如下写法(@RequiredArgsConstructor@NonNull):

@Accessors(chain = true)
@Setter
@Getter
@RequiredArgsConstructor(staticName = "ofName")
public class Student {
    @NonNull private String name;
    private int age;
}

测试代码:

Student student = Student.ofName("zs");

这样构建出的 bean 语义是否要比直接 new 一个含参的构造方法(包含 name 的构造方法)要好很多。

当然,看过很多源码以后,我相信将静态构造方法 ofName 换成 of 会先的更加简洁:

@Accessors(chain = true)
@Setter
@Getter
@RequiredArgsConstructor(staticName = "of")
public class Student {
        @NonNull private String name;
        private int age;
}

测试代码:

Student student = Student.of("zs");

当然他仍然是支持链式调用的:

Student student = Student.of("zs").setAge(24);

这样来写代码,真的很简洁,并且可读性很强。

使用 builder

@Builder
public class Student {
    private String name;
    private int age;
}

调用方式:

Student student = Student.builder().name("zs").age(24).build();

代理模式

正如我们所知的,在程序中调用 rest 接口是一个常见的行为动作,如果你和我一样使用过 springRestTemplate,我相信你会我和一样,对他抛出的非 http 状态码异常深恶痛绝。

所以我们考虑将 RestTemplate 最为底层包装器进行包装器模式的设计:

public abstract class FilterRestTemplate implements RestOperations {
        protected volatile RestTemplate restTemplate;

        protected FilterRestTemplate(RestTemplate restTemplate){
                this.restTemplate = restTemplate;
        }

        //实现RestOperations所有的接口
}

然后再由扩展类对 FilterRestTemplate 进行包装扩展:

public class ExtractRestTemplate extends FilterRestTemplate {
    private RestTemplate restTemplate;
    public ExtractRestTemplate(RestTemplate restTemplate) {
            super(restTemplate);
            this.restTemplate = restTemplate;
    }

    public <T> RestResponseDTO<T> postForEntityWithNoException(String url, Object request, Class<T> responseType, Object... uriVariables)
                    throws RestClientException {
            RestResponseDTO<T> restResponseDTO = new RestResponseDTO<T>();
            ResponseEntity<T> tResponseEntity;
            try {
                    tResponseEntity = restTemplate.postForEntity(url, request, responseType, uriVariables);
                    restResponseDTO.setData(tResponseEntity.getBody());
                    restResponseDTO.setMessage(tResponseEntity.getStatusCode().name());
                    restResponseDTO.setStatusCode(tResponseEntity.getStatusCodeValue());
            }catch (Exception e){
                    restResponseDTO.setStatusCode(RestResponseDTO.UNKNOWN_ERROR);
                    restResponseDTO.setMessage(e.getMessage());
                    restResponseDTO.setData(null);
            }
            return restResponseDTO;
    }
}

包装器 ExtractRestTemplate 很完美的更改了异常抛出的行为,让程序更具有容错性。在这里我们不考虑 ExtractRestTemplate 完成的功能,让我们把焦点放在 FilterRestTemplate 上,实现 RestOperations 所有的接口,这个操作绝对不是一时半会可以写完的:

public abstract class FilterRestTemplate implements RestOperations {

    protected volatile RestTemplate restTemplate;

    protected FilterRestTemplate(RestTemplate restTemplate) {
            this.restTemplate = restTemplate;
    }

    @Override
    public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables) throws RestClientException {
            return restTemplate.getForObject(url,responseType,uriVariables);
    }

    @Override
    public <T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException {
            return restTemplate.getForObject(url,responseType,uriVariables);
    }

    @Override
    public <T> T getForObject(URI url, Class<T> responseType) throws RestClientException {
            return restTemplate.getForObject(url,responseType);
    }

    @Override
    public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables) throws RestClientException {
            return restTemplate.getForEntity(url,responseType,uriVariables);
    }
    //其他实现代码略。。。
}

我相信你看了以上代码,你会和我一样觉得恶心反胃,后来我用 lombok 提供的代理注解优化了我的代码(@Delegate):

@AllArgsConstructor
public abstract class FilterRestTemplate implements RestOperations {
    @Delegate
    protected volatile RestTemplate restTemplate;
}

这几行代码完全替代上述那些冗长的代码。
@Delegate解释委托模式,当时间E发生在类A身上时,A可以通过@Delegate将该事件委托给B处理,并且当B处理完成后,将结果返回给A。对于外部调用者C来说,他并不关心到底是A还是B完成了这次计算,他只关心最终的返回结果是否正确,这样一来就大大解放了A。

其他lombok注解

lambok还有很多注解,不一一解释,大家可以多尝试:

@Data(包括@Getter、@Setter、@ToString、@EqualsAndHashCode)

@NoArgsConstructor

@AllArgsConstructor

@EqualsAndHashCode

@Slf4j          logback日志框架时使用

@Log4j        Log4j日志框架时使用

@ToString(exclude="")

@ToString(exclude={"",""})

@ToString(of="")

@ToString(of={"",""})

enjoy......


CharlesCheung
84 声望3 粉丝