使用Java8(可选)重构遗留代码<;T>;
假设我有一个简单的模型UserInfo和Passport:使用Java8(可选)重构遗留代码<;T>;,java,lambda,refactoring,java-8,optional,Java,Lambda,Refactoring,Java 8,Optional,假设我有一个简单的模型UserInfo和Passport: public class UserInfo { private int age; private String passportId; // getters, setters } public class Passport { // empty } 如果用户年龄大于20岁,我希望看到他的护照,在Java7中,我会: UserInfo userInfo = new UserInfo();
public class UserInfo {
private int age;
private String passportId;
// getters, setters
}
public class Passport {
// empty
}
如果用户年龄大于20岁,我希望看到他的护照,在Java7中,我会:
UserInfo userInfo = new UserInfo();
userInfo.setAge(22);
userInfo.setPassportId(null);
final Passport passport;
if (userInfo.getAge() > 20) {
if (userInfo.getPassportId() == null) {
throw new IllegalArgumentException("Set passport");
}
else {
passport = findPassportById(userInfo.getPassportId());
}
}
这非常简单,但我想使用Java8可选的 String passportId = Optional.of(userInfo)
.filter(x -> x.getAge() > 20)
.map(UserInfo::getPassportId)
.orElseThrow(() -> new IllegalArgumentException("Set passport"));
final Passport passport;
// null checks again? I don't want to!
if (passportId != null) {
passport = findPassportById(passportId);
}
那么,有没有任何实践可以以更干净的方式重构这种常见情况
谢谢 如果
getPassportId
返回null,orelsetrow
将触发异常。在您的代码中,passportId
将永远不会为null
。您可以将其组合在一起,如下所示:
Passport passport = Optional.of(userInfo)
.filter(x -> x.getAge() > 20)
.map(UserInfo::getPassportId)
.map(this::findPassportById) // or wherever findPassportById is defined
.orElsethrow(...);
如果
getPassportId
返回空值,orelsetrow
将触发异常。在您的代码中,passportId
将永远不会为null
。您可以将其组合在一起,如下所示:
Passport passport = Optional.of(userInfo)
.filter(x -> x.getAge() > 20)
.map(UserInfo::getPassportId)
.map(this::findPassportById) // or wherever findPassportById is defined
.orElsethrow(...);
你的主要误解是,你在课堂之外检查年龄
UserInfo
。事实上,您的用户信息类只是一个记录或结构
这显然违反了OOP范式(即,这是过程风格)。什么,如果你也需要在其他地方检查这个年龄?是否确实要将此代码段复制到所有这些位置?如果年龄限制更改为另一个值(例如德国的18岁),会发生什么情况
结论:年龄检查行为只能在一个地方进行。这被称为单一责任原则(SRP)。在这里,此功能显然属于类UserInfo
因此,您可以将其更改为:
public class UserInfo {
private int age;
private String passportId;
...
public Optional<String> getPassportId() {
checkPassport();
return Optional.ofNullable(passportId);
}
private void checkPassport() {
if (age > 20 && (passportId == null || passportId.isEmpty())) {
throw ...
}
}
}
公共类用户信息{
私人互联网;
私有字符串密码;
...
公共可选getPassportId(){
支票护照();
返回可选。不可用(passportId);
}
私人作废支票护照(){
如果(年龄>20&(passportId==null | | passportId.isEmpty()){
投
}
}
}
现在调用getter将导致异常或可能封装passport id的可选异常。抛出异常是否是正确的处理方式是另一个问题
请注意,我没有详细阐述这个问题。例如,年龄检查本身应该再次外包到一个项目中
另外,我强烈建议你去上这门课。这样做时,应该考虑在构建对象时检查参数。但这取决于您的应用程序要求。您的主要误解是,您检查了班级以外的年龄
UserInfo
。事实上,您的用户信息类只是一个记录或结构
这显然违反了OOP范式(即,这是过程风格)。什么,如果你也需要在其他地方检查这个年龄?是否确实要将此代码段复制到所有这些位置?如果年龄限制更改为另一个值(例如德国的18岁),会发生什么情况
结论:年龄检查行为只能在一个地方进行。这被称为单一责任原则(SRP)。在这里,此功能显然属于类UserInfo
因此,您可以将其更改为:
public class UserInfo {
private int age;
private String passportId;
...
public Optional<String> getPassportId() {
checkPassport();
return Optional.ofNullable(passportId);
}
private void checkPassport() {
if (age > 20 && (passportId == null || passportId.isEmpty())) {
throw ...
}
}
}
公共类用户信息{
私人互联网;
私有字符串密码;
...
公共可选getPassportId(){
支票护照();
返回可选。不可用(passportId);
}
私人作废支票护照(){
如果(年龄>20&(passportId==null | | passportId.isEmpty()){
投
}
}
}
现在调用getter将导致异常或可能封装passport id的可选异常。抛出异常是否是正确的处理方式是另一个问题
请注意,我没有详细阐述这个问题。例如,年龄检查本身应该再次外包到一个项目中
另外,我强烈建议你去上这门课。这样做时,应该考虑在构建对象时检查参数。但这取决于您的应用程序需求。我假设
UserInfo
不会为null
,因此将其包装成可选的是没有意义的。当年龄低于20岁时,你也不想继续
另外需要记住的是,可选
的要点是避免异常。如果passportId
是一项基本属性,那么无论如何它都应该是强制性的(如果年龄>20岁)。否则,您将首先处理损坏的数据。另一方面,如果它不是强制性的,那么抛出异常就没有多大意义
如果您不想强制执行,我建议对passportId
设置一个可选的,可以直接通过UserInfo
本身。如果您仍然需要传统的getter,那么您可以使用属性名称添加一个新方法(这似乎是常见的做法,即使在JDK中也是如此)
我假设UserInfo
不会是null
,因此将其包装成可选的是没有意义的。当年龄低于20岁时,你也不想继续
另外需要记住的是,可选
的要点是避免异常。如果passportId
是一项基本属性,那么无论如何它都应该是强制性的(如果年龄>20岁)。否则,您将首先处理损坏的数据。另一方面,如果它不是强制性的,那么抛出异常就没有多大意义
如果您不想强制执行,我建议对passportId
设置一个Optional