Java 使用可选选项防止列车失事中出现空指针

Java 使用可选选项防止列车失事中出现空指针,java,optional,misuse,Java,Optional,Misuse,我只是想知道以下是不是可选的错误用例。可能是的,因为它看起来很恶心 (这是关于调用返回null的“遗留”代码。) 私有静态类人员{ 私人地址; 私有字符串名称; } 私有静态类地址{ 私有整数房屋; 私人信件; 私家弦街;; } 公共字符串getAddress(个人){ 返回可选的.ofNullable(person.getAddress()) .map(x->可选的.ofNullable(x.getHousenr()).map(y->y+).orElse(“”)+ 可选.ofNullable(

我只是想知道以下是不是可选的错误用例。可能是的,因为它看起来很恶心

(这是关于调用返回null的“遗留”代码。)

私有静态类人员{
私人地址;
私有字符串名称;
}
私有静态类地址{
私有整数房屋;
私人信件;
私家弦街;;
}
公共字符串getAddress(个人){
返回可选的.ofNullable(person.getAddress())
.map(x->可选的.ofNullable(x.getHousenr()).map(y->y+).orElse(“”)+
可选.ofNullable(x.getHouseletter()).map(y->y+).orElse(“”)+
可选.ofNullable(x.getStreet()).orElse(“”)
.orElse(“”);
}
//单元测试地址的字符串表示是否正确生成
资产(getAddress(Charlesbabage))
.isEqualTo(“4L Regentstreet”);
我可能应该把代码放在Person类和Address类的方法中,这样就不会太麻烦我了

或者我应该用“老办法”来做:

公共字符串getAddress(个人){
if(person.getAddress()==null){
返回“”;
}
StringBuilder=新的StringBuilder();
if(person.getAddress().getHousenr()!=null){
append(person.getAddress().getHousenr()+);
}
if(person.getAddress().getHouseletter()!=null){
append(person.getAddress().getHouseletter()+);
}
if(person.getAddress().getStreet()!=null){
append(person.getAddress().getStreet()+);
}
返回builder.toString();
}

请记住,这只是一个例子。可以添加更多字段,如词缀、邮政信箱、城镇/城市、市政当局、州、国家(更不用说外国地址),使问题更加严重。

我认为这根本不是一个错误的用例。诚然,如果不考虑格式和空白,阅读起来并不是那么容易,但是您使用
可选
的方式对我来说似乎很好

对于断言而言,拥有(真正丑陋的)代码是很好的。我不知道您最终的预期用例,但假设您只想生成这些对象的字符串表示,我会将检查相应类中空值的逻辑封装在
toString()
方法或类似方法中


编辑:难看的代码不会使其使用错误。尽管在这两个示例中,您的同事可能最终都会讨厌您,但在将元素添加到字符串之前,您正在重复检查元素是否为null的代码。您可以通过使用流和连接来减少重复性工作:

public String getAddress(Person person) {
    return Optional.ofNullable(person.getAddress())
            .map(x -> Stream.of(x.getHousenr(), x.getHouseletter(), x.getStreet())
                        .filter(Objects::nonNull)
                        .map(Object::toString)
                        .collect(Collectors.joining(" "))
            )
            .orElse("<unknown>");
}
公共字符串getAddress(个人){
返回可选的.ofNullable(person.getAddress())
.map(x->Stream.of(x.getHousenr(),x.getHouseletter(),x.getStreet())
.filter(对象::非空)
.map(对象::toString)
.collect(收集器.连接(“”))
)
.orElse(“”);
}
或类似地,无可选:

public String getAddress(Person person) {
    Address address = person.getAddress();
    if (address == null) {
        return "<unknown>";
    }
    return Stream.of(address.getHousenr(), address.getHouseletter(), address.getStreet())
            .filter(Objects::nonNull)
            .map(Object::toString)
            .collect(Collectors.joining(" "))
}
公共字符串getAddress(个人){
地址=person.getAddress();
如果(地址==null){
返回“”;
}
返回流.of(address.getHousenr(),address.getHouseletter(),address.getStreet())
.filter(对象::非空)
.map(对象::toString)
.collect(收集器.连接(“”))
}

这是不可读的,请单独声明字段,对不起,@Andrew Tobliko。阐明了代码的意图。在我看来两者都不好,为什么需要构建字符串?将“4 l Regentstreet”模拟为地址对象并比较2个对象我需要构建一个字符串来向用户显示它。虽然工作代码很重要,但讨厌的代码很可能会不必要地增加维护成本,这一点也很重要。。。。通常,比“工作”代码更重要;特别是如果系统的预期寿命为年。如果你的直觉告诉你代码很难看或不可读,那么一定要重新考虑你的策略。
public String getAddress(Person person) {
    return Optional.ofNullable(person.getAddress())
            .map(x -> Stream.of(x.getHousenr(), x.getHouseletter(), x.getStreet())
                        .filter(Objects::nonNull)
                        .map(Object::toString)
                        .collect(Collectors.joining(" "))
            )
            .orElse("<unknown>");
}
public String getAddress(Person person) {
    Address address = person.getAddress();
    if (address == null) {
        return "<unknown>";
    }
    return Stream.of(address.getHousenr(), address.getHouseletter(), address.getStreet())
            .filter(Objects::nonNull)
            .map(Object::toString)
            .collect(Collectors.joining(" "))
}