您的位置 首页 java

Java中处理null的10+1种方法

一个半严肃的指南,您可能不应该遵循

让我们来看看一个经典的情况: 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?

当你写你的杰作时,请记住流畅性是设计的主要方面。 您需要将微框架的全部废话隐藏在一小段代码的优雅后面! 使用类和方法的名称来传达信息。

文章来源:智云一二三科技

文章标题:Java中处理null的10+1种方法

文章地址:https://www.zhihuclub.com/189077.shtml

关于作者: 智云科技

热门文章

网站地图