Java8getter应该返回可选类型吗?

Java8getter应该返回可选类型吗?,java,java-8,nullable,optional,Java,Java 8,Nullable,Optional,Optional在Java8中引入的类型对于许多开发人员来说是一件新事物 返回可选类型的getter方法代替经典的Foo是一种好的做法吗?假设该值可以是null,一般来说,我认为使用可选类型作为可为null的返回值是一个好主意。然而,对于框架,我认为用可选类型替换经典的getter会在使用依赖getter和setter编码约定的框架(如Hibernate)时带来很多麻烦。在我自己做了一些研究之后,我遇到了一些可能会在适当的时候提出建议的事情。最权威的是以下引用自Oracle文章: “需要注意的是

Optional
在Java8中引入的类型对于许多开发人员来说是一件新事物


返回
可选
类型的getter方法代替经典的
Foo
是一种好的做法吗?假设该值可以是
null

,一般来说,我认为使用可选类型作为可为null的返回值是一个好主意。然而,对于框架,我认为用可选类型替换经典的getter会在使用依赖getter和setter编码约定的框架(如Hibernate)时带来很多麻烦。

在我自己做了一些研究之后,我遇到了一些可能会在适当的时候提出建议的事情。最权威的是以下引用自Oracle文章:

“需要注意的是,可选类的意图是不替换每个空引用。相反,它的目的是帮助设计更易于理解的API,这样,只要读取方法的签名,就可以知道是否可以期望一个可选值。这将强制您主动展开可选项以处理缺少值的情况。“-

我还找到了这篇文章的摘录

“可选”不适用于这些情况,因为它不会给我们带来任何好处:

  • 在域模型层中(不可序列化)
  • 在DTO中(相同原因)
  • 在方法的输入参数中
  • “在构造函数参数中”
这似乎也提出了一些正确的观点


我找不到任何负面的含义或危险信号来建议应避免使用
可选的
。我认为一般的想法是,如果它有帮助或改进了API的可用性,就使用它。

当然,人们会做他们想做的事。但我们在添加此功能时有明确的意图,而且它不是基因我们的目的是为库方法返回类型提供一个有限的机制,其中需要有一个明确的方式来表示“无结果”,并且使用
null
这样做极有可能导致错误

例如,您可能永远不应该将其用于返回结果数组或结果列表的内容,而应该返回空数组或列表。您几乎不应该将其用作内容字段或方法参数

我认为常规使用它作为getter的返回值肯定会被过度使用

可选性没有什么错,它应该被避免,它只是不是许多人希望它是什么,因此,我们相当担心过度使用的风险

(公共服务公告:永远不要调用
可选。get
除非你能证明它永远不会为空;而是使用一种安全的方法,如
orElse
ifPresent
。回想起来,我们应该调用
get
类似于
GetOrelsThrownOschelementException
之类的方法,或者一些让它成功的方法更清楚的是,这是一个非常危险的方法,它首先破坏了
可选的整个目的。吸取的教训。(更新:Java 10具有
可选的.orelsetrow()
,在语义上等同于
get()
,但其名称更合适。)

如果您使用的是现代序列化程序和其他理解
可选
的框架,那么我发现在编写
实体
bean和域层时,这些指导原则非常有效:

  • 如果序列化层(通常是DB)允许表
    FOO
    中列
    BAR
    中的单元格使用
    null
    值,则getter
    FOO.getBar()
    可以返回
    Optional
    ,指示开发人员该值可能合理地被预期为null,他们应该处理该值。如果DB保证该值不会为null,则getter应该将其包装在
    Optional
  • Foo.bar
    应该是
    private
    不是
    Optional
    。如果它是
    private
    ,那么它确实没有理由是
    Optional
  • setter
    Foo.setBar(字符串条)
    应采用
    bar
    not
    可选的类型
    。如果可以使用
    null
    参数,则在JavaDoc注释中说明这一点。如果不可以使用
    null
    则使用
    IllegalArgumentException
    或某些适当的业务逻辑更合适
  • 构造函数不需要
    可选的
    参数(原因类似于第3点)。通常我只在构造函数中包含在序列化数据库中必须为非空的参数

  • 为了提高上述效率,您可能需要编辑用于生成getter的IDE模板以及用于
    toString()
    equals(Obj o)
    等的相应模板,或者直接为这些模板使用字段(大多数IDE生成器已经处理空值)。

    可选
    添加到Java的原因是:

    return Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods())
        .stream()
        .filter(m -> Objects.equals(m.getName(), enclosingInfo.getName())
        .filter(m ->  Arrays.equals(m.getParameterTypes(), parameterClasses))
        .filter(m -> Objects.equals(m.getReturnType(), returnType))
        .findFirst()
        .getOrThrow(() -> new InternalError(...));
    
    比这更干净:

    Method matching =
        Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods())
        .stream()
        .filter(m -> Objects.equals(m.getName(), enclosingInfo.getName())
        .filter(m ->  Arrays.equals(m.getParameterTypes(), parameterClasses))
        .filter(m -> Objects.equals(m.getReturnType(), returnType))
        .getFirst();
    if (matching == null)
      throw new InternalError("Enclosing method not found");
    return matching;
    
    我的观点是,Optional是为了支持函数式编程而编写的,函数式编程是同时添加到Java中的。(该示例由a提供的。更好的示例可能使用
    orElse()
    方法,因为此代码无论如何都会引发异常,但您可以理解。)

    但是现在,人们使用Optional是出于一个完全不同的原因。他们用它来解决语言设计中的一个缺陷。这个缺陷是:无法指定API的哪些参数和返回值允许为null。这可能在Javadoc中提到,但大多数开发人员甚至不为他们的代码编写Javadoc,而不是many会在javadocs编写时检查它们