本文将引导你完成一系列从传统的命令式代码重构到Java 8函数代码,要从本文中获得最大收益,你应该具备Java 8函数的一些实践经验。
1)优先于匿名Lambda的命名函数
为了热身,让我们从简单的任务开始,将一些用户的详细信息带到UI。我们将从实体列表的开始,将User 转换到 UserDto:
<b>public</b> List<UserDto> getAllUsers() {
List<User> users = userRepo.findAll();
List<UserDto> dtos = <b>new</b> ArrayList<>();
<b>for</b> (User user : users) {
UserDto dto = <b>new</b> UserDto();
dto.setUsername(user.getUsername());
dto.setFullName(user.getFirstName() + <font>" "</font><font> + user.getLastName().toUpperCase());
dto.setActive(user.getDeactivationDate() == <b>null</b>);
dtos.add(dto);
}
<b>return</b> dtos;
}
</font>
但是,我对这段代码并不感到自豪,因为我很可能会为许多用例重复编写类似的代码。那么,让我们使用Java 8:
<b>public</b> List<UserDto> getAllUsers() {
<b>return</b> userRepo.findAll().stream()
.map(user -> {
UserDto dto = <b>new</b> UserDto();
dto.setUsername(user.getUsername());
dto.setFullName(user.getFirstName() + <font>" "</font><font> + user.getLastName().toUpperCase());
dto.setActive(user.getDeactivationDate() == <b>null</b>);
<b>return</b> dto;
})
.collect(toList());
</font>
虽然不错,但是,我仍然不满意。我写的这个lambda演示了一个“匿名函数”。作为一个干净的代码疯子,我有一个问题 - 我想要富有表现力的名字。所以,我很快将lambda内容提取到一个单独的方法中:
<b>public</b> List<UserDto> getAllUsers() {
<b>return</b> userRepo.findAll().stream().map(<b>this</b>::toDto).collect(toList());
}
<b>private</b> UserDto toDto(User user) {
UserDto dto = <b>new</b> UserDto();
dto.setUsername(user.getUsername());
dto.setFullName(user.getFirstName() + <font>" "</font><font> + user.getLastName().toUpperCase());
dto.setActive(user.getDeactivationDate() == <b>null</b>);
<b>return</b> dto;
}
</font>
代码比在之前的版本中更简单,但现在它稍微好一些。
这种User到DTO的逻辑转换可以直接放在DTO构造函数中:
<b>public</b> <b>class</b> UserFacade {
<b>private</b> UserRepo userRepo;
<b>public</b> List<UserDto> getAllUsers() {
<b>return</b> userRepo.findAll().stream().map(UserDto::<b>new</b>).collect(toList());
}
}
<b>public</b> <b>class</b> UserDto {
<b>private</b> String username;
<b>private</b> String fullName;
<b>private</b> <b>boolean</b> active;
<b>public</b> UserDto(User user) {
username = user.getUsername();
fullName = user.getFirstName() + <font>" "</font><font> + user.getLastName().toUpperCase();
active = user.getDeactivationDate() == <b>null</b>;
}
...
}
</font>
现在,让我们假设这个转换需要一些其他组件的帮助,我们希望使用Spring,Guice,CDI等注入。但是,在我们实例化的类中注入依赖项需要非常复杂的代码。如果这个转换过于复杂,我们应该将它移到一个单独的UserMapper类并从那里引用它:
@Service
<b>public</b> <b>class</b> UserFacade {
@Autowired
<b>private</b> UserRepo userRepo;
@Autowired
<b>private</b> UserMapper mapper;
<b>public</b> List<UserDto> getAllUsers() {
<b>return</b> userRepo.findAll().stream().map(mapper::toDto).collect(toList());
}
}
@Component
<b>public</b> <b>class</b> UserMapper {
@Autowired
<b>private</b> OtherClass otherClass;
<b>public</b> UserDto toDto(User user) {
UserDto dto = <b>new</b> UserDto();
dto.setUsername(user.getUsername());
... <font><i>// code using otherClass</i></font><font>
<b>return</b> dto;
}
}
</font>
关键点是:始终将复杂的lambda提取到具有表达名称的函数中,然后可以使用以下四点(::)来引用:
记住,不要使用匿名类型。
在 这个GitHub存储库中 提交了练习的每个阶段,所以请随意浏览存储库以查看所有内容。