咱们在项目中常常遇到一些很冗余的操做,致使一个小功能写成大工程,那么这时候咱们就要考虑是否该升级下咱们的技术了呢?拥抱 lombok
,它会帮助咱们解决一些让咱们很烦躁的问题。如下是应用结合网络资料陆续整理而成的文档。java
源码由javac
解析到AST
后,交给lombok annotation
模块完成注解部分的解析工做,并输出修改后的AST
。spring
@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("不支持逆向转化方法!"); } } }
看到了吧,烦人的 Getter
和 Setter
方法已经去掉了。网络
改造前框架
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)
,看以下代码:ide
@Accessors(chain = true) @Setter @Getter public class Student { private String name; private int age; }
这样就完成了一个对于 bean
来说很友好的链式操做。工具
静态构造方法的语义和简化程度真的高于直接去 new
一个对象。好比 new
一个 List
对象,过去的使用是这样的:post
List<String> list = new ArrayList<>();
看一下 guava
中的建立方式:测试
List<String> list = Lists.newArrayList();
Lists
命名是一种约定(俗话说:约定优于配置),它是指 Lists
是 List
这个类的一个工具类,那么使用 List
的工具类去产生 List
,这样的语义要比直接 new
一个子类来的更直接。再好比有一个工具类叫作 Maps
,那你是否想到了建立 Map
的方法呢:优化
HashMap<String, String> objectObjectHashMap = Maps.newHashMap();
接上上边的静态构造方法和必传参数的构造方法,使用 lombok 将更改为以下写法(@RequiredArgsConstructor
和 @NonNull
):ui
@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 public class Student { private String name; private int age; }
调用方式:
Student student = Student.builder().name("zs").age(24).build();
正如咱们所知的,在程序中调用 rest 接口是一个常见的行为动做,若是你和我同样使用过 spring
的 RestTemplate
,我相信你会我和同样,对他抛出的非 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。
lambok
还有不少注解,不一一解释,你们能够多尝试:
@Data(包括@Getter、@Setter、@ToString、@EqualsAndHashCode)@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
@Slf4j logback日志框架时使用
@Log4j Log4j日志框架时使用
@ToString(exclude="")
@ToString(exclude={"",""})
@ToString(of="")
@ToString(of={"",""})
enjoy......