使用 Optional 来防止 TrainWrecks 中的空指针
Using Optional to prevent NullPointers In TrainWrecks
我只是想知道以下是否是 Optional 的错误用例。可能是吧,因为它看起来很恶心。
(关于调用“遗留”代码,returns 为空。)
private static class Person {
private Address address;
private String name;
}
private static class Address {
private Integer housenr;
private String houseletter;
private String street;
}
public String getAddress(Person person) {
return Optional.ofNullable(person.getAddress())
.map(x -> Optional.ofNullable(x.getHousenr()).map(y -> y + " ").orElse("") +
Optional.ofNullable(x.getHouseletter()).map(y -> y + " ").orElse("") +
Optional.ofNullable(x.getStreet()).orElse(""))
.orElse("<unknown>");
}
// unit test if string representation of an address is properly generated
assertThat(getAddress(charlesBabbage))
.isEqualTo("4 l Regentstreet");
我可能应该将代码放在 Person class 和 Address class 的方法中,这样我就不会太在意了。
或者我应该用“老办法”来做:
public String getAddress(Person person) {
if (person.getAddress() == null) {
return "<unknown>";
}
StringBuilder builder = new StringBuilder();
if (person.getAddress().getHousenr() != null) {
builder.append(person.getAddress().getHousenr() + " ");
}
if (person.getAddress().getHouseletter() != null) {
builder.append(person.getAddress().getHouseletter() + " ");
}
if (person.getAddress().getStreet() != null) {
builder.append(person.getAddress().getStreet() + " ");
}
return builder.toString();
}
请记住,这只是一个例子。可以添加更多字段,如词缀、邮局信箱、town/city、自治市、州、国家(更不用说外国地址)加剧了这个问题。
我完全不认为这是错误的用例。确实,如果不考虑格式和白色 space,阅读起来并不那么容易,但您使用 Optional
的方式对我来说似乎很好。
为了断言,拥有那个(非常丑陋的)代码很好。我不知道您的最终预期用例,但假设您只想生成这些对象的字符串表示形式,我将在 toString()
方法中封装相应 类 中检查空值的逻辑或类似的。
编辑: 难看的代码不会导致其使用错误。虽然你的同事最终可能会讨厌你
在您的两个示例中,您都在重复代码以在将元素添加到字符串之前检查元素是否为空。您可以通过使用 Stream 和加入来减少这种重复性工作:
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(" "))
}
我只是想知道以下是否是 Optional 的错误用例。可能是吧,因为它看起来很恶心。
(关于调用“遗留”代码,returns 为空。)
private static class Person {
private Address address;
private String name;
}
private static class Address {
private Integer housenr;
private String houseletter;
private String street;
}
public String getAddress(Person person) {
return Optional.ofNullable(person.getAddress())
.map(x -> Optional.ofNullable(x.getHousenr()).map(y -> y + " ").orElse("") +
Optional.ofNullable(x.getHouseletter()).map(y -> y + " ").orElse("") +
Optional.ofNullable(x.getStreet()).orElse(""))
.orElse("<unknown>");
}
// unit test if string representation of an address is properly generated
assertThat(getAddress(charlesBabbage))
.isEqualTo("4 l Regentstreet");
我可能应该将代码放在 Person class 和 Address class 的方法中,这样我就不会太在意了。
或者我应该用“老办法”来做:
public String getAddress(Person person) {
if (person.getAddress() == null) {
return "<unknown>";
}
StringBuilder builder = new StringBuilder();
if (person.getAddress().getHousenr() != null) {
builder.append(person.getAddress().getHousenr() + " ");
}
if (person.getAddress().getHouseletter() != null) {
builder.append(person.getAddress().getHouseletter() + " ");
}
if (person.getAddress().getStreet() != null) {
builder.append(person.getAddress().getStreet() + " ");
}
return builder.toString();
}
请记住,这只是一个例子。可以添加更多字段,如词缀、邮局信箱、town/city、自治市、州、国家(更不用说外国地址)加剧了这个问题。
我完全不认为这是错误的用例。确实,如果不考虑格式和白色 space,阅读起来并不那么容易,但您使用 Optional
的方式对我来说似乎很好。
为了断言,拥有那个(非常丑陋的)代码很好。我不知道您的最终预期用例,但假设您只想生成这些对象的字符串表示形式,我将在 toString()
方法中封装相应 类 中检查空值的逻辑或类似的。
编辑: 难看的代码不会导致其使用错误。虽然你的同事最终可能会讨厌你
在您的两个示例中,您都在重复代码以在将元素添加到字符串之前检查元素是否为空。您可以通过使用 Stream 和加入来减少这种重复性工作:
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(" "))
}