一个半严肃的指南,您可能不应该遵循
让我们来看看一个经典的情况: DAO 可能返回 null 并且服务必须处理它。 干净利落。 有多少种方法可以用 Java 解决这个问题? 恐怕太多了。
在以下代码段中,目标是在 Person 为 null 时返回 Person 的名称或 字符串 “<missing>”。
public class NPE {
public static void main(String[] args) {
//let's create a simple scenario
MyService myService = new MyService(new PersonDAO());
myService.process();
}
}
class Person {
//this is our model: a simple class with one getter
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
class PersonDAO {
//this a DAO with one method always returning null
public Person findPerson() {
return null;
}
}
class MyService {
//this is the service that uses the DAO and tries to avoid a NPE
private PersonDAO dao;
public PayrollService(PersonDAO dao) {
this.dao = dao;
}
public String process(){
//person is always null, how to handle it?
Person person = dao.findPerson();
//TODO we need to return the person's name
return ... //person's name or '<missing>'
}
}
让我们探索一些选项。
1)“单线”
public String process() {
return Optional.ofNullable(dao.findPerson()).map(Person::getName).orElse("<missing>");
}
这是简单而优雅的。 缺点是小辈可能看不懂,有时不适合屏幕。
2)不优雅的默认值
public String process() {
return Optional.ofNullable(dao.findPerson())
.orElse(new Person("<missing>"))
.getName();
}
这是一个经典的反模式:它默认为一个名为“<missing>”的人,因此总是有一个名称可以检索。
3) 选择性滥用
public String process() {
try {
return Optional.of(dao.findPerson()).map(Person::getName).get();
} catch (NullPointerException e) {
return "<missing>";
}
}
这个例子创造性地使用 Optional 来做 Optional 在 Java 语言中试图避免的唯一事情:抛出 NPE。
4) 直接来自学校的练习
public String process() {
try {
Person person = dao.findPerson();
return person.getName();
} catch (NullPointerException e) {
return "<missing>";
}
}
这个太傻了,有些人可能第一眼都没注意到。
5) “我听说你可以用 Optional 避免 NPE”
public String process() {
try {
Optional<Person> person = Optional.of(dao.findPerson());
return person.get().getName();
} catch (NullPointerException e) {
return "<missing>";
}
}
这是对上一个的改进。 是不是更傻了?
6)设计的一个投掷NPE
public String process() {
try {
return Objects.requireNonNull(dao.findPerson()).getName();
} catch (NullPointerException e) {
return "<missing>";
}
}
如果我是故意这样做的,那并不傻,是吗?
7) 喜欢 lambdas 的人
public String process() {
return Optional.ofNullable(dao.findPerson()).map(person -> {
return person.getName();
}).orElse("<missing>");
}
不错。 要是有办法让它更短就好了!
8) 刚刚听说 Optional 的人
public String process() {
Optional<Person> person = Optional.ofNullable(dao.findPerson());
if (person.isPresent()) {
return person.get().getName();
} else {
return "<missing>";
}
}
我该如何描述这个? 冗长,也许? 当然,如果您按代码行数获得报酬……
9)老经典
public String process9() {
Person person = dao.findPerson();
return Objects.nonNull(person) ? person.getName() : "<missing>";
}
有多少人还在这样做?
10) Java 1.4 兼容
public String process() {
Person person = dao.findPerson();
if (person != null) {
return person.getName();
} else {
return "<missing>";
}
}
我们去过那里。
结论
处理 null 的十种方法,但只是其中的几种并不完全可笑。 选择最差的,让你的评论者发疯。
我留给你一个奖金。 特殊类别“当您可以编写迷你框架时,为什么要使用语言的简单功能?”。 谁不喜欢使用复杂的代码或外部依赖项来完成基本任务?
惊恐的事件
public String process() {
return AvoidNPE.calling(Person::getName)
.on(dao.findPerson())
.andWhenNullReturn("<missing>")
.please();
}
static class AvoidNPE {
private Object target;
private Object defaultValue;
private Function <Object, Object> function;
public static <T> AvoidNPE calling(Function<T, Object> function) {
AvoidNPE avoidNPE = new AvoidNPE();
avoidNPE.function = (Function<Object, Object>) function;
return avoidNPE;
}
public AvoidNPE on(Object target) {
this.target = target;
return this;
}
public AvoidNPE andWhenNullReturn(Object defaultValue) {
this.defaultValue = defaultValue;
return this;
}
public <O> O please() {
return (O) (Objects.nonNull(target) ? function.apply(target) : defaultValue);
}
}
我希望我能说这样的一件艺术品只能是一个不合时宜的愚人节玩笑,但是那里有图书馆在做类似的事情。 我们使用它们! 谁从来没有为 StringUtils::isEmpty 导入 Apache Common?
当你写你的杰作时,请记住流畅性是设计的主要方面。 您需要将微框架的全部废话隐藏在一小段代码的优雅后面! 使用类和方法的名称来传达信息。