Java 8 开始新增的 Optional 类 - Optional 可能存在的滥用

Optional 对象存在的滥用

现在我们来看看 Optional 存在的滥用和在这种滥用情况下有多危险。

主要的情况就是将 Optional 作为方法的参数这种滥用。

设想下,我们有一个 Person 的 List,我们希望对这个 List 中的对象进查找,并且从查找中找到给出 List 对中 Person 对象的名字,同时我们还希望我们找到的这个 Person 对象还需要满足一定的年龄。

如果我们使用 Optional 作为参数的方法的话,我们会得到下面的方法:

public static List<Person> search(List<Person> people, String name, Optional<Integer> age) {
    // Null checks for people and name
    return people.stream()
            .filter(p -> p.getName().equals(name))
            .filter(p -> p.getAge().get() >= age.orElse(0))
            .collect(Collectors.toList());
}

随后,在后续其他的程序中,我们可以尝试使用这个方法

someObject.search(people, "Peter", null);

现在,如果我们执行上面的代码的时候,我们将会得到一个 NullPointerException 异常,然后我们就需要对输入的参数进行 Null 检查,这个和我们为了使用 Optional 的目标是不一致的。

下面为一些可以使用的方法能够让我们的代码更好的运行:

public static List<Person> search(List<Person> people, String name, Integer age) {
    // Null checks for people and name
    final Integer ageFilter = age != null ? age : 0;

    return people.stream()
            .filter(p -> p.getName().equals(name))
            .filter(p -> p.getAge().get() >= ageFilter)
            .collect(Collectors.toList());
}

上面的代码中,输入的参数还是 Optional,但是我们只用一次检查来进行处理。

另外一种可能的方法就是使用方法重载(overloaded )使用同样的方法名,但是输入的参数是不同的。

public static List<Person> search(List<Person> people, String name) {
    return doSearch(people, name, 0);
}

public static List<Person> search(List<Person> people, String name, int age) {
    return doSearch(people, name, age);
}

private static List<Person> doSearch(List<Person> people, String name, int age) {
    // Null checks for people and name
    return people.stream()
            .filter(p -> p.getName().equals(name))
            .filter(p -> p.getAge().get().intValue() >= age)
            .collect(Collectors.toList());
}

通过上面的配置,我们的 API 的使用就更加明确了,使用 2 个不同的 API 来做不同的事情,但是这 2 个方法都共享了相同的实现。

So, there are solutions to avoid using Optionals as method parameters. The intent of Java when releasing Optional was to use it as a return type, thus indicating that a method could return an empty value. As a matter of fact, the practice of using Optional as a method parameter is even discouraged by some code inspectors.